diff --git a/.custom-gcl.yaml b/.custom-gcl.yaml
index c7ce532b334..832efd43d1d 100644
--- a/.custom-gcl.yaml
+++ b/.custom-gcl.yaml
@@ -1,6 +1,6 @@
-version: v2.11.4
+version: v2.12.1
name: golangci-kube-api-linter
destination: ./tmp/bin/
plugins:
- module: 'sigs.k8s.io/kube-api-linter'
- version: v0.0.0-20260408163332-73b2175ca510
+ version: v0.0.0-20260423112246-3fa174937a6b
diff --git a/.github/env b/.github/env
index 0590ee68a4f..f73d142513b 100644
--- a/.github/env
+++ b/.github/env
@@ -1,3 +1,3 @@
-golang-version=1.25
-kind-version=v0.31.0
-kind-image=kindest/node:v1.35.1
+golang-version=1.26
+kind-version=v0.32.0
+kind-image=kindest/node:v1.36.1
diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml
index f2df1027539..2ad989c3887 100644
--- a/.github/workflows/actionlint.yml
+++ b/.github/workflows/actionlint.yml
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v6.0.2
+ uses: actions/checkout@v6.0.3
- name: Download actionlint
id: get_actionlint
run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/v1.7.4/scripts/download-actionlint.bash)
diff --git a/.github/workflows/changed-files.yaml b/.github/workflows/changed-files.yaml
index 75cec2a672a..84ea6f678fb 100644
--- a/.github/workflows/changed-files.yaml
+++ b/.github/workflows/changed-files.yaml
@@ -16,7 +16,7 @@ jobs:
steps:
- name: checkout repo
id: checkout
- uses: actions/checkout@v6.0.2
+ uses: actions/checkout@v6.0.3
with:
fetch-depth: 0
- name: get changed files
diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml
index d13d9ff87f6..6ecff8a3894 100644
--- a/.github/workflows/checks.yaml
+++ b/.github/workflows/checks.yaml
@@ -22,7 +22,7 @@ jobs:
- ubuntu-latest
name: Generate and format
steps:
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Import environment variables from file
run: cat ".github/env" >> "$GITHUB_ENV"
- uses: actions/setup-go@v6.4.0
@@ -37,7 +37,7 @@ jobs:
runs-on: ubuntu-latest
name: Check Documentation formatting and links
steps:
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Import environment variables from file
run: cat ".github/env" >> "$GITHUB_ENV"
- uses: actions/setup-go@v6.4.0
@@ -52,7 +52,7 @@ jobs:
runs-on: ubuntu-latest
name: Golang linter
steps:
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Import environment variables from file
run: cat ".github/env" >> "$GITHUB_ENV"
- uses: actions/setup-go@v6.4.0
@@ -70,7 +70,7 @@ jobs:
runs-on: ubuntu-latest
name: Check prometheus metrics
steps:
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Import environment variables from file
run: cat ".github/env" >> "$GITHUB_ENV"
- uses: actions/setup-go@v6.4.0
@@ -88,7 +88,7 @@ jobs:
- ubuntu-latest
name: Build operator binary
steps:
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Import environment variables from file
run: cat ".github/env" >> "$GITHUB_ENV"
- uses: actions/setup-go@v6.4.0
@@ -101,7 +101,7 @@ jobs:
runs-on: ubuntu-latest
name: Build Prometheus Operator rule config map to rule file CRDs CLI tool
steps:
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Import environment variables from file
run: cat ".github/env" >> "$GITHUB_ENV"
- uses: actions/setup-go@v6.4.0
diff --git a/.github/workflows/cspell.json b/.github/workflows/cspell.json
index 3609a1563e3..262180e357c 100644
--- a/.github/workflows/cspell.json
+++ b/.github/workflows/cspell.json
@@ -424,6 +424,11 @@
"FIPSSTS",
"checkmark",
"STARTTLS",
- "MLKEM"
+ "MLKEM",
+ "slashexx",
+ "Errorf",
+ "prompkg",
+ "nutmos",
+ "nattapong"
]
}
diff --git a/.github/workflows/e2e-feature-gated.yaml b/.github/workflows/e2e-feature-gated.yaml
index 6a690230753..fa8db884ed9 100644
--- a/.github/workflows/e2e-feature-gated.yaml
+++ b/.github/workflows/e2e-feature-gated.yaml
@@ -22,7 +22,7 @@ jobs:
if: ${{ needs.changed-files.outputs.non-markdown-files }}
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Setup E2E environment
uses: ./.github/actions/setup-e2e # composite action with your setup steps
diff --git a/.github/workflows/e2e-prometheus-v2.yaml b/.github/workflows/e2e-prometheus-v2.yaml
index 20014b5b9da..8d0262d8e43 100644
--- a/.github/workflows/e2e-prometheus-v2.yaml
+++ b/.github/workflows/e2e-prometheus-v2.yaml
@@ -27,7 +27,7 @@ jobs:
- suite: operatorUpgrade
target: test-e2e-operator-upgrade
steps:
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Setup E2E environment
uses: ./.github/actions/setup-e2e # composite action with your setup steps
diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index e0161c88e73..1bd79f85844 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -37,7 +37,7 @@ jobs:
- suite: operatorUpgrade
target: test-e2e-operator-upgrade
steps:
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Setup E2E environment
uses: ./.github/actions/setup-e2e # composite action with your setup steps
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
index e8e2fe80d17..2ab527403d2 100644
--- a/.github/workflows/publish.yaml
+++ b/.github/workflows/publish.yaml
@@ -22,7 +22,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v6.0.2
+ uses: actions/checkout@v6.0.3
- name: Import environment variables from file
run: cat ".github/env" >> "$GITHUB_ENV"
- name: Reclaim disk space
@@ -36,21 +36,21 @@ jobs:
go-version: '${{ env.golang-version }}'
check-latest: true
- name: Install cosign
- uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1
+ uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
- name: Check the Docker version
run: docker version
- name: Check the cosign version
run: cosign version
- name: Install crane
- uses: imjasonh/setup-crane@6da1ae018866400525525ce74ff892880c099987 # v0.5
+ uses: imjasonh/setup-crane@59c71e96a00b28651f10369ba3359a6d730740a0 # v0.6
- name: Login to quay.io
- uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
+ uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: quay.io
username: ${{ secrets.quay_username }}
password: ${{ secrets.quay_password }}
- name: Login to ghcr.io
- uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
+ uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 4280d8a6e14..2680ccb0249 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -10,7 +10,7 @@ jobs:
name: Upload release assets
steps:
- name: Checkout
- uses: actions/checkout@v6.0.2
+ uses: actions/checkout@v6.0.3
- name: Import environment variables from file
run: cat ".github/env" >> "$GITHUB_ENV"
- name: Install Go
diff --git a/.github/workflows/spell-check.yaml b/.github/workflows/spell-check.yaml
index 146426dabc1..daf6b0ee104 100644
--- a/.github/workflows/spell-check.yaml
+++ b/.github/workflows/spell-check.yaml
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Run cSpell
uses: streetsidesoftware/cspell-action@de2a73e963e7443969755b648a1008f77033c5b2 # v8.4.0
with:
diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml
index 19c5d475ccf..4003971a0d4 100644
--- a/.github/workflows/stale.yaml
+++ b/.github/workflows/stale.yaml
@@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
if: github.repository == 'prometheus-operator/prometheus-operator'
steps:
- - uses: actions/stale@v10.2.0
+ - uses: actions/stale@v10.3.0
with:
stale-issue-message: 'This issue has been automatically marked as stale because it has not had any activity in the last 60 days. Thank you for your contributions.'
close-issue-message: 'This issue was closed because it has not had any activity in the last 120 days. Please reopen if you feel this is still valid.'
diff --git a/.github/workflows/test-prom-version-upgrade.yaml b/.github/workflows/test-prom-version-upgrade.yaml
index 8262fe884c6..ce78d3d127c 100644
--- a/.github/workflows/test-prom-version-upgrade.yaml
+++ b/.github/workflows/test-prom-version-upgrade.yaml
@@ -15,7 +15,7 @@ jobs:
docker image prune --force --all
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Import environment variables from file
run: |
cat ".github/env" >> "$GITHUB_ENV"
diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml
index a039f5341ff..0a87913abe6 100644
--- a/.github/workflows/unit.yaml
+++ b/.github/workflows/unit.yaml
@@ -21,7 +21,7 @@ jobs:
needs: changed-files
if: ${{ needs.changed-files.outputs.non-markdown-files }}
steps:
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Import environment variables from file
run: cat ".github/env" >> "$GITHUB_ENV"
- uses: actions/setup-go@v6.4.0
@@ -35,7 +35,7 @@ jobs:
needs: changed-files
if: ${{ needs.changed-files.outputs.non-markdown-files }}
steps:
- - uses: actions/checkout@v6.0.2
+ - uses: actions/checkout@v6.0.3
- name: Import environment variables from file
run: cat ".github/env" >> "$GITHUB_ENV"
- uses: actions/setup-go@v6.4.0
diff --git a/.golangci-kal.yml b/.golangci-kal.yml
index 99fbfb5adf1..5643ace6ffa 100644
--- a/.golangci-kal.yml
+++ b/.golangci-kal.yml
@@ -6,7 +6,7 @@
# https://github.com/kubernetes-sigs/kube-api-linter/blob/main/docs/linters.md
version: "2"
run:
- go: "1.25"
+ go: "1.26"
allow-parallel-runners: true
linters:
default: none
@@ -23,20 +23,23 @@ linters:
# Whenever a new linter is added, it should not break the backward
# compatibility of existing APIs (at least for v1 APIs).
enable:
- - "nobools"
- "commentstart"
- "conflictingmarkers"
- "duplicatemarkers"
+ - "forbiddenmarkers"
+ - "nobools"
+ - "nodurations"
- "nofloats"
+ - "nomaps"
+ - "nophase"
+ - "nonullable"
+ - "noreferences"
+ - "notimestamp"
- "optionalorrequired"
- - "statussubresource"
- - "uniquemarkers"
- "jsontags"
- "statusoptional"
- - "nophase"
- - "nonullable"
- - "forbiddenmarkers"
- - "nomaps"
+ - "statussubresource"
+ - "uniquemarkers"
disable:
- "*"
lintersConfig:
@@ -65,4 +68,4 @@ linters:
# KAL only validates the API folders.
- path-except: pkg/apis/monitoring/
linters:
- - kubeapilinter
\ No newline at end of file
+ - kubeapilinter
diff --git a/.golangci.yml b/.golangci.yml
index 49df8753a0f..a7db7c4f936 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,6 +1,6 @@
version: "2"
run:
- go: "1.25"
+ go: "1.26"
timeout: 10m
modules-download-mode: readonly
allow-parallel-runners: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index eabe63ded94..ec35f7005aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,28 @@
+## 0.92.1 / 2026-06-30
+
+* [BUGFIX] Fix "namespace not found" errors when the operator watches monitoring and workload resources in different resources. #8658
+
+## 0.92.0 / 2026-06-18
+
+> **Note:** The `PrometheusTopologySharding` and `PrometheusShardRetentionPolicy` feature gates have been promoted to **Beta** in this release and are now enabled by default. See the [sharding documentation](https://prometheus-operator.dev/docs/platform/sharding/) for details.
+
+* [CHANGE] Add URL validation for the `tokenUrl` field in OAuth2 configuration across all CRDs. #8579
+* [CHANGE] Add URL validation for the `url` field in `RemoteReadSpec` in `Prometheus` CRD. #8596
+* [FEATURE] Migrate retention options from CLI flags to the config file for `Prometheus` CRD (Prometheus >= v3 uses the config file; older versions continue to use CLI flags). #8547
+* [FEATURE] Add `staleSeriesCompactionThreshold` field to `TSDBSpec` in `Prometheus` and `PrometheusAgent` CRDs. #8563
+* [FEATURE] Add `labelNameUnderscoreSanitization` and `labelNamePreserveMultipleUnderscores` fields to `OTLPConfig` in `Prometheus` and `PrometheusAgent` CRDs. #8562
+* [FEATURE] Add `payload` field to Webhook receiver in `AlertmanagerConfig` CRD. #8507
+* [ENHANCEMENT] Use pod topology labels for zone sharding on Kubernetes >= 1.35 when the `PrometheusTopologySharding` feature gate is enabled (removes the need for `attachMetadata.node=true`). #8564
+* [ENHANCEMENT] Add validation for the Slack `update_message` field in Alertmanager configuration Secret. #8556
+* [BUGFIX] Validate target labels in `Probe` static configuration to prevent invalid Prometheus scrape configs. #7901
+* [BUGFIX] Fix goroutine leak and data race in `pollBasedListerWatcher`. #8593
+* [BUGFIX] Validate `ProxyConfig` in OAuth2 configuration. #8610
+* [BUGFIX] Fix SMTP smarthost format error handling in Alertmanager configuration. #8586
+* [BUGFIX] Fix missing `return` in admission webhook after marshal failure. #8582
+* [BUGFIX] Fix `FindOwner` to return `nil` on `meta.Accessor` error. #8585
+* [BUGFIX] Fix dropped gzip `Close` errors in `GzipConfig` and `GunzipConfig`. #8573
+* [BUGFIX] Fix panic on malformed key=value flag input (e.g. `--labels "key"`). #8560
+
## 0.91.0 / 2026-05-05
* [CHANGE] Enforce mutual exclusion of `basicAuth`, `authorization` and `oauth2` in `ScrapeConfig` CRD. #8480
diff --git a/Dockerfile b/Dockerfile
index ee43ddfa42d..f2540f91a32 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
ARG ARCH=amd64
ARG OS=linux
-ARG GOLANG_BUILDER=1.25
+ARG GOLANG_BUILDER=1.26
FROM quay.io/prometheus/golang-builder:${GOLANG_BUILDER}-base AS builder
WORKDIR /workspace
diff --git a/Documentation/api-reference/api.md b/Documentation/api-reference/api.md
index 315e8cc7826..7f179a1b60a 100644
--- a/Documentation/api-reference/api.md
+++ b/Documentation/api-reference/api.md
@@ -445,6 +445,18 @@ map[string]string
Note that the ScrapeConfig custom resource definition is currently at Alpha level.
+Note that the ScrapeConfig custom resource definition is currently at Alpha level
+and will be graduated to Beta in a future release.
@@ -12801,7 +13132,9 @@ client’s secret.
Note that the ScrapeConfig custom resource definition is currently at Alpha level.
+Note that the ScrapeConfig custom resource definition is currently at Alpha level
+and will be graduated to Beta in a future release.
URL represents a valid URL
@@ -22798,7 +23373,8 @@ gzipped Prometheus configuration under the
prometheus.yaml.gz key.
This behavior is
deprecated and will be removed in the next major version
of the custom resource definition. It is recommended to use
spec.additionalScrapeConfigs instead.
-
Note that the ScrapeConfig custom resource definition is currently at Alpha level.
+
Note that the ScrapeConfig custom resource definition is currently at Alpha level
+and will be graduated to Beta in a future release.
@@ -22815,7 +23391,8 @@ Kubernetes meta/v1.LabelSelector
scrapeConfigNamespaceSelector defines the namespaces to match for ScrapeConfig discovery. An empty label selector
matches all namespaces. A null label selector matches the current
namespace only.
-Note that the ScrapeConfig custom resource definition is currently at Alpha level.
+Note that the ScrapeConfig custom resource definition is currently at Alpha level
+and will be graduated to Beta in a future release.
@@ -22944,6 +23521,22 @@ the label value isn’t empty, all Prometheus shards will scrape the target.
+shardingStrategy
+
+
+ShardingStrategy
+
+
+
+
+(Optional)
+shardingStrategy defines the sharding strategy for distributing scraped targets across Prometheus shards.
+When not defined, the operator defaults to the ‘Address’ mode which distributes
+targets based on a hash of the target address.
+
+
+
+
replicaExternalLabelName
string
@@ -23261,6 +23854,18 @@ map[string]string
+schedulerName
+
+string
+
+
+
+(Optional)
+schedulerName defines the scheduler to use for Pod scheduling. If not specified, the default scheduler is used.
+
+
+
+
serviceAccountName
string
@@ -25408,6 +26013,8 @@ Only valid for Pod, Endpoint and Endpointslice roles.
"SDK"
+"WorkloadIdentity"
+
AzureSDConfig
@@ -25682,7 +26289,7 @@ SafeTLSConfig
(Optional)
-tlsConfig defies the TLS configuration applying to the target HTTP endpoint.
+tlsConfig defines the TLS configuration applying to the target HTTP endpoint.
@@ -25854,12 +26461,26 @@ string
(Optional)
filter defines the filter expression used to filter the catalog results.
-See https://www.consul.io/api-docs/catalog#list-services
+See https://developer.hashicorp.com/consul/api-docs/catalog#filtering
It requires Prometheus >= 3.0.0.
+healthFilter
+
+string
+
+
+
+(Optional)
+healthFilter defines the filter expression used to filter the health results.
+See https://developer.hashicorp.com/consul/api-docs/health#filtering
+It requires Prometheus >= 3.11.2.
+
+
+
+
allowStale
bool
@@ -27354,6 +27975,22 @@ This includes settings for certificates, CA validation, and TLS protocol options
+forceImplicitTLS
+
+bool
+
+
+
+(Optional)
+forceImplicitTLS defines whether to force use of implicit TLS (direct TLS connection) for better security.
+true: force use of implicit TLS (direct TLS connection on any port)
+false: force disable implicit TLS (use explicit TLS/STARTTLS if required)
+nil (default): auto-detect based on port (465=implicit, other=explicit) for backward compatibility
+It requires Alertmanager >= v0.31.0.
+
+
+
+
threading
@@ -27363,7 +28000,8 @@ EmailThreadingConfig
(Optional)
-threading defines the threading configuration for email receiver.
+threading defines the threading configuration for email receiver.
+It requires Alertmanager >= v0.30.0.
@@ -27385,34 +28023,16 @@ EmailThreadingConfig
-enabled
-forceImplicitTLS
-
-bool
-
-
-
-(Optional)
-enabled defines whether to enable threading, which makes alert notifications in the same
-alert group show up in the same email thread.
-
-
-
-
threadByDate
-string
+
+ThreadByDateType
+
-(Optional)
-threadByDate defines what granularity of current date to thread by. Accepted values: daily, none.
-(none means group by alert group key, no date).
-forceImplicitTLS defines whether to force use of implicit TLS (direct TLS connection) for better security.
-true: force use of implicit TLS (direct TLS connection on any port)
-false: force disable implicit TLS (use explicit TLS/STARTTLS if required)
-nil (default): auto-detect based on port (465=implicit, other=explicit) for backward compatibility
-It requires Alertmanager >= v0.31.0.
+threadByDate defines what granularity of current date to thread by. Accepted values: Daily, None.
+(None means group by alert group key, no date).
@@ -29208,8 +29828,7 @@ bool
@@ -31596,7 +32215,8 @@ gzipped Prometheus configuration under the prometheus.yaml.gz key.
This behavior is deprecated and will be removed in the next major version
of the custom resource definition. It is recommended to use
spec.additionalScrapeConfigs instead.
-Note that the ScrapeConfig custom resource definition is currently at Alpha level.
+Note that the ScrapeConfig custom resource definition is currently at Alpha level
+and will be graduated to Beta in a future release.
@@ -31613,7 +32233,8 @@ Kubernetes meta/v1.LabelSelector
scrapeConfigNamespaceSelector defines the namespaces to match for ScrapeConfig discovery. An empty label selector
matches all namespaces. A null label selector matches the current
namespace only.
-Note that the ScrapeConfig custom resource definition is currently at Alpha level.
+Note that the ScrapeConfig custom resource definition is currently at Alpha level
+and will be graduated to Beta in a future release.
@@ -31742,6 +32363,22 @@ the label value isn’t empty, all Prometheus shards will scrape the target.
+shardingStrategy
+
+
+ShardingStrategy
+
+
+
+
+(Optional)
+shardingStrategy defines the sharding strategy for distributing scraped targets across Prometheus shards.
+When not defined, the operator defaults to the ‘Address’ mode which distributes
+targets based on a hash of the target address.
+
+
+
+
replicaExternalLabelName
string
@@ -32059,6 +32696,18 @@ map[string]string
+schedulerName
+
+string
+
+
+
+(Optional)
+schedulerName defines the scheduler to use for Pod scheduling. If not specified, the default scheduler is used.
+
+
+
+
serviceAccountName
string
@@ -34578,8 +35227,9 @@ HTTPConfig
@@ -36462,6 +37112,26 @@ HTTPConfig
+ThreadByDateType
+(string alias)
+
+(Appears on: EmailThreadingConfig )
+
+
+
+
+
+
+Value
+Description
+
+
+"Daily"
+
+"None"
+
+
+
Time
(string alias)
@@ -37767,6 +38437,22 @@ This includes settings for certificates, CA validation, and TLS protocol options
+forceImplicitTLS
+
+bool
+
+
+
+(Optional)
+forceImplicitTLS defines whether to force use of implicit TLS (direct TLS connection) for better security.
+true: force use of implicit TLS (direct TLS connection on any port)
+false: force disable implicit TLS (use explicit TLS/STARTTLS if required)
+nil (default): auto-detect based on port (465=implicit, other=explicit) for backward compatibility
+It requires Alertmanager >= v0.31.0.
+
+
+
+
threading
@@ -37776,7 +38462,8 @@ EmailThreadingConfig
(Optional)
-threading defines the threading configuration for email receiver.
+threading defines the threading configuration for email receiver.
+It requires Alertmanager >= v0.30.0.
@@ -37798,34 +38485,16 @@ EmailThreadingConfig
-enabled
-forceImplicitTLS
-
-bool
-
-
-
-(Optional)
-enabled defines whether to enable threading, which makes alert notifications in the same
-alert group show up in the same email thread.
-
-
-
-
threadByDate
-string
+
+ThreadByDateType
+
-(Optional)
-threadByDate defines what granularity of current date to thread by. Accepted values: daily, none.
-(none means group by alert group key, no date).
-forceImplicitTLS defines whether to force use of implicit TLS (direct TLS connection) for better security.
-true: force use of implicit TLS (direct TLS connection on any port)
-false: force disable implicit TLS (use explicit TLS/STARTTLS if required)
-nil (default): auto-detect based on port (465=implicit, other=explicit) for backward compatibility
-It requires Alertmanager >= v0.31.0.
+threadByDate defines what granularity of current date to thread by. Accepted values: Daily, None.
+(None means group by alert group key, no date).
@@ -41078,6 +41747,26 @@ HTTPConfig
+
ThreadByDateType
+(string alias)
+
+(Appears on: EmailThreadingConfig )
+
+
+
+
+
+
+Value
+Description
+
+
+"Daily"
+
+"None"
+
+
+
Time
(string alias)
diff --git a/Documentation/getting-started/compatibility.md b/Documentation/getting-started/compatibility.md
index 733b327c329..5de038fc07b 100644
--- a/Documentation/getting-started/compatibility.md
+++ b/Documentation/getting-started/compatibility.md
@@ -24,7 +24,7 @@ The Prometheus Operator uses the official [Go client](https://github.com/kuberne
The current version of the Prometheus operator uses the following Go client version:
```$ mdox-exec="go list -m -f '{{ .Version }}' k8s.io/client-go"
-v0.35.2
+v0.36.1
```
## Prometheus
@@ -78,12 +78,15 @@ Prometheus Operator supports all Prometheus versions >= v2.0.0. The operator's e
* v3.10.0
* v3.11.0
* v3.11.1
+* v3.11.2
+* v3.11.3
+* v3.12.0
```
The end-to-end tests are mostly tested against
```$ mdox-exec="go run ./cmd/po-docgen/. compatibility defaultPrometheusVersion"
-* v3.11.1
+* v3.12.0
```
## Alertmanager
@@ -93,7 +96,7 @@ The Prometheus Operator is compatible with Alertmanager v0.15 and above.
The end-to-end tests are mostly tested against
```$ mdox-exec="go run ./cmd/po-docgen/. compatibility defaultAlertmanagerVersion"
-* v0.32.0
+* v0.33.0
```
## Thanos
diff --git a/Documentation/platform/operator.md b/Documentation/platform/operator.md
index 0a233ec4635..8df0e48e344 100644
--- a/Documentation/platform/operator.md
+++ b/Documentation/platform/operator.md
@@ -1,5 +1,5 @@
---
-weight: 211
+weight: 212
toc: false
title: CLI reference
menu:
@@ -70,8 +70,8 @@ Arguments:
Feature gates are a set of key=value pairs that describe Prometheus-Operator features.
Available feature gates:
PrometheusAgentDaemonSet: Enables the DaemonSet mode for PrometheusAgent (enabled: false)
- PrometheusShardRetentionPolicy: Enables shard retention policy for Prometheus (enabled: false)
- PrometheusTopologySharding: Enables the zone aware sharding for Prometheus (enabled: false)
+ PrometheusShardRetentionPolicy: Enables shard retention policy for Prometheus (enabled: true)
+ PrometheusTopologySharding: Enables the zone aware sharding for Prometheus (enabled: true)
RemoteWriteCustomResourceDefinition: Enables the RemoteWrite CRD support (enabled: false)
StatusForConfigurationResources: Updates the status subresource for configuration resources (enabled: false)
-key-file string
@@ -101,13 +101,15 @@ Arguments:
-namespaces value
Namespaces to scope the interaction of the Prometheus Operator and the apiserver (allow list). This is mutually exclusive with --deny-namespaces.
-prometheus-config-reloader string
- Prometheus config reloader image (default "quay.io/prometheus-operator/prometheus-config-reloader:v0.89.0")
+ Prometheus config reloader image (default "quay.io/prometheus-operator/prometheus-config-reloader:v0.91.0")
-prometheus-default-base-image string
Prometheus default base image (path without tag/version) (default "quay.io/prometheus/prometheus")
-prometheus-instance-namespaces value
Namespaces where Prometheus and PrometheusAgent custom resources and corresponding Secrets, Configmaps and StatefulSets are watched/created. If set this takes precedence over --namespaces or --deny-namespaces for Prometheus custom resources.
-prometheus-instance-selector value
Label selector to filter Prometheus and PrometheusAgent Custom Resources to watch.
+ -repair-policy-for-statefulsets value
+ Policy to use when a StatefulSet rollout is stuck. Possible values: 'none' (default), 'evict' or 'delete'. (default none)
-secret-field-selector value
Field selector to filter Secrets to watch
-secret-label-selector value
diff --git a/Documentation/platform/prometheus-agent.md b/Documentation/platform/prometheus-agent.md
index f17705ca56a..1c6f711b3ae 100644
--- a/Documentation/platform/prometheus-agent.md
+++ b/Documentation/platform/prometheus-agent.md
@@ -26,7 +26,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
rules:
- apiGroups:
diff --git a/Documentation/platform/rbac.md b/Documentation/platform/rbac.md
index d9e72c1194a..d0e15109cd9 100644
--- a/Documentation/platform/rbac.md
+++ b/Documentation/platform/rbac.md
@@ -26,7 +26,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
rules:
- apiGroups:
@@ -212,7 +212,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
namespace: default
```
@@ -228,7 +228,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
diff --git a/Documentation/platform/sharding.md b/Documentation/platform/sharding.md
new file mode 100644
index 00000000000..191cfa6319d
--- /dev/null
+++ b/Documentation/platform/sharding.md
@@ -0,0 +1,286 @@
+---
+weight: 209
+toc: true
+title: Sharding
+menu:
+ docs:
+ parent: operator
+lead: ""
+images: []
+draft: false
+description: Sharding Prometheus
+---
+
+When there are too much data to ingest and process, scaling Prometheus vertically may come to an end and it might become necessary to distribute scraped targets across multiple Prometheus shards.
+
+## Design
+
+The Prometheus operator will create `.spec.shards` StatefulSets multiplied by `.spec.replicas` pods.
+
+By default, shards use the Prometheus `modulus` configuration which takes the hash of the source label values in order to split scraped
+targets based on the number of shards. By default, Prometheus hashes the value of the
+* `__address__` label for `ServiceMonitor` and `PodMonitor` resources
+* `__param_target__` label for `Probe` resources
+
+To query globally, deploy the Thanos querier connecting to all Thanos sidecars (in the same way, use the Thanos ruler to evaluate rules across shards). Another option is to remote write the samples to a central location.
+
+**Limitations:**
+
+* Scaling down the number of shards doesn't reshard existing data onto remaining instances. It must be manually moved (see also Scaling below).
+* Scaling up the number of shards will not reshard existing data either. It will continue to be available from the same instances.
+
+## Configuration
+
+### Implementing a custom target distribution
+
+To implement a custom distribution, set the `__tmp_hash` label during target discovery using relabeling configuration. The operator uses this label's value instead of the default labels when computing the shard assignment.
+
+For example, to shard targets by pod namespace and name rather than by address:
+
+```yaml
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: example-app
+ labels:
+ team: frontend
+spec:
+ selector:
+ matchLabels:
+ app: example-app
+ endpoints:
+ - port: web
+ relabelings:
+ - sourceLabels: [__meta_kubernetes_pod_namespace, __meta_kubernetes_pod_name]
+ separator: /
+ targetLabel: __tmp_hash
+```
+
+The relabeling can also be applied at the scrape class level to affect multiple monitoring resources at once.
+
+### Scraping a target from all the shards
+
+By default, each target is assigned to exactly one shard. To have all shards scrape the same target — useful for singleton services such as kube-state-metrics where every shard needs the full set of metrics — set the `__tmp_disable_sharding` label to a non-empty value using relabeling configuration.
+
+```yaml
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: kube-state-metrics
+spec:
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: kube-state-metrics
+ endpoints:
+ - port: http
+ relabelings:
+ - targetLabel: __tmp_disable_sharding
+ replacement: "true"
+```
+
+### Topology-aware sharding
+
+> **Beta:** Topology-aware sharding requires the `PrometheusTopologySharding` feature gate to be enabled on the operator.
+
+In multi-zone clusters, the default address-based sharding distributes targets without regard for their zone, which can generate costly cross-zone traffic. Topology-aware sharding pins each Prometheus shard to a specific zone so that it only scrapes targets local to that zone.
+
+When `mode: Topology` is set, the operator:
+* Generates relabeling rules so each shard keeps only targets whose zone label matches its assigned zone.
+* Automatically adds a `nodeSelector` to schedule each shard's pods in the correct zone.
+* Adds a `zone` external label to each shard's Prometheus configuration (configurable via `externalLabelName`).
+
+The number of shards must be greater than or equal to the number of topology values. When `spec.shards` is a multiple of the number of zones, the shards are evenly distributed across zones. Otherwise, some zones receive more shards than others.
+
+```yaml
+apiVersion: monitoring.coreos.com/v1
+kind: Prometheus
+metadata:
+ name: prometheus
+spec:
+ shards: 4
+ replicas: 2
+ shardingStrategy:
+ mode: Topology
+ topology:
+ values:
+ - europe-west4-a
+ - europe-west4-b
+```
+
+With this configuration and 4 shards across 2 zones, shards 0 and 2 are scheduled in `europe-west4-a` and shards 1 and 3 in `europe-west4-b`. Each shard only scrapes targets in its zone.
+
+### Retaining shards
+
+> **Beta:** Shard retention requires the `PrometheusShardRetentionPolicy` feature gate to be enabled on the operator.
+
+When scaling down the number of shards, the pods from the removed shards are deleted by default along with access to their historical data. To preserve scaled-down shards so their data remains queryable until the retention duration expires, set `.spec.shardRetentionPolicy.whenScaled` to `Retain`:
+
+```yaml
+apiVersion: monitoring.coreos.com/v1
+kind: Prometheus
+metadata:
+ name: prometheus
+spec:
+ shards: 2
+ shardRetentionPolicy:
+ whenScaled: Retain
+```
+
+Retained shards continue running and can be queried via the Thanos sidecar and querier alongside the active shards. By default, the operator deletes them once the Prometheus retention time has been reached. This can be overridden with the `retain.retentionPeriod` field:
+
+```yaml
+apiVersion: monitoring.coreos.com/v1
+kind: Prometheus
+metadata:
+ name: prometheus
+spec:
+ shards: 2
+ retentionSize: 100Gi
+ shardRetentionPolicy:
+ whenScaled: Retain
+ retain:
+ retentionPeriod: 7d
+```
+
+> **Note:** If the Prometheus resource uses size-based retention only (no retention time configured), retained shards are kept forever by default.
+
+## Example
+
+The following manifest creates a Prometheus server with two replicas:
+
+```yaml
+apiVersion: monitoring.coreos.com/v1
+kind: Prometheus
+metadata:
+ labels:
+ prometheus: prometheus
+ name: prometheus
+ namespace: default
+spec:
+ serviceAccountName: prometheus
+ replicas: 2
+ serviceMonitorSelector:
+ matchLabels:
+ team: frontend
+```
+
+This can be verified with the following command:
+
+```bash
+kubectl get pods -n default
+```
+
+The output is similar to this:
+
+```bash
+prometheus-prometheus-0 2/2 Running 1 10s
+prometheus-prometheus-1 2/2 Running 1 10s
+```
+
+Deploy the example application and monitor it:
+
+```yaml mdox-exec="cat example/shards/example-app-deployment.yaml"
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: example-app
+ namespace: default
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: example-app
+ template:
+ metadata:
+ labels:
+ app: example-app
+ spec:
+ containers:
+ - name: example-app
+ image: quay.io/brancz/prometheus-example-app:v0.5.0
+ ports:
+ - name: web
+ containerPort: 8080
+```
+
+```yaml mdox-exec="cat example/shards/example-app-service.yaml"
+kind: Service
+apiVersion: v1
+metadata:
+ name: example-app
+ namespace: default
+ labels:
+ app: example-app
+spec:
+ selector:
+ app: example-app
+ ports:
+ - name: web
+ port: 8080
+```
+
+```yaml mdox-exec="cat example/shards/example-app-service-monitor.yaml"
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: example-app
+ namespace: default
+ labels:
+ team: frontend
+spec:
+ selector:
+ matchLabels:
+ app: example-app
+ endpoints:
+ - port: web
+```
+
+Explore one of the monitoring Prometheus instances:
+
+```bash
+kubectl port-forward pod/prometheus-prometheus-0 9090:9090
+```
+
+We find the prometheus server scrapes three targets.
+
+Now let's expand the Prometheus resource to two shards as shown below:
+
+```yaml mdox-exec="cat example/shards/prometheus.yaml"
+apiVersion: monitoring.coreos.com/v1
+kind: Prometheus
+metadata:
+ labels:
+ prometheus: shards
+ name: prometheus
+ namespace: default
+spec:
+ serviceAccountName: prometheus
+ replicas: 2
+ shards: 2
+ serviceMonitorSelector:
+ matchLabels:
+ team: frontend
+```
+
+This can be verified with the following command:
+
+```bash
+kubectl get pods -n
+```
+
+The output is similar to this:
+
+```bash
+prometheus-prometheus-0 2/2 Running 1 11m
+prometheus-prometheus-1 2/2 Running 1 11m
+prometheus-prometheus-shard-1-0 2/2 Running 1 12s
+prometheus-prometheus-shard-1-1 2/2 Running 1 12s
+```
+
+Explore one of the monitoring Prometheus instances added for sharding:
+
+```bash
+kubectl port-forward prometheus-prometheus-shard-1-0 9091:9090
+```
+
+We should find that one or two targets are being scraped by this instance while the original Prometheus shard scrapes the remaining target(s).
diff --git a/Documentation/platform/storage.md b/Documentation/platform/storage.md
index 2389b6b992a..c3a817935d3 100644
--- a/Documentation/platform/storage.md
+++ b/Documentation/platform/storage.md
@@ -1,5 +1,5 @@
---
-weight: 209
+weight: 210
toc: true
title: Storage
menu:
diff --git a/Documentation/platform/strategic-merge-patch.md b/Documentation/platform/strategic-merge-patch.md
index cac0f6b23b5..492a2a0836e 100644
--- a/Documentation/platform/strategic-merge-patch.md
+++ b/Documentation/platform/strategic-merge-patch.md
@@ -1,5 +1,5 @@
---
-weight: 210
+weight: 211
toc: true
title: Strategic Merge Patch
menu:
diff --git a/Documentation/platform/troubleshooting.md b/Documentation/platform/troubleshooting.md
index e19550b7d92..296e3521676 100644
--- a/Documentation/platform/troubleshooting.md
+++ b/Documentation/platform/troubleshooting.md
@@ -1,5 +1,5 @@
---
-weight: 212
+weight: 213
toc: true
title: Troubleshooting
menu:
@@ -286,12 +286,12 @@ If the `--controller-id` flag is not set, the operator will try to reconcile all
The following table illustrates the behavior based on whether the `--controller-id` flag is set and whether the `operator.prometheus.io/controller-id` annotation is present on the resources:
-| Operator started with with the `--controller-id` flag | Resource with the `operator.prometheus.io/controller-id` annotation | Behavior |
-|-------------------------------------------------------|---------------------------------------------------------------------|-------------------------------------------------------------------------------------|
-| Yes | Yes | The operator reconciles the resource only if the annotation value matches the flag. |
-| Yes | No | The operator does not reconcile the resource |
-| No | Yes | The operator does not reconcile the resource. |
-| No | No | The operator reconciles the resource. |
+| Operator started with the `--controller-id` flag | Resource with the `operator.prometheus.io/controller-id` annotation | Behavior |
+|--------------------------------------------------|---------------------------------------------------------------------|-------------------------------------------------------------------------------------|
+| Yes | Yes | The operator reconciles the resource only if the annotation value matches the flag. |
+| Yes | No | The operator does not reconcile the resource |
+| No | Yes | The operator does not reconcile the resource. |
+| No | No | The operator reconciles the resource. |
### Configuring Prometheus/PrometheusAgent for Mimir and Grafana Cloud
diff --git a/Documentation/platform/webhook.md b/Documentation/platform/webhook.md
index 330f05113a4..c32af3b3e2b 100644
--- a/Documentation/platform/webhook.md
+++ b/Documentation/platform/webhook.md
@@ -86,7 +86,7 @@ kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/name: prometheus-operator-admission-webhook
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator-admission-webhook
namespace: default
```
@@ -97,7 +97,7 @@ kind: Deployment
metadata:
labels:
app.kubernetes.io/name: prometheus-operator-admission-webhook
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator-admission-webhook
namespace: default
spec:
@@ -114,7 +114,7 @@ spec:
kubectl.kubernetes.io/default-container: prometheus-operator-admission-webhook
labels:
app.kubernetes.io/name: prometheus-operator-admission-webhook
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
spec:
affinity:
podAntiAffinity:
@@ -131,7 +131,7 @@ spec:
- --web.enable-tls=true
- --web.cert-file=/etc/tls/private/tls.crt
- --web.key-file=/etc/tls/private/tls.key
- image: quay.io/prometheus-operator/admission-webhook:v0.91.0
+ image: quay.io/prometheus-operator/admission-webhook:v0.92.1
name: prometheus-operator-admission-webhook
ports:
- containerPort: 8443
@@ -179,7 +179,7 @@ kind: Service
metadata:
labels:
app.kubernetes.io/name: prometheus-operator-admission-webhook
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator-admission-webhook
namespace: default
spec:
diff --git a/Documentation/proposals/accepted/202405-agent-daemonset.md b/Documentation/proposals/accepted/202405-agent-daemonset.md
index 61ba7d319b3..6c552f9a16f 100644
--- a/Documentation/proposals/accepted/202405-agent-daemonset.md
+++ b/Documentation/proposals/accepted/202405-agent-daemonset.md
@@ -12,6 +12,7 @@ draft: false
* Owners:
* [haanhvu](https://github.com/haanhvu)
+ * [slashexx](https://github.com/slashexx)
* Status:
* `Accepted`
* Related Tickets:
@@ -84,6 +85,97 @@ The current [PrometheusAgent CRD](https://prometheus-operator.dev/docs/platform/
We will add a new `mode` field that accepts either `StatefulSet` or `DaemonSet`, with `StatefulSet` being the default. If the DaemonSet mode is activated (`mode: DaemonSet`), all the unrelated fields listed above will not be accepted. In the MVP, we will simply fail the reconciliation if any of those fields are set. We will prevent users to directly switch from a live StatefulSet setup to DaemonSet, because that might break their workload if they forget to unset the unsupported fields. Following up, we will leverage validation rules with [Kubernetes' Common Expression Language (CEL)](https://kubernetes.io/docs/reference/using-api/cel/). Only then, we will allow switching from a live StatefulSet setup to DaemonSet. We already have an issue for CEL [here](https://github.com/prometheus-operator/prometheus-operator/issues/5079).
+#### 6.1.1 CEL Validation rules
+
+When `mode:DaemonSet`, the following CEL rules will be applied to prevent access to these fields:
+
+- `replicas`
+- `storage`
+- `shards`
+- `persistentVolumeClaimRetentionPolicy`
+- `scrapeConfigSelector`
+- `scrapeConfigNamespaceSelector`
+- `probeSelector`
+- `probeNamespaceSelector`
+- `serviceMonitorSelector`
+- `serviceMonitorNamespaceSelector`
+- `additionalScrapeConfigs`
+
+This is implemented by adding `x-kubernetes-validations` like:
+
+```yaml
+x-kubernetes-validations:
+ - rule: "self.mode == 'DaemonSet' ? !has(self.replicas) : true"
+ message: "replicas field is not allowed when mode is 'DaemonSet'"
+ - rule: "self.mode == 'DaemonSet' ? !has(self.storage) : true"
+ message: "storage field is not allowed when mode is 'DaemonSet'"
+ - rule: "self.mode == 'DaemonSet' ? !has(self.shards) : true"
+ message: "shards field is not allowed when mode is 'DaemonSet'"
+ - rule: "self.mode == 'DaemonSet' ? !has(self.persistentVolumeClaimRetentionPolicy) : true"
+ message: "persistentVolumeClaimRetentionPolicy field is not allowed when mode is 'DaemonSet'"
+ - rule: "!(has(self.mode) && self.mode == 'DaemonSet' && has(self.scrapeConfigSelector))"
+ message: "scrapeConfigSelector cannot be set when mode is DaemonSet"
+ - rule: "!(has(self.mode) && self.mode == 'DaemonSet' && has(self.probeSelector))"
+ message: "probeSelector cannot be set when mode is DaemonSet"
+ - rule: "!(has(self.mode) && self.mode == 'DaemonSet' && has(self.probeNamespaceSelector))"
+ message: "probeNamespaceSelector cannot be set when mode is DaemonSet"
+ - rule: "!(has(self.mode) && self.mode == 'DaemonSet' && has(self.scrapeConfigNamespaceSelector))"
+ message: "scrapeConfigNamespaceSelector cannot be set when mode is DaemonSet"
+ - rule: "!(has(self.mode) && self.mode == 'DaemonSet' && has(self.serviceMonitorSelector))"
+ message: "serviceMonitorSelector cannot be set when mode is DaemonSet"
+ - rule: "!(has(self.mode) && self.mode == 'DaemonSet' && has(self.serviceMonitorNamespaceSelector))"
+ message: "serviceMonitorNamespaceSelector cannot be set when mode is DaemonSet"
+ - rule: "!(has(self.mode) && self.mode == 'DaemonSet' && has(self.additionalScrapeConfigs))"
+ message: "additionalScrapeConfigs cannot be set when mode is DaemonSet"
+```
+
+#### 6.1.2 Runtime Validation Logic as Fallback
+
+CEL validation will provide immediate feedback during `kubectl apply` but we will need runtime validation logic in the controller as a fallback mechanism. This fallback will be integrated directly in the `PrometheusAgent` reconciler loop.
+
+This is mainly because :
+1. CEL validation will require Kubernetes version 1.25+ and hence not all users might have CEL supported clusters.
+2. This will provide an in-depth defense mechanism against misconfigurations.
+3. More detailed error response in case the first layer of defense fails.
+
+```go
+if spec.Mode == "DaemonSet" {
+ if spec.Replicas != nil {
+ return fmt.Errorf("cannot configure replicas when using DaemonSet mode")
+ }
+ if spec.Storage != nil {
+ return fmt.Errorf("cannot configure storage when using DaemonSet mode")
+ }
+ if spec.Shards > 1 {
+ return fmt.Errorf("shards cannot be greater than 1 when mode is DaemonSet")
+ }
+ if spec.PersistentVolumeClaimRetentionPolicy != nil {
+ return fmt.Errorf("cannot configure persistentVolumeClaimRetentionPolicy when using DaemonSet mode")
+ }
+ if spec.ScrapeConfigSelector != nil {
+ return fmt.Errorf("cannot configure scrapeConfigSelector when using DaemonSet mode")
+ }
+ if spec.ProbeSelector != nil {
+ return fmt.Errorf("cannot configure probeSelector when using DaemonSet mode")
+ }
+ if spec.ProbeNamespaceSelector != nil {
+ return fmt.Errorf("cannot configure probeNamespaceSelector when using DaemonSet mode")
+ }
+ if spec.ScrapeConfigNamespaceSelector != nil {
+ return fmt.Errorf("cannot configure scrapeConfigNamespaceSelector when using DaemonSet mode")
+ }
+ if spec.ServiceMonitorSelector != nil {
+ return fmt.Errorf("cannot configure serviceMonitorSelector when using DaemonSet mode")
+ }
+ if spec.ServiceMonitorNamespaceSelector != nil {
+ return fmt.Errorf("cannot configure serviceMonitorNamespaceSelector when using DaemonSet mode")
+ }
+ if spec.AdditionalScrapeConfigs != nil {
+ return fmt.Errorf("cannot configure additionalScrapeConfigs when using DaemonSet mode")
+ }
+}
+```
+
### 6.2. Node detecting:
As pointed out in [Danny from GMP’s talk](https://www.youtube.com/watch?v=yk2aaAyxgKw), to make Prometheus Agent DaemonSet know which node it’s on, we can use [Kubernetes’ downward API](https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/). In `config-reloader` container, we can mount the node name as an environment variable like this:
@@ -115,6 +207,66 @@ We'll go with this option, because it filters targets right at discovery time, a
We've also considered using relabel config that filters pods by `__meta_kubernetes_pod_node_name` label. However, we didn't choose to go with this option because it filters pods only after discovering all the pods from PodMonitor, which increases load on Kubernetes API server.
+## Secondary/Extended goal (new feature gate)
+
+> **Note:** We are exploring the integration of ServiceMonitor support for DaemonSet mode using EndpointSlice as an experimental feature. This exploration will determine feasibility and performance, and if viable, it may be introduced behind a separate feature gate. This approach allows the main DaemonSet mode to reach GA independently of this feature.
+
+### ServiceMonitor Support with EndpointSlice
+
+To enable ServiceMonitor support for DaemonSet mode while addressing the performance concerns mentioned in section 5, we implement EndpointSlice-based service discovery:
+
+#### EndpointSlice Discovery Implementation
+
+The PrometheusAgent CRD already supports a `serviceDiscoveryRole` field that can be set to `EndpointSlice`:
+
+```yaml
+apiVersion: monitoring.coreos.com/v1alpha1
+kind: PrometheusAgent
+spec:
+ mode: DaemonSet
+ serviceDiscoveryRole: EndpointSlice # Use EndpointSlice instead of Endpoints
+ serviceMonitorSelector:
+ matchLabels:
+ team: platform
+```
+
+When `serviceDiscoveryRole: EndpointSlice` is specified, the generated Prometheus configuration will use:
+
+```yaml
+scrape_configs:
+- job_name: serviceMonitor/default/my-service/0
+ kubernetes_sd_configs:
+ - role: endpointslice # Instead of "endpoints"
+ namespaces:
+ names: [default]
+```
+
+#### Performance Benefits
+
+EndpointSlice provides significant performance improvements over classic Endpoints:
+* **Scalability**: EndpointSlice objects are limited to 1000 endpoints each, preventing massive objects
+* **Efficiency**: Multiple smaller objects reduce memory usage and network traffic
+* **Parallel Processing**: Multiple EndpointSlice objects can be processed in parallel
+* **Reduced API Server Load**: Less stress on Kubernetes API server with distributed endpoint information
+
+#### Implementation Details
+
+The implementation properly handles EndpointSlice support by checking both the user's `serviceDiscoveryRole` setting and cluster compatibility. The logic involves:
+
+```go
+// Check if THIS PrometheusAgent wants EndpointSlice discovery
+cpf := p.GetCommonPrometheusFields()
+if ptr.Deref(cpf.ServiceDiscoveryRole, monitoringv1.EndpointsRole) == monitoringv1.EndpointSliceRole {
+ if c.endpointSliceSupported {
+ opts = append(opts, prompkg.WithEndpointSliceSupport())
+ } else {
+ // Warn user that they want EndpointSlice but cluster doesn't support it
+ c.logger.Warn("EndpointSlice requested but not supported by Kubernetes cluster")
+ // Fall back to classic endpoints
+ }
+}
+```
+
## 7. Action Plan
For the implementation, we’ll do what we detailed in the How section. The common logics between StatefulSet and DaemonSet modes will be extracted into one place. We will have a separate `daemonset.go` for the separate logic of the DaemonSet mode.
diff --git a/Documentation/user-guides/basic-auth.md b/Documentation/user-guides/basic-auth.md
index 0470142b456..e50a890a87e 100644
--- a/Documentation/user-guides/basic-auth.md
+++ b/Documentation/user-guides/basic-auth.md
@@ -5,7 +5,7 @@
## Basic auth for targets
-To authenticate a `ServiceMonitor`s over a metrics endpoint use [`basicAuth`](../api.md#monitoring.coreos.com/v1.BasicAuth)
+To authenticate a `ServiceMonitor`s over a metrics endpoint use [`basicAuth`](../api-reference/api.md#monitoring.coreos.com/v1.BasicAuth)
```yaml
apiVersion: monitoring.coreos.com/v1
diff --git a/Documentation/user-guides/shards-and-replicas.md b/Documentation/user-guides/shards-and-replicas.md
deleted file mode 100644
index 32523e67bb6..00000000000
--- a/Documentation/user-guides/shards-and-replicas.md
+++ /dev/null
@@ -1,155 +0,0 @@
-# Shards and Replicas
-
-If a single Prometheus can't hold the current target's metrics, one can reshard targets onto multiple Prometheus servers.
-
-Shards use the Prometheus `modulus` configuration which takes the hash of the source label values in order to split scrape
-targets based on the number of shards. Prometheus operator will create number of `shards` multiplied by `replicas` pods.
-
-Note that scaling down shards will not reshard data onto remaining instances. It must be manually moved. Increasing
-shards will not reshard data either. It will continue to be available from the same instances.
-To query globally, use the Thanos sidecar and Thanos querier. Alternatively, remote
-write to a central location. Sharding is done on the contents of the `__address__` target meta-label.
-
-## Example
-
-View the complete [Shards manifests](../../example/shards).
-
-The following manifest creates a Prometheus server with two replicas:
-
-```yaml
-apiVersion: monitoring.coreos.com/v1
-kind: Prometheus
-metadata:
- labels:
- prometheus: prometheus
- name: prometheus
- namespace: default
-spec:
- serviceAccountName: prometheus
- replicas: 2
- serviceMonitorSelector:
- matchLabels:
- team: frontend
-```
-
-This can be verified with the following command:
-
-```bash
-> kubectl get pods -n
-```
-
-The output is similar to this:
-
-```bash
-prometheus-prometheus-0 2/2 Running 1 10s
-prometheus-prometheus-1 1/2 Running 1 10s
-```
-
-Deploy the example application and monitor it:
-
-```yaml mdox-exec="cat example/shards/example-app-deployment.yaml"
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: example-app
-spec:
- replicas: 3
- selector:
- matchLabels:
- app: example-app
- template:
- metadata:
- labels:
- app: example-app
- spec:
- containers:
- - name: example-app
- image: quay.io/brancz/prometheus-example-app:v0.5.0
- ports:
- - name: web
- containerPort: 8080
-```
-
-```yaml mdox-exec="cat example/shards/example-app-service.yaml"
-kind: Service
-apiVersion: v1
-metadata:
- name: example-app
- labels:
- app: example-app
-spec:
- selector:
- app: example-app
- ports:
- - name: web
- port: 8080
-```
-
-```yaml mdox-exec="cat example/shards/example-app-service-monitor.yaml"
-apiVersion: monitoring.coreos.com/v1
-kind: ServiceMonitor
-metadata:
- name: example-app
- labels:
- team: frontend
-spec:
- selector:
- matchLabels:
- app: example-app
- endpoints:
- - port: web
-```
-
-Explore one of the monitoring Prometheus instances:
-
-```bash
-> kubectl port-forward pod/prometheus-prometheus-0 9090:9090
-```
-
-We find the prometheus server scrapes three targets.
-
-### Reshard Targets and Expand Prometheus
-
-Expand prometheus to two shards as shown below:
-
-```yaml mdox-exec="cat example/shards/prometheus.yaml"
-apiVersion: monitoring.coreos.com/v1
-kind: Prometheus
-metadata:
- labels:
- prometheus: shards
- name: prometheus
- namespace: default
-spec:
- serviceAccountName: prometheus
- replicas: 2
- shards: 2
- serviceMonitorSelector:
- matchLabels:
- team: frontend
-```
-
-This can be verified with the following command:
-
-```bash
-> kubectl get pods -n
-```
-
-The output is similar to this:
-
-```bash
-prometheus-prometheus-0 2/2 Running 1 11m
-prometheus-prometheus-1 2/2 Running 1 11m
-prometheus-prometheus-shard-1-0 2/2 Running 1 12s
-prometheus-prometheus-shard-1-1 2/2 Running 1 12s
-```
-
-Explore one of the monitoring Prometheus instances added for sharding:
-
-```bash
-> kubectl port-forward prometheus-prometheus-shard-1-0 9091:9090
-```
-
-We find two targets are being scraped. The original Prometheus instance scrapes one target.
-
-To query globally, we must use the Thanos sidecar, since the original data in Prometheus will not be rebalanced.
diff --git a/MAINTAINERS.md b/MAINTAINERS.md
index b5c2e8fb27b..f005841f9a5 100644
--- a/MAINTAINERS.md
+++ b/MAINTAINERS.md
@@ -29,6 +29,7 @@ Full list of triage people is displayed below:
| João Marçal | `@JoaoBraveCoding` | [@JoaoBraveCoding](https://github.com/JoaoBraveCoding) | Red Hat |
| Dong Jiang | `@dongjiang` | [@dongjiang1989](https://github.com/dongjiang1989) | iFlytek |
| S Ashwin | `@Ashwin Sriram` | [@AshwinSriram11](https://github.com/AshwinSriram11) | Deutsche Bank |
+| Mos Nattapong E | `@Nutmos` | [@nutmos](https://github.com/nutmos) | Red Hat |
## Emeritus maintainers
diff --git a/Makefile b/Makefile
index 7067864fc9b..f0374d549ae 100644
--- a/Makefile
+++ b/Makefile
@@ -368,8 +368,7 @@ check-metrics: $(PROMLINTER_BINARY) ## Lint Prometheus metrics.
$(PROMLINTER_BINARY) lint .
.PHONY: check
-check: ## Run all checks.
- check-golang check-api
+check: check-golang check-api ## Run all checks.
.PHONY: check-golang
check-golang: $(GOLANGCILINTER_BINARY) ## Run golangci-lint checks.
@@ -380,12 +379,11 @@ check-api: $(GOLANGCIKUBEAPILINTER_BINARY) ## Run golangci-kube-api-linter check
cd pkg/apis/monitoring && $(GOLANGCIKUBEAPILINTER_BINARY) run -v --config $(ROOT_DIR)/.golangci-kal.yml
.PHONY: fix
-fix: ## Fix all auto-fixable issues.
- fix-golang fix-api
+fix: fix-golang fix-api ## Fix all auto-fixable issues.
.PHONY: fix-golang
fix-golang: $(GOLANGCILINTER_BINARY) ## Run golangci-lint to fix issues.
- $(GOLANGCILINTER_BINARY) run --fix
+ $(GOLANGCILINTER_BINARY) run --fix -v
.PHONY: fix-api
fix-api: $(GOLANGCIKUBEAPILINTER_BINARY) ## Run golangci-kube-api-linter to fix issues on API types.
@@ -409,8 +407,7 @@ check-docs: $(MDOX_BINARY) ## Check documentation formatting and links.
###########
.PHONY: test
-test: ## Run all tests (unit, long, and e2e).
- test-unit test-long test-e2e
+test: test-unit test-long test-e2e ## Run all tests (unit, long, and e2e).
.PHONY: test-unit
test-unit:
diff --git a/RELEASE.md b/RELEASE.md
index c620319331e..88ed732a085 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -18,7 +18,12 @@ The release cycle for cutting releases is every 6 weeks
| Release | Date of release (year-month-day) | Release shepherd |
|---------|----------------------------------|-------------------------------------------|
-| v0.92 | 2026-06-10 | **searching for volunteer** |
+| v0.97 | 2027-01-06 | **searching for volunteer** |
+| v0.96 | 2026-11-25 | **searching for volunteer** |
+| v0.95 | 2026-10-14 | **searching for volunteer** |
+| v0.94 | 2026-09-02 | **searching for volunteer** |
+| v0.93 | 2026-07-22 | Simon Pasquier (GitHub: @simonpasquier) |
+| v0.92 | 2026-06-10 | Jayapriya Pai (Github: @slashpai) |
| v0.91 | 2026-04-29 | Simon Pasquier (GitHub: @simonpasquier) |
| v0.90 | 2026-03-18 | Jayapriya Pai (Github: @slashpai) |
| v0.89 | 2026-02-04 | Simon Pasquier (GitHub: @simonpasquier) |
@@ -41,11 +46,6 @@ The release cycle for cutting releases is every 6 weeks
| v0.72 | 2024-02-21 | Arthur Sens (Github: @ArthurSens) |
| v0.71 | 2024-01-10 | Simon Pasquier (GitHub: @simonpasquier) |
| v0.70 | 2023-11-29 | Pawel Krupa (GitHub: @paulfantom) |
-| v0.69 | 2023-10-18 | Simon Pasquier (GitHub: @simonpasquier) |
-| v0.68 | 2023-09-06 | Arthur Sens (Github: @ArthurSens) |
-| v0.67 | 2023-07-26 | Simon Pasquier (GitHub: @simonpasquier) |
-| v0.66 | 2023-06-14 | Arthur Sens (Github: @ArthurSens) |
-| v0.65 | 2023-05-03 | Philip Gough (GitHub: @PhilipGough) |
If any of the maintainers is interested in volunteering please create a pull request against the [prometheus-operator/prometheus-operator](https://github.com/prometheus-operator/prometheus-operator) repository and propose yourself for the release series of your choice.
diff --git a/VERSION b/VERSION
index 8f63f4f9a10..da011ce41e1 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.91.0
+0.92.1
diff --git a/bundle.yaml b/bundle.yaml
index bea8ae9937c..30fe443b234 100644
--- a/bundle.yaml
+++ b/bundle.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: alertmanagerconfigs.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -760,7 +760,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -1833,7 +1833,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -2600,7 +2600,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -3438,7 +3438,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -4286,7 +4286,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -5146,7 +5146,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -6074,7 +6074,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -7067,7 +7067,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -7874,7 +7874,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -8761,7 +8761,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -9569,7 +9569,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -10319,7 +10319,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -11049,7 +11049,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -11286,6 +11286,14 @@ spec:
format: int32
minimum: 0
type: integer
+ payload:
+ description: |-
+ payload define custom payload to be sent to the webhook endpoint.
+ This is an advanced configuration option that allows you
+ to define a custom payload using Go templates.
+ It requires Alertmanager >= v0.32.0.
+ minLength: 1
+ type: string
sendResolved:
description: sendResolved defines whether or not to notify
about resolved alerts.
@@ -11861,7 +11869,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -12363,8 +12371,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: alertmanagers.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -13988,7 +13996,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the
token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -16400,7 +16408,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -18100,7 +18107,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -21004,7 +21010,7 @@ spec:
A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
- The volume will be mounted read-only (ro) and non-executable files (noexec).
+ The volume will be mounted read-only (ro).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties:
@@ -21176,8 +21182,7 @@ spec:
description: |-
portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
- are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
- is on.
+ are redirected to the pxd.portworx.com CSI driver.
properties:
fsType:
description: |-
@@ -22377,8 +22382,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: podmonitors.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -22441,6 +22446,10 @@ spec:
The Prometheus service account must have the `list` and `watch`
permissions on the `Nodes` objects.
+
+ Node metadata labels are not automatically added to scraped metrics. They are
+ exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ with relabeling configuration.
type: boolean
type: object
bodySizeLimit:
@@ -23142,7 +23151,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -23776,8 +23785,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: probes.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -24453,7 +24462,7 @@ spec:
type: object
tokenUrl:
description: tokenUrl defines the URL to fetch the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -25192,8 +25201,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: prometheusagents.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -27766,7 +27775,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -29687,7 +29695,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -30251,6 +30258,26 @@ spec:
It requires Prometheus >= v3.1.0.
type: boolean
+ labelNamePreserveMultipleUnderscores:
+ description: |-
+ labelNamePreserveMultipleUnderscores enables preserving of multiple consecutive underscores in label names when translation_strategy uses
+ underscore escaping.
+ When true (default), multiple consecutive underscores are preserved during label name sanitization.
+
+ Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+
+ It requires Prometheus >= v3.8.0.
+ type: boolean
+ labelNameUnderscoreSanitization:
+ description: |-
+ labelNameUnderscoreSanitization controls whether to enable prepending of 'key_' to labels starting with '_'.
+ Reserved labels starting with '__' are not modified.
+ This is only relevant when translation_strategy uses underscore escaping (e.g., "UnderscoreEscapingWithSuffixes" or "UnderscoreEscapingWithoutSuffixes").
+
+ Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+
+ It requires Prometheus >= v3.8.0.
+ type: boolean
promoteAllResourceAttributes:
description: |-
promoteAllResourceAttributes promotes all resource attributes to metric labels except the ones defined in `ignoreResourceAttributes`.
@@ -31278,7 +31305,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -31928,6 +31955,10 @@ spec:
The Prometheus service account must have the `list` and `watch`
permissions on the `Nodes` objects.
+
+ Node metadata labels are not automatically added to scraped metrics. They are
+ exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ with relabeling configuration.
type: boolean
type: object
authorization:
@@ -34211,6 +34242,26 @@ spec:
It requires Prometheus >= v2.39.0 or PrometheusAgent >= v2.54.0.
pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
type: string
+ staleSeriesCompactionThreshold:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ staleSeriesCompactionThreshold configures the trigger point for compacting
+ stale series from memory into persistent blocks and removing those stale
+ series from memory.
+
+ The threshold is a number between 0.0 and 1.0. It represents the ratio of
+ stale series in memory to the total series in memory. The stale series
+ compaction is triggered when this ratio crosses the configured threshold.
+ It may not trigger the stale series compaction if the usual head compaction
+ is about to happen soon.
+
+ If set to 0, stale series compaction is disabled.
+
+ It requires Prometheus >= v3.10.0.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
type: object
updateStrategy:
description: |-
@@ -35251,7 +35302,7 @@ spec:
A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
- The volume will be mounted read-only (ro) and non-executable files (noexec).
+ The volume will be mounted read-only (ro).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties:
@@ -35423,8 +35474,7 @@ spec:
description: |-
portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
- are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
- is on.
+ are redirected to the pxd.portworx.com CSI driver.
properties:
fsType:
description: |-
@@ -36708,8 +36758,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: prometheuses.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -40042,7 +40092,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -42005,7 +42054,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -42560,6 +42608,26 @@ spec:
It requires Prometheus >= v3.1.0.
type: boolean
+ labelNamePreserveMultipleUnderscores:
+ description: |-
+ labelNamePreserveMultipleUnderscores enables preserving of multiple consecutive underscores in label names when translation_strategy uses
+ underscore escaping.
+ When true (default), multiple consecutive underscores are preserved during label name sanitization.
+
+ Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+
+ It requires Prometheus >= v3.8.0.
+ type: boolean
+ labelNameUnderscoreSanitization:
+ description: |-
+ labelNameUnderscoreSanitization controls whether to enable prepending of 'key_' to labels starting with '_'.
+ Reserved labels starting with '__' are not modified.
+ This is only relevant when translation_strategy uses underscore escaping (e.g., "UnderscoreEscapingWithSuffixes" or "UnderscoreEscapingWithoutSuffixes").
+
+ Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+
+ It requires Prometheus >= v3.8.0.
+ type: boolean
promoteAllResourceAttributes:
description: |-
promoteAllResourceAttributes promotes all resource attributes to metric labels except the ones defined in `ignoreResourceAttributes`.
@@ -43490,7 +43558,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -43738,7 +43806,11 @@ spec:
type: string
type: object
url:
- description: url defines the URL of the endpoint to query from.
+ description: |-
+ url defines the URL of the endpoint to query from.
+
+ It must use the HTTP or HTTPS scheme.
+ pattern: ^(http|https)://.+$
type: string
required:
- url
@@ -44393,7 +44465,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -45188,6 +45260,10 @@ spec:
The Prometheus service account must have the `list` and `watch`
permissions on the `Nodes` objects.
+
+ Node metadata labels are not automatically added to scraped metrics. They are
+ exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ with relabeling configuration.
type: boolean
type: object
authorization:
@@ -46199,11 +46275,8 @@ spec:
shardRetentionPolicy:
description: |-
shardRetentionPolicy defines the retention policy for the Prometheus shards.
- (Alpha) Using this field requires the 'PrometheusShardRetentionPolicy' feature gate to be enabled.
- The final goals for this feature can be seen at https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/proposals/202310-shard-autoscaling.md#graceful-scale-down-of-prometheus-servers,
- however, the feature is not yet fully implemented in this PR. The limitation being:
- * Retention duration is not settable, for now, shards are retained forever.
+ (Beta) Using this mode requires the `PrometheusShardRetentionPolicy` feature gate (enabled by default).
properties:
retain:
description: |-
@@ -48070,6 +48143,26 @@ spec:
It requires Prometheus >= v2.39.0 or PrometheusAgent >= v2.54.0.
pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
type: string
+ staleSeriesCompactionThreshold:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ staleSeriesCompactionThreshold configures the trigger point for compacting
+ stale series from memory into persistent blocks and removing those stale
+ series from memory.
+
+ The threshold is a number between 0.0 and 1.0. It represents the ratio of
+ stale series in memory to the total series in memory. The stale series
+ compaction is triggered when this ratio crosses the configured threshold.
+ It may not trigger the stale series compaction if the usual head compaction
+ is about to happen soon.
+
+ If set to 0, stale series compaction is disabled.
+
+ It requires Prometheus >= v3.10.0.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
type: object
updateStrategy:
description: |-
@@ -49110,7 +49203,7 @@ spec:
A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
- The volume will be mounted read-only (ro) and non-executable files (noexec).
+ The volume will be mounted read-only (ro).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties:
@@ -49282,8 +49375,7 @@ spec:
description: |-
portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
- are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
- is on.
+ are redirected to the pxd.portworx.com CSI driver.
properties:
fsType:
description: |-
@@ -50540,8 +50632,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: prometheusrules.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -50807,8 +50899,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: scrapeconfigs.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -51377,7 +51469,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -52179,7 +52271,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -52870,7 +52962,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -53639,7 +53731,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -54353,7 +54445,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -55400,7 +55492,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -56184,7 +56276,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -56883,7 +56975,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -57506,7 +57598,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -58243,7 +58335,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -58968,7 +59060,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -59691,7 +59783,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -60343,7 +60435,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -61177,7 +61269,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -61745,7 +61837,7 @@ spec:
type: object
tokenUrl:
description: tokenUrl defines the URL to fetch the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -62675,7 +62767,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -63736,8 +63828,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: servicemonitors.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -63801,6 +63893,10 @@ spec:
The Prometheus service account must have the `list` and `watch`
permissions on the `Nodes` objects.
+
+ Node metadata labels are not automatically added to scraped metrics. They are
+ exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ with relabeling configuration.
type: boolean
type: object
bodySizeLimit:
@@ -64422,7 +64518,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -64444,7 +64540,8 @@ spec:
type: string
port:
description: |-
- port defines the name of the Service port which this endpoint refers to.
+ port defines the name of the Service port which this endpoint refers to
+ (e.g. `.spec.ports[].name`).
It takes precedence over `targetPort`.
type: string
@@ -64610,8 +64707,10 @@ spec:
- type: integer
- type: string
description: |-
- targetPort defines the name or number of the target port of the `Pod` object behind the
- Service. The port must be specified with the container's port property.
+ targetPort defines the name or number of a container port on Pods selected
+ by the Service.
+ If a name, it matches against `.spec.containers[].ports[].name` of the Pods.
+ If a number, it matches against `.spec.containers[].ports[].containerPort` of the Pods.
x-kubernetes-int-or-string: true
tlsConfig:
description: tlsConfig defines TLS configuration used by the
@@ -65149,8 +65248,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: thanosrulers.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -67376,7 +67475,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -69319,7 +69417,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -70615,7 +70712,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -73591,7 +73688,7 @@ spec:
A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
- The volume will be mounted read-only (ro) and non-executable files (noexec).
+ The volume will be mounted read-only (ro).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties:
@@ -73763,8 +73860,7 @@ spec:
description: |-
portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
- are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
- is on.
+ are redirected to the pxd.portworx.com CSI driver.
properties:
fsType:
description: |-
@@ -74945,7 +75041,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
@@ -74962,7 +75058,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
rules:
- apiGroups:
@@ -75075,7 +75171,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
namespace: default
spec:
@@ -75091,13 +75187,13 @@ spec:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
spec:
automountServiceAccountToken: true
containers:
- args:
- --kubelet-service=kube-system/kubelet
- - --prometheus-config-reloader=quay.io/prometheus-operator/prometheus-config-reloader:v0.91.0
+ - --prometheus-config-reloader=quay.io/prometheus-operator/prometheus-config-reloader:v0.92.1
- --watch-referenced-objects-in-all-namespaces=true
- --disable-unmanaged-prometheus-configuration=true
- --kubelet-endpoints=true
@@ -75105,7 +75201,7 @@ spec:
env:
- name: GOGC
value: "30"
- image: quay.io/prometheus-operator/prometheus-operator:v0.91.0
+ image: quay.io/prometheus-operator/prometheus-operator:v0.92.1
name: prometheus-operator
ports:
- containerPort: 8080
@@ -75139,7 +75235,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
namespace: default
---
@@ -75149,7 +75245,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
namespace: default
spec:
diff --git a/cmd/admission-webhook/Dockerfile b/cmd/admission-webhook/Dockerfile
index 71cd4ab158c..8553ce2c464 100644
--- a/cmd/admission-webhook/Dockerfile
+++ b/cmd/admission-webhook/Dockerfile
@@ -1,6 +1,6 @@
ARG ARCH=amd64
ARG OS=linux
-ARG GOLANG_BUILDER=1.25
+ARG GOLANG_BUILDER=1.26
FROM quay.io/prometheus/golang-builder:${GOLANG_BUILDER}-base AS builder
WORKDIR /workspace
diff --git a/cmd/operator/main.go b/cmd/operator/main.go
index fa1232aa4b1..27898865402 100644
--- a/cmd/operator/main.go
+++ b/cmd/operator/main.go
@@ -43,7 +43,6 @@ import (
"k8s.io/client-go/rest"
k8sflag "k8s.io/component-base/cli/flag"
"k8s.io/klog/v2"
- "k8s.io/utils/ptr"
crd "github.com/prometheus-operator/prometheus-operator/example"
"github.com/prometheus-operator/prometheus-operator/internal/goruntime"
@@ -131,7 +130,7 @@ var (
kubeletSyncPeriod time.Duration
kubeletHTTPMetrics bool
- featureGates = k8sflag.NewMapStringBool(ptr.To(map[string]bool{}))
+ featureGates = k8sflag.NewMapStringBool(new(map[string]bool{}))
)
func parseFlags(fs *flag.FlagSet) {
@@ -433,6 +432,16 @@ func start() int {
promAgentControllerOptions = append(promAgentControllerOptions, prometheusagentcontroller.WithEndpointSlice())
}
+ // PodTopologyLabelsAdmission (KEP-4742) is enabled by default in K8s >= 1.35.
+ // It injects topology.kubernetes.io/zone as a pod label, removing the need
+ // for attach_metadata.node=true in topology sharding configurations.
+ podTopologyLabelsSupported := cfg.KubernetesVersion.GTE(semver.MustParse("1.35.0"))
+ logger.Info("Kubernetes API capabilities", "pod_topology_labels", podTopologyLabelsSupported)
+ if podTopologyLabelsSupported {
+ promControllerOptions = append(promControllerOptions, prometheuscontroller.WithPodTopologyLabels())
+ promAgentControllerOptions = append(promAgentControllerOptions, prometheusagentcontroller.WithPodTopologyLabels())
+ }
+
prometheusSupported, err := checkPrerequisites(
ctx,
logger,
diff --git a/cmd/prometheus-config-reloader/Dockerfile b/cmd/prometheus-config-reloader/Dockerfile
index 74ed0f0bd0c..597befb5d04 100644
--- a/cmd/prometheus-config-reloader/Dockerfile
+++ b/cmd/prometheus-config-reloader/Dockerfile
@@ -1,6 +1,6 @@
ARG ARCH=amd64
ARG OS=linux
-ARG GOLANG_BUILDER=1.25
+ARG GOLANG_BUILDER=1.26
FROM quay.io/prometheus/golang-builder:${GOLANG_BUILDER}-base AS builder
WORKDIR /workspace
diff --git a/example/admission-webhook/deployment.yaml b/example/admission-webhook/deployment.yaml
index 3f7cffdeb20..b422389d8dc 100644
--- a/example/admission-webhook/deployment.yaml
+++ b/example/admission-webhook/deployment.yaml
@@ -3,7 +3,7 @@ kind: Deployment
metadata:
labels:
app.kubernetes.io/name: prometheus-operator-admission-webhook
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator-admission-webhook
namespace: default
spec:
@@ -20,7 +20,7 @@ spec:
kubectl.kubernetes.io/default-container: prometheus-operator-admission-webhook
labels:
app.kubernetes.io/name: prometheus-operator-admission-webhook
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
spec:
affinity:
podAntiAffinity:
@@ -37,7 +37,7 @@ spec:
- --web.enable-tls=true
- --web.cert-file=/etc/tls/private/tls.crt
- --web.key-file=/etc/tls/private/tls.key
- image: quay.io/prometheus-operator/admission-webhook:v0.91.0
+ image: quay.io/prometheus-operator/admission-webhook:v0.92.1
name: prometheus-operator-admission-webhook
ports:
- containerPort: 8443
diff --git a/example/admission-webhook/pod-disruption-budget.yaml b/example/admission-webhook/pod-disruption-budget.yaml
index f6506a71f53..2e2d8ec5a30 100644
--- a/example/admission-webhook/pod-disruption-budget.yaml
+++ b/example/admission-webhook/pod-disruption-budget.yaml
@@ -3,7 +3,7 @@ kind: PodDisruptionBudget
metadata:
labels:
app.kubernetes.io/name: prometheus-operator-admission-webhook
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator-admission-webhook
namespace: default
spec:
diff --git a/example/admission-webhook/service-account.yaml b/example/admission-webhook/service-account.yaml
index 2ea4ecb4c2c..ef84b50e3b0 100644
--- a/example/admission-webhook/service-account.yaml
+++ b/example/admission-webhook/service-account.yaml
@@ -4,6 +4,6 @@ kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/name: prometheus-operator-admission-webhook
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator-admission-webhook
namespace: default
diff --git a/example/admission-webhook/service-monitor.yaml b/example/admission-webhook/service-monitor.yaml
index 3e1b87ce3d4..f104385f3e8 100644
--- a/example/admission-webhook/service-monitor.yaml
+++ b/example/admission-webhook/service-monitor.yaml
@@ -3,7 +3,7 @@ kind: ServiceMonitor
metadata:
labels:
app.kubernetes.io/name: prometheus-operator-admission-webhook
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator-admission-webhook
namespace: default
spec:
@@ -13,4 +13,4 @@ spec:
selector:
matchLabels:
app.kubernetes.io/name: prometheus-operator-admission-webhook
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
diff --git a/example/admission-webhook/service.yaml b/example/admission-webhook/service.yaml
index 40ff7d3e4fb..696f40b6457 100644
--- a/example/admission-webhook/service.yaml
+++ b/example/admission-webhook/service.yaml
@@ -3,7 +3,7 @@ kind: Service
metadata:
labels:
app.kubernetes.io/name: prometheus-operator-admission-webhook
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator-admission-webhook
namespace: default
spec:
diff --git a/example/alertmanager-crd-conversion/patch.json b/example/alertmanager-crd-conversion/patch.json
index 863c3e502c3..70b91b8e8f6 100644
--- a/example/alertmanager-crd-conversion/patch.json
+++ b/example/alertmanager-crd-conversion/patch.json
@@ -3,8 +3,8 @@
"kind": "CustomResourceDefinition",
"metadata": {
"annotations": {
- "controller-gen.kubebuilder.io/version": "v0.20.1",
- "operator.prometheus.io/version": "0.91.0"
+ "controller-gen.kubebuilder.io/version": "v0.21.0",
+ "operator.prometheus.io/version": "0.92.1"
},
"name": "alertmanagerconfigs.monitoring.coreos.com"
},
diff --git a/example/prometheus-operator-crd-full/monitoring.coreos.com_alertmanagerconfigs.yaml b/example/prometheus-operator-crd-full/monitoring.coreos.com_alertmanagerconfigs.yaml
index 55218bd631a..7f3d86b4a4e 100644
--- a/example/prometheus-operator-crd-full/monitoring.coreos.com_alertmanagerconfigs.yaml
+++ b/example/prometheus-operator-crd-full/monitoring.coreos.com_alertmanagerconfigs.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: alertmanagerconfigs.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -760,7 +760,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -1833,7 +1833,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -2600,7 +2600,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -3438,7 +3438,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -4286,7 +4286,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -5146,7 +5146,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -6074,7 +6074,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -7067,7 +7067,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -7874,7 +7874,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -8761,7 +8761,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -9569,7 +9569,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -10319,7 +10319,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -11049,7 +11049,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -11286,6 +11286,14 @@ spec:
format: int32
minimum: 0
type: integer
+ payload:
+ description: |-
+ payload define custom payload to be sent to the webhook endpoint.
+ This is an advanced configuration option that allows you
+ to define a custom payload using Go templates.
+ It requires Alertmanager >= v0.32.0.
+ minLength: 1
+ type: string
sendResolved:
description: sendResolved defines whether or not to notify
about resolved alerts.
@@ -11861,7 +11869,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -12989,7 +12997,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -14038,7 +14046,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -14797,7 +14805,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -15619,7 +15627,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -16453,7 +16461,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -17291,7 +17299,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -18193,7 +18201,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -19171,7 +19179,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -19970,7 +19978,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -20842,7 +20850,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -21635,7 +21643,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -22379,7 +22387,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -23101,7 +23109,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -23338,6 +23346,14 @@ spec:
format: int32
minimum: 0
type: integer
+ payload:
+ description: |-
+ payload define custom payload to be sent to the webhook endpoint.
+ This is an advanced configuration option that allows you
+ to define a custom payload using Go templates.
+ It requires Alertmanager >= v0.32.0.
+ minLength: 1
+ type: string
sendResolved:
description: sendResolved defines whether or not to notify
about resolved alerts.
@@ -23891,7 +23907,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
diff --git a/example/prometheus-operator-crd-full/monitoring.coreos.com_alertmanagers.yaml b/example/prometheus-operator-crd-full/monitoring.coreos.com_alertmanagers.yaml
index 48d5ae3d4d7..24298cfe810 100644
--- a/example/prometheus-operator-crd-full/monitoring.coreos.com_alertmanagers.yaml
+++ b/example/prometheus-operator-crd-full/monitoring.coreos.com_alertmanagers.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: alertmanagers.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -1628,7 +1628,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the
token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -4040,7 +4040,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -5740,7 +5739,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -8644,7 +8642,7 @@ spec:
A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
- The volume will be mounted read-only (ro) and non-executable files (noexec).
+ The volume will be mounted read-only (ro).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties:
@@ -8816,8 +8814,7 @@ spec:
description: |-
portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
- are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
- is on.
+ are redirected to the pxd.portworx.com CSI driver.
properties:
fsType:
description: |-
diff --git a/example/prometheus-operator-crd-full/monitoring.coreos.com_podmonitors.yaml b/example/prometheus-operator-crd-full/monitoring.coreos.com_podmonitors.yaml
index f0ac5692b78..2d83e87aab9 100644
--- a/example/prometheus-operator-crd-full/monitoring.coreos.com_podmonitors.yaml
+++ b/example/prometheus-operator-crd-full/monitoring.coreos.com_podmonitors.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: podmonitors.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -67,6 +67,10 @@ spec:
The Prometheus service account must have the `list` and `watch`
permissions on the `Nodes` objects.
+
+ Node metadata labels are not automatically added to scraped metrics. They are
+ exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ with relabeling configuration.
type: boolean
type: object
bodySizeLimit:
@@ -768,7 +772,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
diff --git a/example/prometheus-operator-crd-full/monitoring.coreos.com_probes.yaml b/example/prometheus-operator-crd-full/monitoring.coreos.com_probes.yaml
index 0074f2bcd4d..4f2b5cb4b7a 100644
--- a/example/prometheus-operator-crd-full/monitoring.coreos.com_probes.yaml
+++ b/example/prometheus-operator-crd-full/monitoring.coreos.com_probes.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: probes.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -680,7 +680,7 @@ spec:
type: object
tokenUrl:
description: tokenUrl defines the URL to fetch the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
diff --git a/example/prometheus-operator-crd-full/monitoring.coreos.com_prometheusagents.yaml b/example/prometheus-operator-crd-full/monitoring.coreos.com_prometheusagents.yaml
index 50c40a50e7e..69add8d9752 100644
--- a/example/prometheus-operator-crd-full/monitoring.coreos.com_prometheusagents.yaml
+++ b/example/prometheus-operator-crd-full/monitoring.coreos.com_prometheusagents.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: prometheusagents.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -2577,7 +2577,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -4498,7 +4497,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -5062,6 +5060,26 @@ spec:
It requires Prometheus >= v3.1.0.
type: boolean
+ labelNamePreserveMultipleUnderscores:
+ description: |-
+ labelNamePreserveMultipleUnderscores enables preserving of multiple consecutive underscores in label names when translation_strategy uses
+ underscore escaping.
+ When true (default), multiple consecutive underscores are preserved during label name sanitization.
+
+ Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+
+ It requires Prometheus >= v3.8.0.
+ type: boolean
+ labelNameUnderscoreSanitization:
+ description: |-
+ labelNameUnderscoreSanitization controls whether to enable prepending of 'key_' to labels starting with '_'.
+ Reserved labels starting with '__' are not modified.
+ This is only relevant when translation_strategy uses underscore escaping (e.g., "UnderscoreEscapingWithSuffixes" or "UnderscoreEscapingWithoutSuffixes").
+
+ Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+
+ It requires Prometheus >= v3.8.0.
+ type: boolean
promoteAllResourceAttributes:
description: |-
promoteAllResourceAttributes promotes all resource attributes to metric labels except the ones defined in `ignoreResourceAttributes`.
@@ -6089,7 +6107,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -6739,6 +6757,10 @@ spec:
The Prometheus service account must have the `list` and `watch`
permissions on the `Nodes` objects.
+
+ Node metadata labels are not automatically added to scraped metrics. They are
+ exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ with relabeling configuration.
type: boolean
type: object
authorization:
@@ -9022,6 +9044,26 @@ spec:
It requires Prometheus >= v2.39.0 or PrometheusAgent >= v2.54.0.
pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
type: string
+ staleSeriesCompactionThreshold:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ staleSeriesCompactionThreshold configures the trigger point for compacting
+ stale series from memory into persistent blocks and removing those stale
+ series from memory.
+
+ The threshold is a number between 0.0 and 1.0. It represents the ratio of
+ stale series in memory to the total series in memory. The stale series
+ compaction is triggered when this ratio crosses the configured threshold.
+ It may not trigger the stale series compaction if the usual head compaction
+ is about to happen soon.
+
+ If set to 0, stale series compaction is disabled.
+
+ It requires Prometheus >= v3.10.0.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
type: object
updateStrategy:
description: |-
@@ -10062,7 +10104,7 @@ spec:
A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
- The volume will be mounted read-only (ro) and non-executable files (noexec).
+ The volume will be mounted read-only (ro).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties:
@@ -10234,8 +10276,7 @@ spec:
description: |-
portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
- are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
- is on.
+ are redirected to the pxd.portworx.com CSI driver.
properties:
fsType:
description: |-
diff --git a/example/prometheus-operator-crd-full/monitoring.coreos.com_prometheuses.yaml b/example/prometheus-operator-crd-full/monitoring.coreos.com_prometheuses.yaml
index 58a1e423511..30204cdc435 100644
--- a/example/prometheus-operator-crd-full/monitoring.coreos.com_prometheuses.yaml
+++ b/example/prometheus-operator-crd-full/monitoring.coreos.com_prometheuses.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: prometheuses.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -3337,7 +3337,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -5300,7 +5299,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -5855,6 +5853,26 @@ spec:
It requires Prometheus >= v3.1.0.
type: boolean
+ labelNamePreserveMultipleUnderscores:
+ description: |-
+ labelNamePreserveMultipleUnderscores enables preserving of multiple consecutive underscores in label names when translation_strategy uses
+ underscore escaping.
+ When true (default), multiple consecutive underscores are preserved during label name sanitization.
+
+ Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+
+ It requires Prometheus >= v3.8.0.
+ type: boolean
+ labelNameUnderscoreSanitization:
+ description: |-
+ labelNameUnderscoreSanitization controls whether to enable prepending of 'key_' to labels starting with '_'.
+ Reserved labels starting with '__' are not modified.
+ This is only relevant when translation_strategy uses underscore escaping (e.g., "UnderscoreEscapingWithSuffixes" or "UnderscoreEscapingWithoutSuffixes").
+
+ Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+
+ It requires Prometheus >= v3.8.0.
+ type: boolean
promoteAllResourceAttributes:
description: |-
promoteAllResourceAttributes promotes all resource attributes to metric labels except the ones defined in `ignoreResourceAttributes`.
@@ -6785,7 +6803,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -7033,7 +7051,11 @@ spec:
type: string
type: object
url:
- description: url defines the URL of the endpoint to query from.
+ description: |-
+ url defines the URL of the endpoint to query from.
+
+ It must use the HTTP or HTTPS scheme.
+ pattern: ^(http|https)://.+$
type: string
required:
- url
@@ -7688,7 +7710,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -8483,6 +8505,10 @@ spec:
The Prometheus service account must have the `list` and `watch`
permissions on the `Nodes` objects.
+
+ Node metadata labels are not automatically added to scraped metrics. They are
+ exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ with relabeling configuration.
type: boolean
type: object
authorization:
@@ -9494,11 +9520,8 @@ spec:
shardRetentionPolicy:
description: |-
shardRetentionPolicy defines the retention policy for the Prometheus shards.
- (Alpha) Using this field requires the 'PrometheusShardRetentionPolicy' feature gate to be enabled.
- The final goals for this feature can be seen at https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/proposals/202310-shard-autoscaling.md#graceful-scale-down-of-prometheus-servers,
- however, the feature is not yet fully implemented in this PR. The limitation being:
- * Retention duration is not settable, for now, shards are retained forever.
+ (Beta) Using this mode requires the `PrometheusShardRetentionPolicy` feature gate (enabled by default).
properties:
retain:
description: |-
@@ -11365,6 +11388,26 @@ spec:
It requires Prometheus >= v2.39.0 or PrometheusAgent >= v2.54.0.
pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
type: string
+ staleSeriesCompactionThreshold:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ staleSeriesCompactionThreshold configures the trigger point for compacting
+ stale series from memory into persistent blocks and removing those stale
+ series from memory.
+
+ The threshold is a number between 0.0 and 1.0. It represents the ratio of
+ stale series in memory to the total series in memory. The stale series
+ compaction is triggered when this ratio crosses the configured threshold.
+ It may not trigger the stale series compaction if the usual head compaction
+ is about to happen soon.
+
+ If set to 0, stale series compaction is disabled.
+
+ It requires Prometheus >= v3.10.0.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
type: object
updateStrategy:
description: |-
@@ -12405,7 +12448,7 @@ spec:
A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
- The volume will be mounted read-only (ro) and non-executable files (noexec).
+ The volume will be mounted read-only (ro).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties:
@@ -12577,8 +12620,7 @@ spec:
description: |-
portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
- are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
- is on.
+ are redirected to the pxd.portworx.com CSI driver.
properties:
fsType:
description: |-
diff --git a/example/prometheus-operator-crd-full/monitoring.coreos.com_prometheusrules.yaml b/example/prometheus-operator-crd-full/monitoring.coreos.com_prometheusrules.yaml
index 236cda0e3a7..b594dfee269 100644
--- a/example/prometheus-operator-crd-full/monitoring.coreos.com_prometheusrules.yaml
+++ b/example/prometheus-operator-crd-full/monitoring.coreos.com_prometheusrules.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: prometheusrules.monitoring.coreos.com
spec:
group: monitoring.coreos.com
diff --git a/example/prometheus-operator-crd-full/monitoring.coreos.com_scrapeconfigs.yaml b/example/prometheus-operator-crd-full/monitoring.coreos.com_scrapeconfigs.yaml
index 73b24f01332..75169bf429a 100644
--- a/example/prometheus-operator-crd-full/monitoring.coreos.com_scrapeconfigs.yaml
+++ b/example/prometheus-operator-crd-full/monitoring.coreos.com_scrapeconfigs.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: scrapeconfigs.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -573,7 +573,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -1375,7 +1375,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -2066,7 +2066,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -2835,7 +2835,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -3549,7 +3549,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -4596,7 +4596,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -5380,7 +5380,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -6079,7 +6079,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -6702,7 +6702,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -7439,7 +7439,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -8164,7 +8164,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -8887,7 +8887,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -9539,7 +9539,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -10373,7 +10373,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -10941,7 +10941,7 @@ spec:
type: object
tokenUrl:
description: tokenUrl defines the URL to fetch the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -11871,7 +11871,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
diff --git a/example/prometheus-operator-crd-full/monitoring.coreos.com_servicemonitors.yaml b/example/prometheus-operator-crd-full/monitoring.coreos.com_servicemonitors.yaml
index 5548f726251..d64c9060370 100644
--- a/example/prometheus-operator-crd-full/monitoring.coreos.com_servicemonitors.yaml
+++ b/example/prometheus-operator-crd-full/monitoring.coreos.com_servicemonitors.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: servicemonitors.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -68,6 +68,10 @@ spec:
The Prometheus service account must have the `list` and `watch`
permissions on the `Nodes` objects.
+
+ Node metadata labels are not automatically added to scraped metrics. They are
+ exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ with relabeling configuration.
type: boolean
type: object
bodySizeLimit:
@@ -689,7 +693,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -711,7 +715,8 @@ spec:
type: string
port:
description: |-
- port defines the name of the Service port which this endpoint refers to.
+ port defines the name of the Service port which this endpoint refers to
+ (e.g. `.spec.ports[].name`).
It takes precedence over `targetPort`.
type: string
@@ -877,8 +882,10 @@ spec:
- type: integer
- type: string
description: |-
- targetPort defines the name or number of the target port of the `Pod` object behind the
- Service. The port must be specified with the container's port property.
+ targetPort defines the name or number of a container port on Pods selected
+ by the Service.
+ If a name, it matches against `.spec.containers[].ports[].name` of the Pods.
+ If a number, it matches against `.spec.containers[].ports[].containerPort` of the Pods.
x-kubernetes-int-or-string: true
tlsConfig:
description: tlsConfig defines TLS configuration used by the
diff --git a/example/prometheus-operator-crd-full/monitoring.coreos.com_thanosrulers.yaml b/example/prometheus-operator-crd-full/monitoring.coreos.com_thanosrulers.yaml
index 383c526ba50..314e174c945 100644
--- a/example/prometheus-operator-crd-full/monitoring.coreos.com_thanosrulers.yaml
+++ b/example/prometheus-operator-crd-full/monitoring.coreos.com_thanosrulers.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: thanosrulers.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -2230,7 +2230,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -4173,7 +4172,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -5469,7 +5467,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -8445,7 +8443,7 @@ spec:
A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
- The volume will be mounted read-only (ro) and non-executable files (noexec).
+ The volume will be mounted read-only (ro).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties:
@@ -8617,8 +8615,7 @@ spec:
description: |-
portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
- are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
- is on.
+ are redirected to the pxd.portworx.com CSI driver.
properties:
fsType:
description: |-
diff --git a/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml b/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
index 47941d6f62a..7677a0eb80b 100644
--- a/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+++ b/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: alertmanagerconfigs.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -760,7 +760,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -1833,7 +1833,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -2600,7 +2600,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -3438,7 +3438,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -4286,7 +4286,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -5146,7 +5146,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -6074,7 +6074,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -7067,7 +7067,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -7874,7 +7874,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -8761,7 +8761,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -9569,7 +9569,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -10319,7 +10319,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -11049,7 +11049,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -11286,6 +11286,14 @@ spec:
format: int32
minimum: 0
type: integer
+ payload:
+ description: |-
+ payload define custom payload to be sent to the webhook endpoint.
+ This is an advanced configuration option that allows you
+ to define a custom payload using Go templates.
+ It requires Alertmanager >= v0.32.0.
+ minLength: 1
+ type: string
sendResolved:
description: sendResolved defines whether or not to notify
about resolved alerts.
@@ -11861,7 +11869,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch
the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
diff --git a/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml b/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
index 48d5ae3d4d7..24298cfe810 100644
--- a/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+++ b/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: alertmanagers.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -1628,7 +1628,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the
token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -4040,7 +4040,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -5740,7 +5739,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -8644,7 +8642,7 @@ spec:
A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
- The volume will be mounted read-only (ro) and non-executable files (noexec).
+ The volume will be mounted read-only (ro).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties:
@@ -8816,8 +8814,7 @@ spec:
description: |-
portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
- are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
- is on.
+ are redirected to the pxd.portworx.com CSI driver.
properties:
fsType:
description: |-
diff --git a/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml b/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
index f0ac5692b78..2d83e87aab9 100644
--- a/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+++ b/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: podmonitors.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -67,6 +67,10 @@ spec:
The Prometheus service account must have the `list` and `watch`
permissions on the `Nodes` objects.
+
+ Node metadata labels are not automatically added to scraped metrics. They are
+ exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ with relabeling configuration.
type: boolean
type: object
bodySizeLimit:
@@ -768,7 +772,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
diff --git a/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml b/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
index 0074f2bcd4d..4f2b5cb4b7a 100644
--- a/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+++ b/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: probes.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -680,7 +680,7 @@ spec:
type: object
tokenUrl:
description: tokenUrl defines the URL to fetch the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
diff --git a/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml b/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml
index 50c40a50e7e..69add8d9752 100644
--- a/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml
+++ b/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: prometheusagents.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -2577,7 +2577,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -4498,7 +4497,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -5062,6 +5060,26 @@ spec:
It requires Prometheus >= v3.1.0.
type: boolean
+ labelNamePreserveMultipleUnderscores:
+ description: |-
+ labelNamePreserveMultipleUnderscores enables preserving of multiple consecutive underscores in label names when translation_strategy uses
+ underscore escaping.
+ When true (default), multiple consecutive underscores are preserved during label name sanitization.
+
+ Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+
+ It requires Prometheus >= v3.8.0.
+ type: boolean
+ labelNameUnderscoreSanitization:
+ description: |-
+ labelNameUnderscoreSanitization controls whether to enable prepending of 'key_' to labels starting with '_'.
+ Reserved labels starting with '__' are not modified.
+ This is only relevant when translation_strategy uses underscore escaping (e.g., "UnderscoreEscapingWithSuffixes" or "UnderscoreEscapingWithoutSuffixes").
+
+ Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+
+ It requires Prometheus >= v3.8.0.
+ type: boolean
promoteAllResourceAttributes:
description: |-
promoteAllResourceAttributes promotes all resource attributes to metric labels except the ones defined in `ignoreResourceAttributes`.
@@ -6089,7 +6107,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -6739,6 +6757,10 @@ spec:
The Prometheus service account must have the `list` and `watch`
permissions on the `Nodes` objects.
+
+ Node metadata labels are not automatically added to scraped metrics. They are
+ exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ with relabeling configuration.
type: boolean
type: object
authorization:
@@ -9022,6 +9044,26 @@ spec:
It requires Prometheus >= v2.39.0 or PrometheusAgent >= v2.54.0.
pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
type: string
+ staleSeriesCompactionThreshold:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ staleSeriesCompactionThreshold configures the trigger point for compacting
+ stale series from memory into persistent blocks and removing those stale
+ series from memory.
+
+ The threshold is a number between 0.0 and 1.0. It represents the ratio of
+ stale series in memory to the total series in memory. The stale series
+ compaction is triggered when this ratio crosses the configured threshold.
+ It may not trigger the stale series compaction if the usual head compaction
+ is about to happen soon.
+
+ If set to 0, stale series compaction is disabled.
+
+ It requires Prometheus >= v3.10.0.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
type: object
updateStrategy:
description: |-
@@ -10062,7 +10104,7 @@ spec:
A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
- The volume will be mounted read-only (ro) and non-executable files (noexec).
+ The volume will be mounted read-only (ro).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties:
@@ -10234,8 +10276,7 @@ spec:
description: |-
portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
- are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
- is on.
+ are redirected to the pxd.portworx.com CSI driver.
properties:
fsType:
description: |-
diff --git a/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml b/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
index 58a1e423511..30204cdc435 100644
--- a/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+++ b/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: prometheuses.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -3337,7 +3337,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -5300,7 +5299,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -5855,6 +5853,26 @@ spec:
It requires Prometheus >= v3.1.0.
type: boolean
+ labelNamePreserveMultipleUnderscores:
+ description: |-
+ labelNamePreserveMultipleUnderscores enables preserving of multiple consecutive underscores in label names when translation_strategy uses
+ underscore escaping.
+ When true (default), multiple consecutive underscores are preserved during label name sanitization.
+
+ Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+
+ It requires Prometheus >= v3.8.0.
+ type: boolean
+ labelNameUnderscoreSanitization:
+ description: |-
+ labelNameUnderscoreSanitization controls whether to enable prepending of 'key_' to labels starting with '_'.
+ Reserved labels starting with '__' are not modified.
+ This is only relevant when translation_strategy uses underscore escaping (e.g., "UnderscoreEscapingWithSuffixes" or "UnderscoreEscapingWithoutSuffixes").
+
+ Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+
+ It requires Prometheus >= v3.8.0.
+ type: boolean
promoteAllResourceAttributes:
description: |-
promoteAllResourceAttributes promotes all resource attributes to metric labels except the ones defined in `ignoreResourceAttributes`.
@@ -6785,7 +6803,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -7033,7 +7051,11 @@ spec:
type: string
type: object
url:
- description: url defines the URL of the endpoint to query from.
+ description: |-
+ url defines the URL of the endpoint to query from.
+
+ It must use the HTTP or HTTPS scheme.
+ pattern: ^(http|https)://.+$
type: string
required:
- url
@@ -7688,7 +7710,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -8483,6 +8505,10 @@ spec:
The Prometheus service account must have the `list` and `watch`
permissions on the `Nodes` objects.
+
+ Node metadata labels are not automatically added to scraped metrics. They are
+ exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ with relabeling configuration.
type: boolean
type: object
authorization:
@@ -9494,11 +9520,8 @@ spec:
shardRetentionPolicy:
description: |-
shardRetentionPolicy defines the retention policy for the Prometheus shards.
- (Alpha) Using this field requires the 'PrometheusShardRetentionPolicy' feature gate to be enabled.
- The final goals for this feature can be seen at https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/proposals/202310-shard-autoscaling.md#graceful-scale-down-of-prometheus-servers,
- however, the feature is not yet fully implemented in this PR. The limitation being:
- * Retention duration is not settable, for now, shards are retained forever.
+ (Beta) Using this mode requires the `PrometheusShardRetentionPolicy` feature gate (enabled by default).
properties:
retain:
description: |-
@@ -11365,6 +11388,26 @@ spec:
It requires Prometheus >= v2.39.0 or PrometheusAgent >= v2.54.0.
pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
type: string
+ staleSeriesCompactionThreshold:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ staleSeriesCompactionThreshold configures the trigger point for compacting
+ stale series from memory into persistent blocks and removing those stale
+ series from memory.
+
+ The threshold is a number between 0.0 and 1.0. It represents the ratio of
+ stale series in memory to the total series in memory. The stale series
+ compaction is triggered when this ratio crosses the configured threshold.
+ It may not trigger the stale series compaction if the usual head compaction
+ is about to happen soon.
+
+ If set to 0, stale series compaction is disabled.
+
+ It requires Prometheus >= v3.10.0.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
type: object
updateStrategy:
description: |-
@@ -12405,7 +12448,7 @@ spec:
A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
- The volume will be mounted read-only (ro) and non-executable files (noexec).
+ The volume will be mounted read-only (ro).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties:
@@ -12577,8 +12620,7 @@ spec:
description: |-
portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
- are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
- is on.
+ are redirected to the pxd.portworx.com CSI driver.
properties:
fsType:
description: |-
diff --git a/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml b/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
index 236cda0e3a7..b594dfee269 100644
--- a/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
+++ b/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: prometheusrules.monitoring.coreos.com
spec:
group: monitoring.coreos.com
diff --git a/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml b/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml
index 73b24f01332..75169bf429a 100644
--- a/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml
+++ b/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: scrapeconfigs.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -573,7 +573,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -1375,7 +1375,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -2066,7 +2066,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -2835,7 +2835,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -3549,7 +3549,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -4596,7 +4596,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -5380,7 +5380,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -6079,7 +6079,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -6702,7 +6702,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -7439,7 +7439,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -8164,7 +8164,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -8887,7 +8887,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -9539,7 +9539,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -10373,7 +10373,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -10941,7 +10941,7 @@ spec:
type: object
tokenUrl:
description: tokenUrl defines the URL to fetch the token from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -11871,7 +11871,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
diff --git a/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml b/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
index 5548f726251..d64c9060370 100644
--- a/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+++ b/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: servicemonitors.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -68,6 +68,10 @@ spec:
The Prometheus service account must have the `list` and `watch`
permissions on the `Nodes` objects.
+
+ Node metadata labels are not automatically added to scraped metrics. They are
+ exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ with relabeling configuration.
type: boolean
type: object
bodySizeLimit:
@@ -689,7 +693,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -711,7 +715,8 @@ spec:
type: string
port:
description: |-
- port defines the name of the Service port which this endpoint refers to.
+ port defines the name of the Service port which this endpoint refers to
+ (e.g. `.spec.ports[].name`).
It takes precedence over `targetPort`.
type: string
@@ -877,8 +882,10 @@ spec:
- type: integer
- type: string
description: |-
- targetPort defines the name or number of the target port of the `Pod` object behind the
- Service. The port must be specified with the container's port property.
+ targetPort defines the name or number of a container port on Pods selected
+ by the Service.
+ If a name, it matches against `.spec.containers[].ports[].name` of the Pods.
+ If a number, it matches against `.spec.containers[].ports[].containerPort` of the Pods.
x-kubernetes-int-or-string: true
tlsConfig:
description: tlsConfig defines TLS configuration used by the
diff --git a/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml b/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
index 383c526ba50..314e174c945 100644
--- a/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+++ b/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
@@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
- operator.prometheus.io/version: 0.91.0
+ controller-gen.kubebuilder.io/version: v0.21.0
+ operator.prometheus.io/version: 0.92.1
name: thanosrulers.monitoring.coreos.com
spec:
group: monitoring.coreos.com
@@ -2230,7 +2230,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -4173,7 +4172,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
- This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@@ -5469,7 +5467,7 @@ spec:
tokenUrl:
description: tokenUrl defines the URL to fetch the token
from.
- minLength: 1
+ pattern: ^(http|https)://.+$
type: string
required:
- clientId
@@ -8445,7 +8443,7 @@ spec:
A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
- The volume will be mounted read-only (ro) and non-executable files (noexec).
+ The volume will be mounted read-only (ro).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties:
@@ -8617,8 +8615,7 @@ spec:
description: |-
portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
- are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
- is on.
+ are redirected to the pxd.portworx.com CSI driver.
properties:
fsType:
description: |-
diff --git a/example/rbac/prometheus-operator/prometheus-operator-cluster-role-binding.yaml b/example/rbac/prometheus-operator/prometheus-operator-cluster-role-binding.yaml
index e9db851aca9..079ba10b8fc 100644
--- a/example/rbac/prometheus-operator/prometheus-operator-cluster-role-binding.yaml
+++ b/example/rbac/prometheus-operator/prometheus-operator-cluster-role-binding.yaml
@@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
diff --git a/example/rbac/prometheus-operator/prometheus-operator-cluster-role.yaml b/example/rbac/prometheus-operator/prometheus-operator-cluster-role.yaml
index b5dd7ec1ba4..f59b0638aa7 100644
--- a/example/rbac/prometheus-operator/prometheus-operator-cluster-role.yaml
+++ b/example/rbac/prometheus-operator/prometheus-operator-cluster-role.yaml
@@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
rules:
- apiGroups:
diff --git a/example/rbac/prometheus-operator/prometheus-operator-deployment.yaml b/example/rbac/prometheus-operator/prometheus-operator-deployment.yaml
index a86b95aa014..d1c88bedc35 100644
--- a/example/rbac/prometheus-operator/prometheus-operator-deployment.yaml
+++ b/example/rbac/prometheus-operator/prometheus-operator-deployment.yaml
@@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
namespace: default
spec:
@@ -20,13 +20,13 @@ spec:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
spec:
automountServiceAccountToken: true
containers:
- args:
- --kubelet-service=kube-system/kubelet
- - --prometheus-config-reloader=quay.io/prometheus-operator/prometheus-config-reloader:v0.91.0
+ - --prometheus-config-reloader=quay.io/prometheus-operator/prometheus-config-reloader:v0.92.1
- --watch-referenced-objects-in-all-namespaces=true
- --disable-unmanaged-prometheus-configuration=true
- --kubelet-endpoints=true
@@ -34,7 +34,7 @@ spec:
env:
- name: GOGC
value: "30"
- image: quay.io/prometheus-operator/prometheus-operator:v0.91.0
+ image: quay.io/prometheus-operator/prometheus-operator:v0.92.1
name: prometheus-operator
ports:
- containerPort: 8080
diff --git a/example/rbac/prometheus-operator/prometheus-operator-service-account.yaml b/example/rbac/prometheus-operator/prometheus-operator-service-account.yaml
index 4ee7935f988..93c4df9f41a 100644
--- a/example/rbac/prometheus-operator/prometheus-operator-service-account.yaml
+++ b/example/rbac/prometheus-operator/prometheus-operator-service-account.yaml
@@ -5,6 +5,6 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
namespace: default
diff --git a/example/rbac/prometheus-operator/prometheus-operator-service-monitor.yaml b/example/rbac/prometheus-operator/prometheus-operator-service-monitor.yaml
index 6f803e1a6b5..a84494e8c12 100644
--- a/example/rbac/prometheus-operator/prometheus-operator-service-monitor.yaml
+++ b/example/rbac/prometheus-operator/prometheus-operator-service-monitor.yaml
@@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
namespace: default
spec:
@@ -15,4 +15,4 @@ spec:
matchLabels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
diff --git a/example/rbac/prometheus-operator/prometheus-operator-service.yaml b/example/rbac/prometheus-operator/prometheus-operator-service.yaml
index 5fac9236082..08be5ce6b57 100644
--- a/example/rbac/prometheus-operator/prometheus-operator-service.yaml
+++ b/example/rbac/prometheus-operator/prometheus-operator-service.yaml
@@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: prometheus-operator
- app.kubernetes.io/version: 0.91.0
+ app.kubernetes.io/version: 0.92.1
name: prometheus-operator
namespace: default
spec:
diff --git a/example/shards/example-app-deployment.yaml b/example/shards/example-app-deployment.yaml
index 4bca530185f..c8682871109 100644
--- a/example/shards/example-app-deployment.yaml
+++ b/example/shards/example-app-deployment.yaml
@@ -2,6 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: example-app
+ namespace: default
spec:
replicas: 3
selector:
diff --git a/example/shards/example-app-service-monitor.yaml b/example/shards/example-app-service-monitor.yaml
index d2a68fc9548..32f6ae00de6 100644
--- a/example/shards/example-app-service-monitor.yaml
+++ b/example/shards/example-app-service-monitor.yaml
@@ -2,6 +2,7 @@ apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: example-app
+ namespace: default
labels:
team: frontend
spec:
diff --git a/example/shards/example-app-service.yaml b/example/shards/example-app-service.yaml
index 9f5048ca63a..4afb84959d9 100644
--- a/example/shards/example-app-service.yaml
+++ b/example/shards/example-app-service.yaml
@@ -2,6 +2,7 @@ kind: Service
apiVersion: v1
metadata:
name: example-app
+ namespace: default
labels:
app: example-app
spec:
diff --git a/go.mod b/go.mod
index 848253436b6..b2d8e613e1f 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/prometheus-operator/prometheus-operator
-go 1.25.0
+go 1.26.0
require (
github.com/KimMachineGun/automemlimit v0.7.5
@@ -19,116 +19,139 @@ require (
github.com/mitchellh/hashstructure v1.1.0
github.com/oklog/run v1.2.0
github.com/prometheus-community/prom-label-proxy v0.13.0
- github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.91.0
- github.com/prometheus-operator/prometheus-operator/pkg/client v0.91.0
- github.com/prometheus/alertmanager v0.32.1
+ github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.92.1
+ github.com/prometheus-operator/prometheus-operator/pkg/client v0.92.1
+ github.com/prometheus/alertmanager v0.33.0
github.com/prometheus/client_golang v1.23.2
- github.com/prometheus/common v0.67.5
+ github.com/prometheus/common v0.69.0
github.com/prometheus/exporter-toolkit v0.16.0
- github.com/prometheus/prometheus v0.311.3
+ github.com/prometheus/prometheus v0.312.0
github.com/stretchr/testify v1.11.1
github.com/thanos-io/thanos v0.41.0
- golang.org/x/net v0.53.0
- golang.org/x/sync v0.20.0
- google.golang.org/protobuf v1.36.11
+ golang.org/x/net v0.56.0
+ golang.org/x/sync v0.21.0
+ google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af
gopkg.in/yaml.v2 v2.4.0
- k8s.io/api v0.35.4
- k8s.io/apiextensions-apiserver v0.35.4
- k8s.io/apimachinery v0.35.4
- k8s.io/apiserver v0.35.4
- k8s.io/client-go v0.35.4
- k8s.io/component-base v0.35.4
+ k8s.io/api v0.36.2
+ k8s.io/apiextensions-apiserver v0.36.2
+ k8s.io/apimachinery v0.36.2
+ k8s.io/apiserver v0.36.2
+ k8s.io/client-go v0.36.2
+ k8s.io/component-base v0.36.2
k8s.io/klog/v2 v2.140.0
- k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2
- sigs.k8s.io/controller-runtime v0.23.3
+ k8s.io/utils v0.0.0-20260507154919-ff6756f316d2
+ sigs.k8s.io/controller-runtime v0.24.1
sigs.k8s.io/yaml v1.6.0
)
require (
- github.com/aws/aws-sdk-go-v2 v1.41.5 // indirect
- github.com/aws/aws-sdk-go-v2/config v1.32.13 // indirect
- github.com/aws/aws-sdk-go-v2/credentials v1.19.13 // indirect
- github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 // indirect
- github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect
- github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect
- github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect
- github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 // indirect
- github.com/aws/aws-sdk-go-v2/service/sso v1.30.14 // indirect
- github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.18 // indirect
- github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 // indirect
- github.com/aws/smithy-go v1.24.2 // indirect
+ github.com/armon/go-metrics v0.4.1 // indirect
+ github.com/aws/aws-sdk-go-v2 v1.41.7 // indirect
+ github.com/aws/aws-sdk-go-v2/config v1.32.18 // indirect
+ github.com/aws/aws-sdk-go-v2/credentials v1.19.17 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 // indirect
+ github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect
+ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 // indirect
+ github.com/aws/smithy-go v1.26.0 // indirect
+ github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
+ github.com/coder/quartz v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.7.0 // indirect
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect
- github.com/felixge/httpsnoop v1.0.4 // indirect
- github.com/fxamacker/cbor/v2 v2.9.0 // indirect
- github.com/go-openapi/swag v0.25.5 // indirect
- github.com/go-openapi/swag/cmdutils v0.25.5 // indirect
- github.com/go-openapi/swag/conv v0.25.5 // indirect
- github.com/go-openapi/swag/fileutils v0.25.5 // indirect
- github.com/go-openapi/swag/jsonname v0.25.5 // indirect
- github.com/go-openapi/swag/jsonutils v0.25.5 // indirect
- github.com/go-openapi/swag/loading v0.25.5 // indirect
- github.com/go-openapi/swag/mangling v0.25.5 // indirect
- github.com/go-openapi/swag/netutils v0.25.5 // indirect
- github.com/go-openapi/swag/stringutils v0.25.5 // indirect
- github.com/go-openapi/swag/typeutils v0.25.5 // indirect
- github.com/go-openapi/swag/yamlutils v0.25.5 // indirect
+ github.com/felixge/httpsnoop v1.1.0 // indirect
+ github.com/fxamacker/cbor/v2 v2.9.2 // indirect
+ github.com/go-openapi/runtime/server-middleware v0.32.3 // indirect
+ github.com/go-openapi/swag v0.26.1 // indirect
+ github.com/go-openapi/swag/cmdutils v0.26.1 // indirect
+ github.com/go-openapi/swag/conv v0.26.1 // indirect
+ github.com/go-openapi/swag/fileutils v0.26.1 // indirect
+ github.com/go-openapi/swag/jsonname v0.26.1 // indirect
+ github.com/go-openapi/swag/jsonutils v0.26.1 // indirect
+ github.com/go-openapi/swag/loading v0.26.1 // indirect
+ github.com/go-openapi/swag/mangling v0.26.1 // indirect
+ github.com/go-openapi/swag/netutils v0.26.1 // indirect
+ github.com/go-openapi/swag/stringutils v0.26.1 // indirect
+ github.com/go-openapi/swag/typeutils v0.26.1 // indirect
+ github.com/go-openapi/swag/yamlutils v0.26.1 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
+ github.com/google/btree v1.1.3 // indirect
github.com/google/gnostic-models v0.7.1 // indirect
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
+ github.com/hashicorp/errwrap v1.1.0 // indirect
+ github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
+ github.com/hashicorp/go-metrics v0.5.4 // indirect
+ github.com/hashicorp/go-msgpack/v2 v2.1.5 // indirect
+ github.com/hashicorp/go-multierror v1.1.1 // indirect
+ github.com/hashicorp/go-sockaddr v1.0.7 // indirect
+ github.com/hashicorp/golang-lru v0.6.0 // indirect
+ github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
+ github.com/hashicorp/memberlist v0.5.4 // indirect
+ github.com/klauspost/compress v1.18.6 // indirect
github.com/mdlayher/socket v0.5.1 // indirect
github.com/mdlayher/vsock v1.2.1 // indirect
+ github.com/miekg/dns v1.1.72 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
- github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/oklog/ulid/v2 v2.1.1 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
+ github.com/pierrec/lz4/v4 v4.1.26 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/sigv4 v0.4.1 // indirect
+ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
+ github.com/twmb/franz-go v1.21.2 // indirect
+ github.com/twmb/franz-go/pkg/kmsg v1.13.1 // indirect
+ github.com/twmb/franz-go/plugin/kslog v1.0.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.67.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect
- go.opentelemetry.io/otel/sdk v1.43.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.69.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.44.0 // indirect
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
- golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
- google.golang.org/grpc v1.80.0 // indirect
+ golang.org/x/exp v0.0.0-20260611194520-c48552f49976 // indirect
+ golang.org/x/mod v0.37.0 // indirect
+ golang.org/x/tools v0.46.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20260610212136-7ab31c22f7ad // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad // indirect
+ google.golang.org/grpc v1.81.1 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
+ k8s.io/streaming v0.36.2 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
- sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect
+ sigs.k8s.io/structured-merge-diff/v6 v6.4.0 // indirect
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dennwc/varint v1.0.0 // indirect
- github.com/edsrzf/mmap-go v1.2.0 // indirect
+ github.com/edsrzf/mmap-go v1.2.1-0.20241212181136-fad1cd13edbd // indirect
github.com/efficientgo/core v1.0.0-rc.3 // indirect
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
- github.com/fsnotify/fsnotify v1.9.0 // indirect
+ github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/go-logfmt/logfmt v0.6.1 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
- github.com/go-openapi/analysis v0.25.0 // indirect
- github.com/go-openapi/errors v0.22.7 // indirect
- github.com/go-openapi/jsonpointer v0.22.5 // indirect
- github.com/go-openapi/jsonreference v0.21.5 // indirect
- github.com/go-openapi/loads v0.23.3 // indirect
- github.com/go-openapi/runtime v0.29.3 // indirect
- github.com/go-openapi/spec v0.22.4 // indirect
- github.com/go-openapi/strfmt v0.26.1 // indirect
- github.com/go-openapi/validate v0.25.2 // indirect
+ github.com/go-openapi/analysis v0.25.2 // indirect
+ github.com/go-openapi/errors v0.22.8 // indirect
+ github.com/go-openapi/jsonpointer v0.23.1 // indirect
+ github.com/go-openapi/jsonreference v0.21.6 // indirect
+ github.com/go-openapi/loads v0.24.0 // indirect
+ github.com/go-openapi/runtime v0.32.3 // indirect
+ github.com/go-openapi/spec v0.22.6 // indirect
+ github.com/go-openapi/strfmt v0.26.3 // indirect
+ github.com/go-openapi/validate v0.26.0 // indirect
github.com/google/uuid v1.6.0
github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
@@ -149,20 +172,20 @@ require (
github.com/spf13/cobra v1.10.2 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
- go.opentelemetry.io/otel v1.43.0 // indirect
- go.opentelemetry.io/otel/metric v1.43.0 // indirect
- go.opentelemetry.io/otel/trace v1.43.0 // indirect
+ go.opentelemetry.io/otel v1.44.0 // indirect
+ go.opentelemetry.io/otel/metric v1.44.0 // indirect
+ go.opentelemetry.io/otel/trace v1.44.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
- golang.org/x/crypto v0.50.0 // indirect
+ golang.org/x/crypto v0.53.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect
- golang.org/x/sys v0.43.0 // indirect
- golang.org/x/term v0.42.0 // indirect
- golang.org/x/text v0.36.0 // indirect
+ golang.org/x/sys v0.46.0 // indirect
+ golang.org/x/term v0.44.0 // indirect
+ golang.org/x/text v0.38.0 // indirect
golang.org/x/time v0.15.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.2
- k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect
+ k8s.io/kube-openapi v0.0.0-20260603220949-865597e52e25 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
)
diff --git a/go.sum b/go.sum
index 89c900b1335..89a2b6473ae 100644
--- a/go.sum
+++ b/go.sum
@@ -1,19 +1,21 @@
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.120.0 h1:wc6bgG9DHyKqF5/vQvX1CiZrtHnxJjBlKUyF9nP6meA=
-cloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM=
-cloud.google.com/go/auth v0.18.2/go.mod h1:xD+oY7gcahcu7G2SG2DsBerfFxgPAJz17zz2joOFF3M=
+cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA=
+cloud.google.com/go/auth v0.20.0/go.mod h1:942/yi/itH1SsmpyrbnTMDgGfdy2BUqIKyd0cyYLc5Q=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1 h1:jHb/wfvRikGdxMXYV3QG/SzUOPYN9KEUUuC0Yd0/vC0=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1/go.mod h1:pzBXCYn05zvYIrwLgtK8Ap8QcjRg+0i76tMQdWN6wOk=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 h1:fhqpLE3UEXi9lPaBRpQ6XuRW0nU7hgg4zlmZZa+a9q4=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0/go.mod h1:7dCRMLwisfRH3dBupKeNCioWYUZ4SS09Z14H+7i8ZoY=
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs=
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
+github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/KimMachineGun/automemlimit v0.7.5 h1:RkbaC0MwhjL1ZuBKunGDjE/ggwAX43DwZrJqVwyveTk=
github.com/KimMachineGun/automemlimit v0.7.5/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
@@ -24,40 +26,43 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0=
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
+github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
+github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
-github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY=
-github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
-github.com/aws/aws-sdk-go-v2/config v1.32.13 h1:5KgbxMaS2coSWRrx9TX/QtWbqzgQkOdEa3sZPhBhCSg=
-github.com/aws/aws-sdk-go-v2/config v1.32.13/go.mod h1:8zz7wedqtCbw5e9Mi2doEwDyEgHcEE9YOJp6a8jdSMY=
-github.com/aws/aws-sdk-go-v2/credentials v1.19.13 h1:mA59E3fokBvyEGHKFdnpNNrvaR351cqiHgRg+JzOSRI=
-github.com/aws/aws-sdk-go-v2/credentials v1.19.13/go.mod h1:yoTXOQKea18nrM69wGF9jBdG4WocSZA1h38A+t/MAsk=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 h1:NUS3K4BTDArQqNu2ih7yeDLaS3bmHD0YndtA6UP884g=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21/go.mod h1:YWNWJQNjKigKY1RHVJCuupeWDrrHjRqHm0N9rdrWzYI=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 h1:c31//R3xgIJMSC8S6hEVq+38DcvUlgFY0FM6mSI5oto=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA=
-github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 h1:QKZH0S178gCmFEgst8hN0mCX1KxLgHBKKY/CLqwP8lg=
-github.com/aws/aws-sdk-go-v2/service/signin v1.0.9/go.mod h1:7yuQJoT+OoH8aqIxw9vwF+8KpvLZ8AWmvmUWHsGQZvI=
-github.com/aws/aws-sdk-go-v2/service/sso v1.30.14 h1:GcLE9ba5ehAQma6wlopUesYg/hbcOhFNWTjELkiWkh4=
-github.com/aws/aws-sdk-go-v2/service/sso v1.30.14/go.mod h1:WSvS1NLr7JaPunCXqpJnWk1Bjo7IxzZXrZi1QQCkuqM=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.18 h1:mP49nTpfKtpXLt5SLn8Uv8z6W+03jYVoOSAl/c02nog=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.18/go.mod h1:YO8TrYtFdl5w/4vmjL8zaBSsiNp3w0L1FfKVKenZT7w=
-github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 h1:p8ogvvLugcR/zLBXTXrTkj0RYBUdErbMnAFFp12Lm/U=
-github.com/aws/aws-sdk-go-v2/service/sts v1.41.10/go.mod h1:60dv0eZJfeVXfbT1tFJinbHrDfSJ2GZl4Q//OSSNAVw=
-github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng=
-github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
+github.com/aws/aws-sdk-go-v2 v1.41.7 h1:DWpAJt66FmnnaRIOT/8ASTucrvuDPZASqhhLey6tLY8=
+github.com/aws/aws-sdk-go-v2 v1.41.7/go.mod h1:4LAfZOPHNVNQEckOACQx60Y8pSRjIkNZQz1w92xpMJc=
+github.com/aws/aws-sdk-go-v2/config v1.32.18 h1:Hcia46bxhGgF3BaSnG8nSNCWmqTK6bj9xN9/FJ3WK6Q=
+github.com/aws/aws-sdk-go-v2/config v1.32.18/go.mod h1:zEjCAYmxqDadH1WX8CdBvmLKhUEUVFgKRQG38zjDmrY=
+github.com/aws/aws-sdk-go-v2/credentials v1.19.17 h1:gP2nkGsS+KMvF/jfFz2Vv2qiiOqWKyPACSzPsqHgoW8=
+github.com/aws/aws-sdk-go-v2/credentials v1.19.17/go.mod h1:Bsew3S/moG5iT77giPj1q8wb/s0RE5/QfH+ASjYtuQc=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 h1:UuSfcORqNSz/ey3VPRS8TcVH2Ikf0/sC+Hdj400QI6U=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23/go.mod h1:+G/OSGiOFnSOkYloKj/9M35s74LgVAdJBSD5lsFfqKg=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 h1:GpT/TrnBYuE5gan2cZbTtvP+JlHsutdmlV2YfEyNde0=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23/go.mod h1:xYWD6BS9ywC5bS3sz9Xh04whO/hzK2plt2Zkyrp4JuA=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 h1:bpd8vxhlQi2r1hiueOw02f/duEPTMK59Q4QMAoTTtTo=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23/go.mod h1:15DfR2nw+CRHIk0tqNyifu3G1YdAOy68RftkhMDDwYk=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 h1:OQqn11BtaYv1WLUowvcA30MpzIu8Ti4pcLPIIyoKZrA=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24/go.mod h1:X5ZJyfwVrWA96GzPmUCWFQaEARPR7gCrpq2E92PJwAE=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 h1:FLudkZLt5ci0ozzgkVo8BJGwvqNaZbTWb3UcucAateA=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9/go.mod h1:w7wZ/s9qK7c8g4al+UyoF1Sp/Z45UwMGcqIzLWVQHWk=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 h1:pbrxO/kuIwgEsOPLkaHu0O+m4fNgLU8B3vxQ+72jTPw=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23/go.mod h1:/CMNUqoj46HpS3MNRDEDIwcgEnrtZlKRaHNaHxIFpNA=
+github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 h1:TdJ+HdzOBhU8+iVAOGUTU63VXopcumCOF1paFulHWZc=
+github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI=
+github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE=
+github.com/aws/aws-sdk-go-v2/service/sso v1.30.17/go.mod h1:xNWknVi4Ezm1vg1QsB/5EWpAJURq22uqd38U8qKvOJc=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0 h1:nDARhv/oF55bcxF7rCI/4PDxOKnVXVWwDuDwCs2I2SQ=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0/go.mod h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg=
+github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 h1:F/M5Y9I3nwr2IEpshZgh1GeHpOItExNM9L1euNuh/fk=
+github.com/aws/aws-sdk-go-v2/service/sts v1.42.1/go.mod h1:mTNxImtovCOEEuD65mKW7DCsL+2gjEH+RPEAexAzAio=
+github.com/aws/smithy-go v1.26.0 h1:9ouqbi+NyKP7fV3Te7UElCwdAb6Y8uk7LGwPE5tVe/s=
+github.com/aws/smithy-go v1.26.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps=
github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3/go.mod h1:CIWtjkly68+yqLPbvwwR/fjNJA/idrtULjZWh2v1ys0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -66,11 +71,17 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
+github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
+github.com/coder/quartz v0.3.1 h1:JMJLj4Xj4NLSrUC1R/g/Hn0y9fkyOvb8tf6P0j+kPn0=
+github.com/coder/quartz v0.3.1/go.mod h1:BgE7DOj/8NfvRgvKw0jPLDQH/2Lya2kxcTaNJ8X0rZk=
github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=
github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
@@ -82,8 +93,8 @@ github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE=
github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/edsrzf/mmap-go v1.2.0 h1:hXLYlkbaPzt1SaQk+anYwKSRNhufIDCchSPkUD6dD84=
-github.com/edsrzf/mmap-go v1.2.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
+github.com/edsrzf/mmap-go v1.2.1-0.20241212181136-fad1cd13edbd h1:I4PrRZuNMeDP3VbFrak4QsqwO5tWkQf0tqrrr1L2DsU=
+github.com/edsrzf/mmap-go v1.2.1-0.20241212181136-fad1cd13edbd/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
github.com/efficientgo/core v1.0.0-rc.3 h1:X6CdgycYWDcbYiJr1H1+lQGzx13o7bq3EUkbB9DsSPc=
github.com/efficientgo/core v1.0.0-rc.3/go.mod h1:FfGdkzWarkuzOlY04VY+bGfb1lWrjaL6x/GLcQ4vJps=
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
@@ -92,18 +103,20 @@ github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjT
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM=
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc=
-github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
-github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
-github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
-github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
-github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
-github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
+github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc=
+github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
+github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
+github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
+github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78=
+github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE=
github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -113,54 +126,56 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
-github.com/go-openapi/analysis v0.25.0 h1:EnjAq1yO8wEO9HbPmY8vLPEIkdZuuFhCAKBPvCB7bCs=
-github.com/go-openapi/analysis v0.25.0/go.mod h1:5WFTRE43WLkPG9r9OtlMfqkkvUTYLVVCIxLlEpyF8kE=
-github.com/go-openapi/errors v0.22.7 h1:JLFBGC0Apwdzw3484MmBqspjPbwa2SHvpDm0u5aGhUA=
-github.com/go-openapi/errors v0.22.7/go.mod h1://QW6SD9OsWtH6gHllUCddOXDL0tk0ZGNYHwsw4sW3w=
-github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA=
-github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0=
-github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE=
-github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=
-github.com/go-openapi/loads v0.23.3 h1:g5Xap1JfwKkUnZdn+S0L3SzBDpcTIYzZ5Qaag0YDkKQ=
-github.com/go-openapi/loads v0.23.3/go.mod h1:NOH07zLajXo8y55hom0omlHWDVVvCwBM/S+csCK8LqA=
-github.com/go-openapi/runtime v0.29.3 h1:h5twGaEqxtQg40ePiYm9vFFH1q06Czd7Ot6ufdK0w/Y=
-github.com/go-openapi/runtime v0.29.3/go.mod h1:8A1W0/L5eyNJvKciqZtvIVQvYO66NlB7INMSZ9bw/oI=
-github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ=
-github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ=
-github.com/go-openapi/strfmt v0.26.1 h1:7zGCHji7zSYDC2tCXIusoxYQz/48jAf2q+sF6wXTG+c=
-github.com/go-openapi/strfmt v0.26.1/go.mod h1:Zslk5VZPOISLwmWTMBIS7oiVFem1o1EI6zULY8Uer7Y=
-github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU=
-github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA=
-github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c=
-github.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
-github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g=
-github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k=
-github.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk=
-github.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc=
-github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo=
-github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU=
-github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo=
-github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo=
-github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU=
-github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g=
-github.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw=
-github.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY=
-github.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU=
-github.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14=
-github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M=
-github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII=
-github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E=
-github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc=
-github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ=
-github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ=
-github.com/go-openapi/testify/enable/yaml/v2 v2.4.1 h1:NZOrZmIb6PTv5LTFxr5/mKV/FjbUzGE7E6gLz7vFoOQ=
-github.com/go-openapi/testify/enable/yaml/v2 v2.4.1/go.mod h1:r7dwsujEHawapMsxA69i+XMGZrQ5tRauhLAjV/sxg3Q=
-github.com/go-openapi/testify/v2 v2.4.1 h1:zB34HDKj4tHwyUQHrUkpV0Q0iXQ6dUCOQtIqn8hE6Iw=
-github.com/go-openapi/testify/v2 v2.4.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
-github.com/go-openapi/validate v0.25.2 h1:12NsfLAwGegqbGWr2CnvT65X/Q2USJipmJ9b7xDJZz0=
-github.com/go-openapi/validate v0.25.2/go.mod h1:Pgl1LpPPGFnZ+ys4/hTlDiRYQdI1ocKypgE+8Q8BLfY=
+github.com/go-openapi/analysis v0.25.2 h1:I0vy4n3alz+DHTiN1PRhCb7QZxkK6g5YmswZKv2TKuw=
+github.com/go-openapi/analysis v0.25.2/go.mod h1:Uhs1t/2XR10EnwONYILGEzw8gcfGIG5Xk5K2AxnhqDo=
+github.com/go-openapi/errors v0.22.8 h1:oP7sW7TWc3wFFjrzzj0nI83H2qMBkNjNfSd+XRejk/I=
+github.com/go-openapi/errors v0.22.8/go.mod h1:BuUoHcYrU6E7V9gfj1I5wLQqgtIHnup/alXZ8KdgQ0w=
+github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4=
+github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY=
+github.com/go-openapi/jsonreference v0.21.6 h1:NZ5nGfnaM1n4I43Xjm1e5/M2GjOwQwndQz22uhxwD+Y=
+github.com/go-openapi/jsonreference v0.21.6/go.mod h1:xzbgtQ3ZbWxvET3AxdzCJlJt6vkovbf+IfSPJjD0tUY=
+github.com/go-openapi/loads v0.24.0 h1:4LLorXRPTzIN9V6ngMUZbAscsBOUBk3Oa8cClu/bFrQ=
+github.com/go-openapi/loads v0.24.0/go.mod h1:xQMgX+hw5xRAhGrcDXxeMw78IFqUpIzhleu3HqPhyF4=
+github.com/go-openapi/runtime v0.32.3 h1:J7Ycy5DJmhhP1By3NifhRUjnkXTrk21qbeqSULjwX8U=
+github.com/go-openapi/runtime v0.32.3/go.mod h1:/WTQi0fa5DiGnnCXQKsTkSm15OzJp8Uz3H2t+67TBr4=
+github.com/go-openapi/runtime/server-middleware v0.32.3 h1:Y/6h9ix9NCoMG04XazRwX6eA3alh4+JZ6qXdar5yd24=
+github.com/go-openapi/runtime/server-middleware v0.32.3/go.mod h1:fYPep4GdTwg/XqZUjR40uIM/8C12Ba5M+MrGCiwpTHo=
+github.com/go-openapi/spec v0.22.6 h1:Tyy1pLaNCM8GBCFLoGYLonjJi6zykqyLCjXLc19ZPic=
+github.com/go-openapi/spec v0.22.6/go.mod h1:HZvTHat+iH0PALQRWhrqIHtU/PEqxqd89fu0MxGlMeM=
+github.com/go-openapi/strfmt v0.26.3 h1:rzmslHarJgBbf2qfGge+X3htclQfmXqBZMm0Too0HhU=
+github.com/go-openapi/strfmt v0.26.3/go.mod h1:a5nsUw0oRpQzZeOwx8bi6cKbzFZslpbCKt1LEot+KnQ=
+github.com/go-openapi/swag v0.26.1 h1:l5sVEyVpwj+DDYeZyo7wQI/Ebn/mKYIyGB/pFwAfGoQ=
+github.com/go-openapi/swag v0.26.1/go.mod h1:yNY38BbIVthxbkDtq1UHBCGasBqjakW3lCR6ANzdBEw=
+github.com/go-openapi/swag/cmdutils v0.26.1 h1:f2iE1ijYaJ3nuu5PaEMx3zpEhzhZFgivCJObWEObLIQ=
+github.com/go-openapi/swag/cmdutils v0.26.1/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM=
+github.com/go-openapi/swag/conv v0.26.1 h1:slr5FVkg9Wc3Y5zcwenD8Sd/PQ94b2I/QJI7N7KTBpg=
+github.com/go-openapi/swag/conv v0.26.1/go.mod h1:mvQXgPptZk9GTrFgGwWvT4q+dN+zQej9JfmGwnipz1A=
+github.com/go-openapi/swag/fileutils v0.26.1 h1:K1XCM2CGhfNsc6YDt6v7Q5+1e59rftYWdcu/isZhvFw=
+github.com/go-openapi/swag/fileutils v0.26.1/go.mod h1:mYUgxQAKX4ShS3qvvySx+/9yrlUnDhjiD1CalaQl8lQ=
+github.com/go-openapi/swag/jsonname v0.26.1 h1:VReupaV6WxlAsCn0e4DUfgV6bPmINnPpyJDLqSfNPcE=
+github.com/go-openapi/swag/jsonname v0.26.1/go.mod h1:OvdW6BoWoj33pTfi7x9vFrgmT+fk7aw0BRwvCE0YOuc=
+github.com/go-openapi/swag/jsonutils v0.26.1 h1:2hdBfFkHg+7Wrz2VsCbeyR6hzkRDs7AztnMR2u84yOY=
+github.com/go-openapi/swag/jsonutils v0.26.1/go.mod h1:U+RMJH3wa+6BRiphuRtIyI8fW9HPFqFQ4sHk2oRx0UQ=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1 h1:1CD7NiLLb/TXl3tOnFYU4b+mNfb5rtgHkaA+q7RMYYQ=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1/go.mod h1:ZWafc8nMdYzTE3uYY6W86f0n46+IF0g4uUyRhJw/kXc=
+github.com/go-openapi/swag/loading v0.26.1 h1:E9K4wqXeROlhjFQ13K9zMz6ojFGXIggGe+ad1odrK9w=
+github.com/go-openapi/swag/loading v0.26.1/go.mod h1:3qvRIlWzWdq1HvmldwmuJ2ohpcAryN6xVt2OTKd0/7E=
+github.com/go-openapi/swag/mangling v0.26.1 h1:gpYI4WuPKFJJVjV5cDLGlDVJhFIxYjQc7yN5eEb4CqM=
+github.com/go-openapi/swag/mangling v0.26.1/go.mod h1:POETDH01hqAdASXfw7ISEd9bCOE6xBHOt8NHmGZRmYM=
+github.com/go-openapi/swag/netutils v0.26.1 h1:BNctoc39WTAUMxyAs355fExOPzMZtPbZ0ZZ1Am2FR5M=
+github.com/go-openapi/swag/netutils v0.26.1/go.mod h1:y02vByhZhQPAVwOX+0KipXFZ/hUbk6G/Enhf5rGaOkQ=
+github.com/go-openapi/swag/stringutils v0.26.1 h1:f88uYyTso7TnHrKM/bUBsQ5e2wKf37cpgo6pvbzd9yU=
+github.com/go-openapi/swag/stringutils v0.26.1/go.mod h1:Sc6d3bU8fgk5AyZR8/8jEQ+Is/Ald+TD/IIggPN8UJk=
+github.com/go-openapi/swag/typeutils v0.26.1 h1:yg42FgMzRR6PVQ3M3qHz1s+Y6/P4HoJ3cBarXa3OVnU=
+github.com/go-openapi/swag/typeutils v0.26.1/go.mod h1:VfnV+oUtSP2vCSCn2aJgnr8OevUYemyIzzS1VOzS10o=
+github.com/go-openapi/swag/yamlutils v0.26.1 h1:0TSLK+lXs9vfIhAWzBeI/lOzEnIoot6WTCO1aAeWFTk=
+github.com/go-openapi/swag/yamlutils v0.26.1/go.mod h1:7W5b7PRX9MxwL7TjeG7H8HkyBGRsIDRObhyMWFgBI2M=
+github.com/go-openapi/testify/enable/yaml/v2 v2.5.1 h1:q9NtHwK4qHF7yZziBPvZyv7zWAIk8ok88Gh2mR6Jpc8=
+github.com/go-openapi/testify/enable/yaml/v2 v2.5.1/go.mod h1:JW0MXIotCYps/XsgJnG3a8Q7rE5xAiBwoOD5OfaIQBk=
+github.com/go-openapi/testify/v2 v2.5.1 h1:TMdhCaw8fUNraVSf3Omoob1dO/AzBfhtFAPW0an6sBo=
+github.com/go-openapi/testify/v2 v2.5.1/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
+github.com/go-openapi/validate v0.26.0 h1:dxWzQ3F+vb1SajqUxHjwb5T4mTpSHmdrtv5Bi7+ZNhw=
+github.com/go-openapi/validate v0.26.0/go.mod h1:b4o00uq7fJeJA+wWhVFCJpKTctzeFwzZImGGmHsl2JA=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
@@ -176,50 +191,91 @@ github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArs
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
+github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c=
github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc h1:VBbFa1lDYWEeV5FZKUiYKYT0VxCp9twUmmaq9eb8sXw=
-github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
+github.com/google/pprof v0.0.0-20260507013755-92041b743c96 h1:YDDnaZ9afWajDboPMt9Vikqca/yWAX7KAxVzb4lJU1M=
+github.com/google/pprof v0.0.0-20260507013755-92041b743c96/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/enterprise-certificate-proxy v0.3.14 h1:yh8ncqsbUY4shRD5dA6RlzjJaT4hi3kII+zYw8wmLb8=
-github.com/googleapis/enterprise-certificate-proxy v0.3.14/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg=
+github.com/googleapis/enterprise-certificate-proxy v0.3.15 h1:xolVQTEXusUcAA5UgtyRLjelpFFHWlPQ4XfWGc7MBas=
+github.com/googleapis/enterprise-certificate-proxy v0.3.15/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg=
github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww=
-github.com/googleapis/gax-go/v2 v2.18.0 h1:jxP5Uuo3bxm3M6gGtV94P4lliVetoCB4Wk2x8QA86LI=
-github.com/googleapis/gax-go/v2 v2.18.0/go.mod h1:uSzZN4a356eRG985CzJ3WfbFSpqkLTjsnhWGJR6EwrE=
+github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4=
+github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 h1:cLN4IBkmkYZNnk7EAJ0BHIethd+J6LqxFNw5mSiI2bM=
github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
+github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY=
+github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI=
+github.com/hashicorp/go-msgpack/v2 v2.1.5 h1:Ue879bPnutj/hXfmUk6s/jtIK90XxgiUIcXRl656T44=
+github.com/hashicorp/go-msgpack/v2 v2.1.5/go.mod h1:bjCsRXpZ7NsJdk45PoCQnzRGDaK8TKm5ZnDI/9y3J4M=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
+github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw=
+github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw=
+github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
+github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
+github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
+github.com/hashicorp/memberlist v0.5.4 h1:40YY+3qq2tAUhZIMEK8kqusKZBBjdwJ3NUjvYkcxh74=
+github.com/hashicorp/memberlist v0.5.4/go.mod h1:OgN6xiIo6RlHUWk+ALjP9e32xWCoQrsOCmHrWCm2MWA=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
-github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
+github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
+github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -237,6 +293,8 @@ github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
github.com/metalmatze/signal v0.0.0-20210307161603-1c9aa721a97a h1:0usWxe5SGXKQovz3p+BiQ81Jy845xSMu2CWKuXsXuUM=
github.com/metalmatze/signal v0.0.0-20210307161603-1c9aa721a97a/go.mod h1:3OETvrxfELvGsU2RoGGWercfeZ4bCL3+SOwzIWtJH/Q=
+github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
+github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
@@ -258,22 +316,24 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E=
github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk=
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns=
-github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
-github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
-github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
+github.com/onsi/ginkgo/v2 v2.27.4 h1:fcEcQW/A++6aZAZQNUmNjvA9PSOzefMJBerHJ4t8v8Y=
+github.com/onsi/ginkgo/v2 v2.27.4/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
+github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
+github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
+github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
+github.com/pierrec/lz4/v4 v4.1.26 h1:GrpZw1gZttORinvzBdXPUXATeqlJjqUG/D87TKMnhjY=
+github.com/pierrec/lz4/v4 v4.1.26/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -285,15 +345,18 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus-community/prom-label-proxy v0.13.0 h1:SD27XYzzLbw1TL9Jv/W2yAWJ9pCz2EsUTyhjya87Ndg=
github.com/prometheus-community/prom-label-proxy v0.13.0/go.mod h1:T5Z6OtsxvjFbbhvQ7wyrJu+CBdGBQeWcNkC8SSy4WUU=
-github.com/prometheus/alertmanager v0.32.1 h1:BQ3jHXNq2A7VSD9Kh0Qx+kXbifNbHSDuKVbMmdRHHJ0=
-github.com/prometheus/alertmanager v0.32.1/go.mod h1:0Dy9faTtMgpVYxJVxV0o65elTxHnSRCF/7gy5BKGZiE=
+github.com/prometheus/alertmanager v0.33.0 h1:AAVa3wpCsaDxisTUUPXx+1qhnA2mx0f8Cc+smpAtN7w=
+github.com/prometheus/alertmanager v0.33.0/go.mod h1:V06Uc8EZ5X5wLOJRGhtXx+EE2LgrinFIADbKWMVm1RY=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
-github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856 h1:1Y6bmpZb8peQCy1IpctnAhIFuyhrdtMaDnETChhSNns=
-github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856/go.mod h1:Vf0QcmVhGqpjLxZOaWrFSep86vchQtJmbztFaMM4f6Q=
+github.com/prometheus/client_golang/exp v0.0.0-20260518105423-c9d5bc4c50a9 h1:e33IfrrwrJkylWwAGcQ2jMvbWVv13lv0suTXjGNeiqY=
+github.com/prometheus/client_golang/exp v0.0.0-20260518105423-c9d5bc4c50a9/go.mod h1:vW/EVguzbNw6xMRmozJQWbY60/+Zsg0TgVJOSXGx2iI=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -301,8 +364,10 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
-github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
-github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/common v0.69.0 h1:OA85nJQS/T/MaYh/Q2CcgDKSGWqNIgrBDvDH85CuiNk=
+github.com/prometheus/common v0.69.0/go.mod h1:ZzL3f6u94qUxh9p+tJTrF+FvBS1XXbbRAZCQkytAL0Y=
github.com/prometheus/exporter-toolkit v0.16.0 h1:xT/j7L2XKF+VJd6B4fpUw6xWabHrSmsUf6mYmFqyu0s=
github.com/prometheus/exporter-toolkit v0.16.0/go.mod h1:d1EL8Z9674xQe/iWhwP2wDyCEoBPbXVeqDbqAUsgJWY=
github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos=
@@ -310,17 +375,22 @@ github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVR
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=
github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
-github.com/prometheus/prometheus v0.311.3 h1:3IrVxQv6v5i/ZCGi6OrYeBhtCwaPTn6Z3DYruXoYm3M=
-github.com/prometheus/prometheus v0.311.3/go.mod h1:gjsCxTKtHO1Q8T9333u1s+lUR1OjPyM7ruuGH8RvVyo=
+github.com/prometheus/prometheus v0.312.0 h1:f9jdv2fQhQ1fks9a9YwlGZrKr4hih0rRP/rh0mu3Q18=
+github.com/prometheus/prometheus v0.312.0/go.mod h1:8oAYd2XPgHXLP4fFKam594R/ZLlPicrrBkVdaWt74Sw=
github.com/prometheus/sigv4 v0.4.1 h1:EIc3j+8NBea9u1iV6O5ZAN8uvPq2xOIUPcqCTivHuXs=
github.com/prometheus/sigv4 v0.4.1/go.mod h1:eu+ZbRvsc5TPiHwqh77OWuCnWK73IdkETYY46P4dXOU=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
@@ -344,6 +414,15 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/thanos-io/thanos v0.41.0 h1:GDPGynjHBa8ORAX7DfluBFjHbMeY1BzjLTGdviFvo7Q=
github.com/thanos-io/thanos v0.41.0/go.mod h1:ppdHafpAT8WAbcwgLiNU4jNtNe17Ct3xX9dXq+h6g2k=
+github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
+github.com/twmb/franz-go v1.21.2 h1:WrvV/spF48JzcRylqDQy02Vm6V6W4lhtD9Y4BOYNMu4=
+github.com/twmb/franz-go v1.21.2/go.mod h1:rfoMTnVk7107fhTGxfEKIHP/e7tPe6oyij/ywzO0czk=
+github.com/twmb/franz-go/pkg/kfake v0.0.0-20260515175617-8268a5d078c0 h1:YWmvjmcidrKLLgObwU1k7K9KuesdYTV33OTIS0Ltj8o=
+github.com/twmb/franz-go/pkg/kfake v0.0.0-20260515175617-8268a5d078c0/go.mod h1:9j4VxU2ng6tHgD4lIkNJ5OJ3D6vgPhhIp3tBa7dJgLA=
+github.com/twmb/franz-go/pkg/kmsg v1.13.1 h1:fG5kItwysTk5UXqVwb64EpQEy3TydF3vYYK21nUQ+bI=
+github.com/twmb/franz-go/pkg/kmsg v1.13.1/go.mod h1:+DPt4NC8RmI6hqb8G09+3giKObE6uD2Eya6CfqBpeJY=
+github.com/twmb/franz-go/plugin/kslog v1.0.0 h1:I64oEmF+0PDvmyLgwrlOtg4mfpSE9GwlcLxM4af2t60=
+github.com/twmb/franz-go/plugin/kslog v1.0.0/go.mod h1:8pMjK3OJJJNNYddBSbnXZkIK5dCKFIk9GcVVCDgvnQc=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
@@ -352,26 +431,26 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
-go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.67.0 h1:c9r/G1CSw4dPI1jaNNG9RnQP+q4SvZnHciDQJVIvchU=
-go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.67.0/go.mod h1:gO9smoZe9KnZcJCqcB0lMmQ4Z5VEifYmjMTpnwtTSuQ=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg=
-go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
-go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 h1:zWWrB1U6nqhS/k6zYB74CjRpuiitRtLLi68VcgmOEto=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0/go.mod h1:2qXPNBX1OVRC0IwOnfo1ljoid+RD0QK3443EaqVlsOU=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak=
-go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
-go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
-go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
-go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
-go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
-go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
-go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
-go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
+go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.69.0 h1:MCcYL7J6Vt/X0kjqbMZkekCmwsurbQRbL69vkiye2lk=
+go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.69.0/go.mod h1:3jnStNwSufK+f5ktjL4EPcwtig4rtd81NS70lqHuXl8=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
+go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
+go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0 h1:qazEJlUOQzhCpzQpFETGby7EdqjI1wsd0W+6Gg1SCTU=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0/go.mod h1:fOD2Yefuxixkx3ahVNf0O/PERb6r4OlbxfATVnYvzCo=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 h1:lgh3PiVrRUWMLOVSkQicxzZll5NjF1r+AtsX1XRIHw0=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0/go.mod h1:5Cnhth3m/AgOeTgE3ex12pPmiu/gGtZit03kSzx9X7s=
+go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
+go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
+go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
+go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
+go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
+go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
+go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
+go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
@@ -380,8 +459,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
-go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
-go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
+go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
@@ -390,22 +469,26 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
-golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
-golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
-golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
+golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
+golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
+golang.org/x/exp v0.0.0-20260611194520-c48552f49976 h1:X8Hz2ImujgbmetVuW+w2YkyZChE3cBpZi2P158rTG9M=
+golang.org/x/exp v0.0.0-20260611194520-c48552f49976/go.mod h1:vnf4pv9iKZXY58sQE1L86zmNWJ4159e1RkcWiLCkeEY=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
-golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
+golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
+golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
-golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -413,47 +496,63 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
-golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
-golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
-golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
+golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
+golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
-golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
+golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
-golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
+golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk=
+golang.org/x/tools v0.46.0/go.mod h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
-google.golang.org/api v0.272.0 h1:eLUQZGnAS3OHn31URRf9sAmRk3w2JjMx37d2k8AjJmA=
-google.golang.org/api v0.272.0/go.mod h1:wKjowi5LNJc5qarNvDCvNQBn3rVK8nSy6jg2SwRwzIA=
-google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA=
-google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
-google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
-google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
-google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
-google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+google.golang.org/api v0.278.0 h1:W7jiRvRi53VYFfZ/HoZjQBtJk7gOFbHD8ot1RzVZU6E=
+google.golang.org/api v0.278.0/go.mod h1:B9TqLBwJqVjp1mtt7WeoQwWRwvu/400y5lETOql+giQ=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto/googleapis/api v0.0.0-20260610212136-7ab31c22f7ad h1:3iLyITS/sySRwbUKoC7ogfj2Yr1Cjs0pfaRKj5U5HEw=
+google.golang.org/genproto/googleapis/api v0.0.0-20260610212136-7ab31c22f7ad/go.mod h1:KdNqO+rCIWgFumrNBSEDlDNrkrQnpkax7Tv1WxNY8V4=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad h1:45WmJvIV6C2+O/jjLkPUH+F3aOj/1miDoU2DD0+NWbg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
+google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
+google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
+google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -467,6 +566,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -474,31 +574,33 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
-k8s.io/api v0.35.4 h1:P7nFYKl5vo9AGUp1Z+Pmd3p2tA7bX2wbFWCvDeRv988=
-k8s.io/api v0.35.4/go.mod h1:yl4lqySWOgYJJf9RERXKUwE9g2y+CkuwG+xmcOK8wXU=
-k8s.io/apiextensions-apiserver v0.35.4 h1:HeP+Upp7ItdvnyGmub0yoix+2z5+ev4M5cE5TCgtOUU=
-k8s.io/apiextensions-apiserver v0.35.4/go.mod h1:ogQlk+stIE8mnoRthSYCwlOS12fVqgWFiErMwPaXA7c=
-k8s.io/apimachinery v0.35.4 h1:xtdom9RG7e+yDp71uoXoJDWEE2eOiHgeO4GdBzwWpds=
-k8s.io/apimachinery v0.35.4/go.mod h1:NNi1taPOpep0jOj+oRha3mBJPqvi0hGdaV8TCqGQ+cc=
-k8s.io/apiserver v0.35.4 h1:vtuFqNFmF9bPRdHDL2lpK6qCTPWDreZJL4LRPwVM6ho=
-k8s.io/apiserver v0.35.4/go.mod h1:JnBcb+J8kFXKpZkgcbcUnPBBHi4qgBii1I7dLxFY/oo=
-k8s.io/client-go v0.35.4 h1:DN6fyaGuzK64UvnKO5fOA6ymSjvfGAnCAHAR0C66kD8=
-k8s.io/client-go v0.35.4/go.mod h1:2Pg9WpsS4NeOpoYTfHHfMxBG8zFMSAUi4O/qoiJC3nY=
-k8s.io/component-base v0.35.4 h1:6n1tNJ87johN0Hif0Fs8K2GMthsaUwMqCebUDLYyv7U=
-k8s.io/component-base v0.35.4/go.mod h1:qaDJgz5c1KYKla9occFmlJEfPpkuA55s90G509R+PeY=
+k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY=
+k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg=
+k8s.io/apiextensions-apiserver v0.36.2 h1:3O5gqOj/dt2XWWbpMe+TXWpE9yU6pjM/tXxtHHJT/K4=
+k8s.io/apiextensions-apiserver v0.36.2/go.mod h1:cL1tBWe8XSaP1H30iWKGo7hf6iAUUUJPEU70dskmAnA=
+k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ=
+k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4=
+k8s.io/apiserver v0.36.2 h1:6vMnkmHZPeBloNkHUhmZYq7Ylv8WIB8xjyEl+eSt26E=
+k8s.io/apiserver v0.36.2/go.mod h1:9PoQ2ikCytrZyZg11mGhLEF5m8Rgsb5FJmYJ4Wvnl1k=
+k8s.io/client-go v0.36.2 h1:bfgxmFKc9CgqsgX4xKLAAdmTQlWee7Ob/HlDOrJ5TBI=
+k8s.io/client-go v0.36.2/go.mod h1:1vgO4OAlfPnoLcb+Rze2GF5rAr14w8qjrYMoyXJzQj0=
+k8s.io/component-base v0.36.2 h1:Z0VH80O7Ng0HDZnZj3WRR3urEGa0kTwmO8CwEwjVK1w=
+k8s.io/component-base v0.36.2/go.mod h1:mGfFOA7Gwpdm1VW2cwSQYbiDIlz8GD2WGwH88QSeCyA=
k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
-k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg=
-k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0=
-k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=
-k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
-sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80=
-sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
+k8s.io/kube-openapi v0.0.0-20260603220949-865597e52e25 h1:mPMaPMpBij2V1Wv/fR+HW124vVGXXvOSS9ver/9yjWs=
+k8s.io/kube-openapi v0.0.0-20260603220949-865597e52e25/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY=
+k8s.io/streaming v0.36.2 h1:NSKthPPg9UFSKsRauVJUVGH2Dvn8fhKmY4qrMkw/p98=
+k8s.io/streaming v0.36.2/go.mod h1:z6fV3D+NVkoeqRMtWwlUZK6U17SY/LqNzOxWL6GyR/s=
+k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 h1:wU4tMEhLGgIbLvXQb1cfN+EcM0wf7zC6CPF+C79jroc=
+k8s.io/utils v0.0.0-20260507154919-ff6756f316d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
+sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4=
+sigs.k8s.io/controller-runtime v0.24.1/go.mod h1:vFkfY5fGt5xAC/sKb8IBFKgWPNKG9OUG29dR8Y2wImw=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
-sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8=
-sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
+sigs.k8s.io/structured-merge-diff/v6 v6.4.0 h1:qmp2e3ZfFi1/jJbDGpD4mt3wyp6PE1NfKHCYLqgNQJo=
+sigs.k8s.io/structured-merge-diff/v6 v6.4.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
diff --git a/jsonnet/prometheus-operator/alertmanagerconfigs-crd.json b/jsonnet/prometheus-operator/alertmanagerconfigs-crd.json
index 56fc8b77898..475917fa915 100644
--- a/jsonnet/prometheus-operator/alertmanagerconfigs-crd.json
+++ b/jsonnet/prometheus-operator/alertmanagerconfigs-crd.json
@@ -3,8 +3,8 @@
"kind": "CustomResourceDefinition",
"metadata": {
"annotations": {
- "controller-gen.kubebuilder.io/version": "v0.20.1",
- "operator.prometheus.io/version": "0.91.0"
+ "controller-gen.kubebuilder.io/version": "v0.21.0",
+ "operator.prometheus.io/version": "0.92.1"
},
"name": "alertmanagerconfigs.monitoring.coreos.com"
},
@@ -705,7 +705,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -1687,7 +1687,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -2381,7 +2381,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -3142,7 +3142,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -3921,7 +3921,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -4702,7 +4702,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -5529,7 +5529,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -6422,7 +6422,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -7158,7 +7158,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -7959,7 +7959,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -8693,7 +8693,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -9377,7 +9377,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -10045,7 +10045,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -10270,6 +10270,11 @@
"minimum": 0,
"type": "integer"
},
+ "payload": {
+ "description": "payload define custom payload to be sent to the webhook endpoint.\nThis is an advanced configuration option that allows you\nto define a custom payload using Go templates.\nIt requires Alertmanager >= v0.32.0.",
+ "minLength": 1,
+ "type": "string"
+ },
"sendResolved": {
"description": "sendResolved defines whether or not to notify about resolved alerts.",
"type": "boolean"
@@ -10777,7 +10782,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
diff --git a/jsonnet/prometheus-operator/alertmanagerconfigs-v1beta1-crd.libsonnet b/jsonnet/prometheus-operator/alertmanagerconfigs-v1beta1-crd.libsonnet
index 2ad3eaafb6e..1de1d77cb19 100644
--- a/jsonnet/prometheus-operator/alertmanagerconfigs-v1beta1-crd.libsonnet
+++ b/jsonnet/prometheus-operator/alertmanagerconfigs-v1beta1-crd.libsonnet
@@ -563,7 +563,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -1533,7 +1533,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -2223,7 +2223,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -2976,7 +2976,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -3746,7 +3746,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -4517,7 +4517,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -5330,7 +5330,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -6216,7 +6216,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -6948,7 +6948,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -7742,7 +7742,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -8469,7 +8469,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -9149,7 +9149,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -9813,7 +9813,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
@@ -10038,6 +10038,11 @@
minimum: 0,
type: 'integer',
},
+ payload: {
+ description: 'payload define custom payload to be sent to the webhook endpoint.\nThis is an advanced configuration option that allows you\nto define a custom payload using Go templates.\nIt requires Alertmanager >= v0.32.0.',
+ minLength: 1,
+ type: 'string',
+ },
sendResolved: {
description: 'sendResolved defines whether or not to notify about resolved alerts.',
type: 'boolean',
@@ -10535,7 +10540,7 @@
},
tokenUrl: {
description: 'tokenUrl defines the URL to fetch the token from.',
- minLength: 1,
+ pattern: '^(http|https)://.+$',
type: 'string',
},
},
diff --git a/jsonnet/prometheus-operator/alertmanagers-crd.json b/jsonnet/prometheus-operator/alertmanagers-crd.json
index 1dc015a4cce..8505d14386b 100644
--- a/jsonnet/prometheus-operator/alertmanagers-crd.json
+++ b/jsonnet/prometheus-operator/alertmanagers-crd.json
@@ -3,8 +3,8 @@
"kind": "CustomResourceDefinition",
"metadata": {
"annotations": {
- "controller-gen.kubebuilder.io/version": "v0.20.1",
- "operator.prometheus.io/version": "0.91.0"
+ "controller-gen.kubebuilder.io/version": "v0.21.0",
+ "operator.prometheus.io/version": "0.92.1"
},
"name": "alertmanagers.monitoring.coreos.com"
},
@@ -1404,7 +1404,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -3601,7 +3601,7 @@
"type": "boolean"
},
"procMount": {
- "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\nNote that this field cannot be set when spec.os.name is windows.",
+ "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nNote that this field cannot be set when spec.os.name is windows.",
"type": "string"
},
"readOnlyRootFilesystem": {
@@ -5085,7 +5085,7 @@
"type": "boolean"
},
"procMount": {
- "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\nNote that this field cannot be set when spec.os.name is windows.",
+ "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nNote that this field cannot be set when spec.os.name is windows.",
"type": "string"
},
"readOnlyRootFilesystem": {
@@ -7266,7 +7266,7 @@
"type": "object"
},
"image": {
- "description": "image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine.\nThe volume is resolved at pod startup depending on which PullPolicy value is provided:\n\n- Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\n- Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\n- IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\n\nThe volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation.\nA failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.\nThe types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.\nThe OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.\nThe volume will be mounted read-only (ro) and non-executable files (noexec).\nSub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.\nThe field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.",
+ "description": "image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine.\nThe volume is resolved at pod startup depending on which PullPolicy value is provided:\n\n- Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\n- Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\n- IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\n\nThe volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation.\nA failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.\nThe types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.\nThe OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.\nThe volume will be mounted read-only (ro).\nSub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.\nThe field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.",
"properties": {
"pullPolicy": {
"description": "Policy for pulling OCI objects. Possible values are:\nAlways: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\nNever: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\nIfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\nDefaults to Always if :latest tag is specified, or IfNotPresent otherwise.",
@@ -7409,7 +7409,7 @@
"type": "object"
},
"portworxVolume": {
- "description": "portworxVolume represents a portworx volume attached and mounted on kubelets host machine.\nDeprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type\nare redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate\nis on.",
+ "description": "portworxVolume represents a portworx volume attached and mounted on kubelets host machine.\nDeprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type\nare redirected to the pxd.portworx.com CSI driver.",
"properties": {
"fsType": {
"description": "fSType represents the filesystem type to mount\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified.",
diff --git a/jsonnet/prometheus-operator/podmonitors-crd.json b/jsonnet/prometheus-operator/podmonitors-crd.json
index f52e8ab0606..c4b29f6db84 100644
--- a/jsonnet/prometheus-operator/podmonitors-crd.json
+++ b/jsonnet/prometheus-operator/podmonitors-crd.json
@@ -3,8 +3,8 @@
"kind": "CustomResourceDefinition",
"metadata": {
"annotations": {
- "controller-gen.kubebuilder.io/version": "v0.20.1",
- "operator.prometheus.io/version": "0.91.0"
+ "controller-gen.kubebuilder.io/version": "v0.21.0",
+ "operator.prometheus.io/version": "0.92.1"
},
"name": "podmonitors.monitoring.coreos.com"
},
@@ -48,7 +48,7 @@
"description": "attachMetadata defines additional metadata which is added to the\ndiscovered targets.\n\nIt requires Prometheus >= v2.35.0.",
"properties": {
"node": {
- "description": "node when set to true, Prometheus attaches node metadata to the discovered\ntargets.\n\nThe Prometheus service account must have the `list` and `watch`\npermissions on the `Nodes` objects.",
+ "description": "node when set to true, Prometheus attaches node metadata to the discovered\ntargets.\n\nThe Prometheus service account must have the `list` and `watch`\npermissions on the `Nodes` objects.\n\nNode metadata labels are not automatically added to scraped metrics. They are\nexposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries\nwith relabeling configuration.",
"type": "boolean"
}
},
@@ -642,7 +642,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
diff --git a/jsonnet/prometheus-operator/probes-crd.json b/jsonnet/prometheus-operator/probes-crd.json
index 8290a1d292d..296613e676d 100644
--- a/jsonnet/prometheus-operator/probes-crd.json
+++ b/jsonnet/prometheus-operator/probes-crd.json
@@ -3,8 +3,8 @@
"kind": "CustomResourceDefinition",
"metadata": {
"annotations": {
- "controller-gen.kubebuilder.io/version": "v0.20.1",
- "operator.prometheus.io/version": "0.91.0"
+ "controller-gen.kubebuilder.io/version": "v0.21.0",
+ "operator.prometheus.io/version": "0.92.1"
},
"name": "probes.monitoring.coreos.com"
},
@@ -593,7 +593,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
diff --git a/jsonnet/prometheus-operator/prometheusagents-crd.json b/jsonnet/prometheus-operator/prometheusagents-crd.json
index c1f0a249ae4..e4035bab8e9 100644
--- a/jsonnet/prometheus-operator/prometheusagents-crd.json
+++ b/jsonnet/prometheus-operator/prometheusagents-crd.json
@@ -3,8 +3,8 @@
"kind": "CustomResourceDefinition",
"metadata": {
"annotations": {
- "controller-gen.kubebuilder.io/version": "v0.20.1",
- "operator.prometheus.io/version": "0.91.0"
+ "controller-gen.kubebuilder.io/version": "v0.21.0",
+ "operator.prometheus.io/version": "0.92.1"
},
"name": "prometheusagents.monitoring.coreos.com"
},
@@ -2238,7 +2238,7 @@
"type": "boolean"
},
"procMount": {
- "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\nNote that this field cannot be set when spec.os.name is windows.",
+ "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nNote that this field cannot be set when spec.os.name is windows.",
"type": "string"
},
"readOnlyRootFilesystem": {
@@ -3824,7 +3824,7 @@
"type": "boolean"
},
"procMount": {
- "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\nNote that this field cannot be set when spec.os.name is windows.",
+ "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nNote that this field cannot be set when spec.os.name is windows.",
"type": "string"
},
"readOnlyRootFilesystem": {
@@ -4273,6 +4273,14 @@
"description": "keepIdentifyingResourceAttributes enables adding `service.name`, `service.namespace` and `service.instance.id`\nresource attributes to the `target_info` metric, on top of converting them into the `instance` and `job` labels.\n\nIt requires Prometheus >= v3.1.0.",
"type": "boolean"
},
+ "labelNamePreserveMultipleUnderscores": {
+ "description": "labelNamePreserveMultipleUnderscores enables preserving of multiple consecutive underscores in label names when translation_strategy uses\nunderscore escaping.\nWhen true (default), multiple consecutive underscores are preserved during label name sanitization.\n\nNotice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.\n\nIt requires Prometheus >= v3.8.0.",
+ "type": "boolean"
+ },
+ "labelNameUnderscoreSanitization": {
+ "description": "labelNameUnderscoreSanitization controls whether to enable prepending of 'key_' to labels starting with '_'.\nReserved labels starting with '__' are not modified.\nThis is only relevant when translation_strategy uses underscore escaping (e.g., \"UnderscoreEscapingWithSuffixes\" or \"UnderscoreEscapingWithoutSuffixes\").\n\nNotice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.\n\nIt requires Prometheus >= v3.8.0.",
+ "type": "boolean"
+ },
"promoteAllResourceAttributes": {
"description": "promoteAllResourceAttributes promotes all resource attributes to metric labels except the ones defined in `ignoreResourceAttributes`.\n\nCannot be true when `promoteResourceAttributes` is defined.\nIt requires Prometheus >= v3.5.0.",
"type": "boolean"
@@ -5130,7 +5138,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -5700,7 +5708,7 @@
"description": "attachMetadata defines additional metadata to the discovered targets.\nWhen the scrape object defines its own configuration, it takes\nprecedence over the scrape class configuration.",
"properties": {
"node": {
- "description": "node when set to true, Prometheus attaches node metadata to the discovered\ntargets.\n\nThe Prometheus service account must have the `list` and `watch`\npermissions on the `Nodes` objects.",
+ "description": "node when set to true, Prometheus attaches node metadata to the discovered\ntargets.\n\nThe Prometheus service account must have the `list` and `watch`\npermissions on the `Nodes` objects.\n\nNode metadata labels are not automatically added to scraped metrics. They are\nexposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries\nwith relabeling configuration.",
"type": "boolean"
}
},
@@ -7441,6 +7449,19 @@
"description": "outOfOrderTimeWindow defines how old an out-of-order/out-of-bounds sample can be with\nrespect to the TSDB max time.\n\nAn out-of-order/out-of-bounds sample is ingested into the TSDB as long as\nthe timestamp of the sample is >= (TSDB.MaxTime - outOfOrderTimeWindow).\n\nThis is an *experimental feature*, it may change in any upcoming release\nin a breaking way.\n\nIt requires Prometheus >= v2.39.0 or PrometheusAgent >= v2.54.0.",
"pattern": "^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$",
"type": "string"
+ },
+ "staleSeriesCompactionThreshold": {
+ "anyOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "type": "string"
+ }
+ ],
+ "description": "staleSeriesCompactionThreshold configures the trigger point for compacting\nstale series from memory into persistent blocks and removing those stale\nseries from memory.\n\nThe threshold is a number between 0.0 and 1.0. It represents the ratio of\nstale series in memory to the total series in memory. The stale series\ncompaction is triggered when this ratio crosses the configured threshold.\nIt may not trigger the stale series compaction if the usual head compaction\nis about to happen soon.\n\nIf set to 0, stale series compaction is disabled.\n\nIt requires Prometheus >= v3.10.0.",
+ "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+ "x-kubernetes-int-or-string": true
}
},
"type": "object"
@@ -8251,7 +8272,7 @@
"type": "object"
},
"image": {
- "description": "image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine.\nThe volume is resolved at pod startup depending on which PullPolicy value is provided:\n\n- Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\n- Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\n- IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\n\nThe volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation.\nA failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.\nThe types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.\nThe OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.\nThe volume will be mounted read-only (ro) and non-executable files (noexec).\nSub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.\nThe field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.",
+ "description": "image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine.\nThe volume is resolved at pod startup depending on which PullPolicy value is provided:\n\n- Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\n- Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\n- IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\n\nThe volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation.\nA failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.\nThe types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.\nThe OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.\nThe volume will be mounted read-only (ro).\nSub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.\nThe field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.",
"properties": {
"pullPolicy": {
"description": "Policy for pulling OCI objects. Possible values are:\nAlways: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\nNever: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\nIfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\nDefaults to Always if :latest tag is specified, or IfNotPresent otherwise.",
@@ -8394,7 +8415,7 @@
"type": "object"
},
"portworxVolume": {
- "description": "portworxVolume represents a portworx volume attached and mounted on kubelets host machine.\nDeprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type\nare redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate\nis on.",
+ "description": "portworxVolume represents a portworx volume attached and mounted on kubelets host machine.\nDeprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type\nare redirected to the pxd.portworx.com CSI driver.",
"properties": {
"fsType": {
"description": "fSType represents the filesystem type to mount\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified.",
diff --git a/jsonnet/prometheus-operator/prometheuses-crd.json b/jsonnet/prometheus-operator/prometheuses-crd.json
index b43f28d9c74..f9ac5ec33b5 100644
--- a/jsonnet/prometheus-operator/prometheuses-crd.json
+++ b/jsonnet/prometheus-operator/prometheuses-crd.json
@@ -3,8 +3,8 @@
"kind": "CustomResourceDefinition",
"metadata": {
"annotations": {
- "controller-gen.kubebuilder.io/version": "v0.20.1",
- "operator.prometheus.io/version": "0.91.0"
+ "controller-gen.kubebuilder.io/version": "v0.21.0",
+ "operator.prometheus.io/version": "0.92.1"
},
"name": "prometheuses.monitoring.coreos.com"
},
@@ -2892,7 +2892,7 @@
"type": "boolean"
},
"procMount": {
- "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\nNote that this field cannot be set when spec.os.name is windows.",
+ "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nNote that this field cannot be set when spec.os.name is windows.",
"type": "string"
},
"readOnlyRootFilesystem": {
@@ -4503,7 +4503,7 @@
"type": "boolean"
},
"procMount": {
- "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\nNote that this field cannot be set when spec.os.name is windows.",
+ "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nNote that this field cannot be set when spec.os.name is windows.",
"type": "string"
},
"readOnlyRootFilesystem": {
@@ -4944,6 +4944,14 @@
"description": "keepIdentifyingResourceAttributes enables adding `service.name`, `service.namespace` and `service.instance.id`\nresource attributes to the `target_info` metric, on top of converting them into the `instance` and `job` labels.\n\nIt requires Prometheus >= v3.1.0.",
"type": "boolean"
},
+ "labelNamePreserveMultipleUnderscores": {
+ "description": "labelNamePreserveMultipleUnderscores enables preserving of multiple consecutive underscores in label names when translation_strategy uses\nunderscore escaping.\nWhen true (default), multiple consecutive underscores are preserved during label name sanitization.\n\nNotice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.\n\nIt requires Prometheus >= v3.8.0.",
+ "type": "boolean"
+ },
+ "labelNameUnderscoreSanitization": {
+ "description": "labelNameUnderscoreSanitization controls whether to enable prepending of 'key_' to labels starting with '_'.\nReserved labels starting with '__' are not modified.\nThis is only relevant when translation_strategy uses underscore escaping (e.g., \"UnderscoreEscapingWithSuffixes\" or \"UnderscoreEscapingWithoutSuffixes\").\n\nNotice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.\n\nIt requires Prometheus >= v3.8.0.",
+ "type": "boolean"
+ },
"promoteAllResourceAttributes": {
"description": "promoteAllResourceAttributes promotes all resource attributes to metric labels except the ones defined in `ignoreResourceAttributes`.\n\nCannot be true when `promoteResourceAttributes` is defined.\nIt requires Prometheus >= v3.5.0.",
"type": "boolean"
@@ -5717,7 +5725,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -5958,7 +5966,8 @@
"type": "object"
},
"url": {
- "description": "url defines the URL of the endpoint to query from.",
+ "description": "url defines the URL of the endpoint to query from.\n\nIt must use the HTTP or HTTPS scheme.",
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -6529,7 +6538,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -7228,7 +7237,7 @@
"description": "attachMetadata defines additional metadata to the discovered targets.\nWhen the scrape object defines its own configuration, it takes\nprecedence over the scrape class configuration.",
"properties": {
"node": {
- "description": "node when set to true, Prometheus attaches node metadata to the discovered\ntargets.\n\nThe Prometheus service account must have the `list` and `watch`\npermissions on the `Nodes` objects.",
+ "description": "node when set to true, Prometheus attaches node metadata to the discovered\ntargets.\n\nThe Prometheus service account must have the `list` and `watch`\npermissions on the `Nodes` objects.\n\nNode metadata labels are not automatically added to scraped metrics. They are\nexposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries\nwith relabeling configuration.",
"type": "boolean"
}
},
@@ -8009,7 +8018,7 @@
"type": "string"
},
"shardRetentionPolicy": {
- "description": "shardRetentionPolicy defines the retention policy for the Prometheus shards.\n(Alpha) Using this field requires the 'PrometheusShardRetentionPolicy' feature gate to be enabled.\n\nThe final goals for this feature can be seen at https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/proposals/202310-shard-autoscaling.md#graceful-scale-down-of-prometheus-servers,\nhowever, the feature is not yet fully implemented in this PR. The limitation being:\n* Retention duration is not settable, for now, shards are retained forever.",
+ "description": "shardRetentionPolicy defines the retention policy for the Prometheus shards.\n\n(Beta) Using this mode requires the `PrometheusShardRetentionPolicy` feature gate (enabled by default).",
"properties": {
"retain": {
"description": "retain defines the config for retention when the retention policy is set\nto `Retain`.\n\nIf not defined, the operator will use the retention duration configured\nfor the Prometheus data. If the resource uses size-based retention, the\nshard(s) are kept forever (unless manually deleted).",
@@ -9460,6 +9469,19 @@
"description": "outOfOrderTimeWindow defines how old an out-of-order/out-of-bounds sample can be with\nrespect to the TSDB max time.\n\nAn out-of-order/out-of-bounds sample is ingested into the TSDB as long as\nthe timestamp of the sample is >= (TSDB.MaxTime - outOfOrderTimeWindow).\n\nThis is an *experimental feature*, it may change in any upcoming release\nin a breaking way.\n\nIt requires Prometheus >= v2.39.0 or PrometheusAgent >= v2.54.0.",
"pattern": "^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$",
"type": "string"
+ },
+ "staleSeriesCompactionThreshold": {
+ "anyOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "type": "string"
+ }
+ ],
+ "description": "staleSeriesCompactionThreshold configures the trigger point for compacting\nstale series from memory into persistent blocks and removing those stale\nseries from memory.\n\nThe threshold is a number between 0.0 and 1.0. It represents the ratio of\nstale series in memory to the total series in memory. The stale series\ncompaction is triggered when this ratio crosses the configured threshold.\nIt may not trigger the stale series compaction if the usual head compaction\nis about to happen soon.\n\nIf set to 0, stale series compaction is disabled.\n\nIt requires Prometheus >= v3.10.0.",
+ "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+ "x-kubernetes-int-or-string": true
}
},
"type": "object"
@@ -10270,7 +10292,7 @@
"type": "object"
},
"image": {
- "description": "image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine.\nThe volume is resolved at pod startup depending on which PullPolicy value is provided:\n\n- Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\n- Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\n- IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\n\nThe volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation.\nA failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.\nThe types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.\nThe OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.\nThe volume will be mounted read-only (ro) and non-executable files (noexec).\nSub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.\nThe field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.",
+ "description": "image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine.\nThe volume is resolved at pod startup depending on which PullPolicy value is provided:\n\n- Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\n- Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\n- IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\n\nThe volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation.\nA failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.\nThe types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.\nThe OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.\nThe volume will be mounted read-only (ro).\nSub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.\nThe field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.",
"properties": {
"pullPolicy": {
"description": "Policy for pulling OCI objects. Possible values are:\nAlways: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\nNever: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\nIfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\nDefaults to Always if :latest tag is specified, or IfNotPresent otherwise.",
@@ -10413,7 +10435,7 @@
"type": "object"
},
"portworxVolume": {
- "description": "portworxVolume represents a portworx volume attached and mounted on kubelets host machine.\nDeprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type\nare redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate\nis on.",
+ "description": "portworxVolume represents a portworx volume attached and mounted on kubelets host machine.\nDeprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type\nare redirected to the pxd.portworx.com CSI driver.",
"properties": {
"fsType": {
"description": "fSType represents the filesystem type to mount\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified.",
diff --git a/jsonnet/prometheus-operator/prometheusrules-crd.json b/jsonnet/prometheus-operator/prometheusrules-crd.json
index 3e030089fa8..9574ec98bbf 100644
--- a/jsonnet/prometheus-operator/prometheusrules-crd.json
+++ b/jsonnet/prometheus-operator/prometheusrules-crd.json
@@ -3,8 +3,8 @@
"kind": "CustomResourceDefinition",
"metadata": {
"annotations": {
- "controller-gen.kubebuilder.io/version": "v0.20.1",
- "operator.prometheus.io/version": "0.91.0"
+ "controller-gen.kubebuilder.io/version": "v0.21.0",
+ "operator.prometheus.io/version": "0.92.1"
},
"name": "prometheusrules.monitoring.coreos.com"
},
diff --git a/jsonnet/prometheus-operator/scrapeconfigs-crd.json b/jsonnet/prometheus-operator/scrapeconfigs-crd.json
index ffa25cf6764..90c1f959287 100644
--- a/jsonnet/prometheus-operator/scrapeconfigs-crd.json
+++ b/jsonnet/prometheus-operator/scrapeconfigs-crd.json
@@ -3,8 +3,8 @@
"kind": "CustomResourceDefinition",
"metadata": {
"annotations": {
- "controller-gen.kubebuilder.io/version": "v0.20.1",
- "operator.prometheus.io/version": "0.91.0"
+ "controller-gen.kubebuilder.io/version": "v0.21.0",
+ "operator.prometheus.io/version": "0.92.1"
},
"name": "scrapeconfigs.monitoring.coreos.com"
},
@@ -521,7 +521,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -1258,7 +1258,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -1905,7 +1905,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -2628,7 +2628,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -3299,7 +3299,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -4274,7 +4274,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -4996,7 +4996,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -5647,7 +5647,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -6231,7 +6231,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -6908,7 +6908,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -7590,7 +7590,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -8264,7 +8264,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -8875,7 +8875,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -9638,7 +9638,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -10177,7 +10177,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -11037,7 +11037,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
diff --git a/jsonnet/prometheus-operator/servicemonitors-crd.json b/jsonnet/prometheus-operator/servicemonitors-crd.json
index 60e7de8f285..7636d04a5f2 100644
--- a/jsonnet/prometheus-operator/servicemonitors-crd.json
+++ b/jsonnet/prometheus-operator/servicemonitors-crd.json
@@ -3,8 +3,8 @@
"kind": "CustomResourceDefinition",
"metadata": {
"annotations": {
- "controller-gen.kubebuilder.io/version": "v0.20.1",
- "operator.prometheus.io/version": "0.91.0"
+ "controller-gen.kubebuilder.io/version": "v0.21.0",
+ "operator.prometheus.io/version": "0.92.1"
},
"name": "servicemonitors.monitoring.coreos.com"
},
@@ -48,7 +48,7 @@
"description": "attachMetadata defines additional metadata which is added to the\ndiscovered targets.\n\nIt requires Prometheus >= v2.37.0.",
"properties": {
"node": {
- "description": "node when set to true, Prometheus attaches node metadata to the discovered\ntargets.\n\nThe Prometheus service account must have the `list` and `watch`\npermissions on the `Nodes` objects.",
+ "description": "node when set to true, Prometheus attaches node metadata to the discovered\ntargets.\n\nThe Prometheus service account must have the `list` and `watch`\npermissions on the `Nodes` objects.\n\nNode metadata labels are not automatically added to scraped metrics. They are\nexposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries\nwith relabeling configuration.",
"type": "boolean"
}
},
@@ -576,7 +576,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -602,7 +602,7 @@
"type": "string"
},
"port": {
- "description": "port defines the name of the Service port which this endpoint refers to.\n\nIt takes precedence over `targetPort`.",
+ "description": "port defines the name of the Service port which this endpoint refers to\n(e.g. `.spec.ports[].name`).\n\nIt takes precedence over `targetPort`.",
"type": "string"
},
"proxyConnectHeader": {
@@ -737,7 +737,7 @@
"type": "string"
}
],
- "description": "targetPort defines the name or number of the target port of the `Pod` object behind the\nService. The port must be specified with the container's port property.",
+ "description": "targetPort defines the name or number of a container port on Pods selected\nby the Service.\nIf a name, it matches against `.spec.containers[].ports[].name` of the Pods.\nIf a number, it matches against `.spec.containers[].ports[].containerPort` of the Pods.",
"x-kubernetes-int-or-string": true
},
"tlsConfig": {
diff --git a/jsonnet/prometheus-operator/thanosrulers-crd.json b/jsonnet/prometheus-operator/thanosrulers-crd.json
index 75703f03eb8..b411c100c86 100644
--- a/jsonnet/prometheus-operator/thanosrulers-crd.json
+++ b/jsonnet/prometheus-operator/thanosrulers-crd.json
@@ -3,8 +3,8 @@
"kind": "CustomResourceDefinition",
"metadata": {
"annotations": {
- "controller-gen.kubebuilder.io/version": "v0.20.1",
- "operator.prometheus.io/version": "0.91.0"
+ "controller-gen.kubebuilder.io/version": "v0.21.0",
+ "operator.prometheus.io/version": "0.92.1"
},
"name": "thanosrulers.monitoring.coreos.com"
},
@@ -1930,7 +1930,7 @@
"type": "boolean"
},
"procMount": {
- "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\nNote that this field cannot be set when spec.os.name is windows.",
+ "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nNote that this field cannot be set when spec.os.name is windows.",
"type": "string"
},
"readOnlyRootFilesystem": {
@@ -3651,7 +3651,7 @@
"type": "boolean"
},
"procMount": {
- "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\nNote that this field cannot be set when spec.os.name is windows.",
+ "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nNote that this field cannot be set when spec.os.name is windows.",
"type": "string"
},
"readOnlyRootFilesystem": {
@@ -4718,7 +4718,7 @@
},
"tokenUrl": {
"description": "tokenUrl defines the URL to fetch the token from.",
- "minLength": 1,
+ "pattern": "^(http|https)://.+$",
"type": "string"
}
},
@@ -7026,7 +7026,7 @@
"type": "object"
},
"image": {
- "description": "image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine.\nThe volume is resolved at pod startup depending on which PullPolicy value is provided:\n\n- Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\n- Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\n- IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\n\nThe volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation.\nA failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.\nThe types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.\nThe OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.\nThe volume will be mounted read-only (ro) and non-executable files (noexec).\nSub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.\nThe field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.",
+ "description": "image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine.\nThe volume is resolved at pod startup depending on which PullPolicy value is provided:\n\n- Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\n- Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\n- IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\n\nThe volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation.\nA failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.\nThe types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.\nThe OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.\nThe volume will be mounted read-only (ro).\nSub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.\nThe field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.",
"properties": {
"pullPolicy": {
"description": "Policy for pulling OCI objects. Possible values are:\nAlways: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\nNever: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\nIfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\nDefaults to Always if :latest tag is specified, or IfNotPresent otherwise.",
@@ -7169,7 +7169,7 @@
"type": "object"
},
"portworxVolume": {
- "description": "portworxVolume represents a portworx volume attached and mounted on kubelets host machine.\nDeprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type\nare redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate\nis on.",
+ "description": "portworxVolume represents a portworx volume attached and mounted on kubelets host machine.\nDeprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type\nare redirected to the pxd.portworx.com CSI driver.",
"properties": {
"fsType": {
"description": "fSType represents the filesystem type to mount\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified.",
diff --git a/pkg/admission/admission.go b/pkg/admission/admission.go
index 009f35f7ebc..d178d86ef79 100644
--- a/pkg/admission/admission.go
+++ b/pkg/admission/admission.go
@@ -180,13 +180,14 @@ func (a *Admission) serveAdmission(w http.ResponseWriter, r *http.Request, admit
responseAdmissionReview.Kind = requestedAdmissionReview.Kind
respBytes, err := json.Marshal(responseAdmissionReview)
-
- a.logger.Debug("sending response", "content", string(respBytes))
-
if err != nil {
a.logger.Error("Cannot serialize response", "err", err)
http.Error(w, fmt.Sprintf("could not serialize response: %v", err), http.StatusInternalServerError)
+ return
}
+
+ a.logger.Debug("sending response", "content", string(respBytes))
+
if _, err := w.Write(respBytes); err != nil {
a.logger.Error("Cannot write response", "err", err)
http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
diff --git a/pkg/alertmanager/amcfg.go b/pkg/alertmanager/amcfg.go
index bce9358e84f..3b84ae5e272 100644
--- a/pkg/alertmanager/amcfg.go
+++ b/pkg/alertmanager/amcfg.go
@@ -919,6 +919,10 @@ func (cb *ConfigBuilder) convertWebhookConfig(ctx context.Context, in monitoring
}
}
+ if in.Payload != nil {
+ out.Payload = *in.Payload
+ }
+
return out, nil
}
@@ -1299,7 +1303,12 @@ func (cb *ConfigBuilder) convertEmailConfig(ctx context.Context, in monitoringv1
}
if ptr.Deref(in.Smarthost, "") != "" {
- out.Smarthost.Host, out.Smarthost.Port, _ = net.SplitHostPort(*in.Smarthost)
+ host, port, err := net.SplitHostPort(*in.Smarthost)
+ if err != nil {
+ return nil, fmt.Errorf("invalid SMTP smarthost %q: %w", *in.Smarthost, err)
+ }
+ out.Smarthost.Host = host
+ out.Smarthost.Port = port
}
if in.AuthPassword != nil {
@@ -1332,7 +1341,7 @@ func (cb *ConfigBuilder) convertEmailConfig(ctx context.Context, in monitoringv1
if t := in.Threading; t != nil {
out.Threading = &emailThreadingConfig{
- Enabled: ptr.To(true),
+ Enabled: new(true),
}
switch t.ThreadByDate {
case "Daily":
@@ -1901,7 +1910,7 @@ func (cb *ConfigBuilder) convertHTTPConfig(ctx context.Context, in *monitoringv1
ClientID: clientID,
ClientSecret: clientSecret,
Scopes: in.OAuth2.Scopes,
- TokenURL: in.OAuth2.TokenURL,
+ TokenURL: string(in.OAuth2.TokenURL),
EndpointParams: in.OAuth2.EndpointParams,
proxyConfig: proxyConfig,
}
@@ -2888,10 +2897,16 @@ func (sc *slackConfig) sanitize(amVersion semver.Version, logger *slog.Logger) e
sc.MessageText = ""
}
- if sc.UpdateMessage != nil && lessThanV0_32 {
- msg := "'update_message' supported in Alertmanager >= 0.32.0 only - dropping field from provided config"
- logger.Warn(msg)
- sc.UpdateMessage = nil
+ if sc.UpdateMessage != nil {
+ if lessThanV0_32 {
+ msg := "'update_message' supported in Alertmanager >= 0.32.0 only - dropping field from provided config"
+ logger.Warn(msg)
+ sc.UpdateMessage = nil
+ } else if *sc.UpdateMessage && sc.APIURL != "" {
+ if sc.APIURL != "https://slack.com/api/chat.postMessage" {
+ return fmt.Errorf(`update_message' can only be used with bot tokens. api_url must be set to https://slack.com/api/chat.postMessage`)
+ }
+ }
}
if sc.AppToken != "" && sc.AppTokenFile != "" {
@@ -2974,7 +2989,7 @@ func (whc *webhookConfig) sanitize(amVersion semver.Version, logger *slog.Logger
whc.Timeout = nil
}
- if len(whc.Payload) != 0 && amVersion.LT(semver.MustParse("0.32.0")) {
+ if whc.Payload != nil && amVersion.LT(semver.MustParse("0.32.0")) {
msg := "'payload' supported in Alertmanager >= 0.32.0 only - dropping field from provided config"
logger.Warn(msg, "current_version", amVersion.String())
whc.Payload = nil
diff --git a/pkg/alertmanager/amcfg_test.go b/pkg/alertmanager/amcfg_test.go
index a9a1e1a6fe0..aad763b923e 100644
--- a/pkg/alertmanager/amcfg_test.go
+++ b/pkg/alertmanager/amcfg_test.go
@@ -125,29 +125,29 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
SMTPConfig: &monitoringv1.GlobalSMTPConfig{
- From: ptr.To("from"),
+ From: new("from"),
SmartHost: &monitoringv1.HostPort{
Host: "smtp.example.org",
Port: "587",
},
- Hello: ptr.To("smtp.example.org"),
- AuthUsername: ptr.To("dev@smtp.example.org"),
+ Hello: new("smtp.example.org"),
+ AuthUsername: new("dev@smtp.example.org"),
AuthPassword: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "smtp-auth",
},
Key: "password",
},
- AuthIdentity: ptr.To("dev@smtp.example.org"),
+ AuthIdentity: new("dev@smtp.example.org"),
AuthSecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "smtp-auth",
},
Key: "secret",
},
- RequireTLS: ptr.To(true),
+ RequireTLS: new(true),
TLSConfig: &monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
MinVersion: ptr.To(monitoringv1.TLSVersion12),
MaxVersion: ptr.To(monitoringv1.TLSVersion13),
},
@@ -177,7 +177,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
"some": "value",
},
},
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -218,7 +218,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
HTTPConfigWithProxy: &monitoringv1.HTTPConfigWithProxy{
HTTPConfig: monitoringv1.HTTPConfig{
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
TLSConfig: &monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
@@ -562,7 +562,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
{
name: "valid global config with Pagerduty URL",
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
- PagerdutyURL: ptr.To(monitoringv1.URL(pagerdutyURL)),
+ PagerdutyURL: new(monitoringv1.URL(pagerdutyURL)),
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
ObjectMeta: metav1.ObjectMeta{
@@ -596,7 +596,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
{
name: "global config with invalid Pagerduty URL",
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
- PagerdutyURL: ptr.To(monitoringv1.URL(invalidPagerdutyURL)),
+ PagerdutyURL: new(monitoringv1.URL(invalidPagerdutyURL)),
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
ObjectMeta: metav1.ObjectMeta{
@@ -640,7 +640,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
HTTPConfigWithProxy: &monitoringv1.HTTPConfigWithProxy{
HTTPConfig: monitoringv1.HTTPConfig{
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -672,12 +672,12 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
HTTPConfigWithProxy: &monitoringv1.HTTPConfigWithProxy{
HTTPConfig: monitoringv1.HTTPConfig{
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://example.com"),
- NoProxy: ptr.To("svc.cluster.local"),
+ ProxyURL: new("http://example.com"),
+ NoProxy: new("svc.cluster.local"),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -718,8 +718,8 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
HTTPConfigWithProxy: &monitoringv1.HTTPConfigWithProxy{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://example.com"),
- NoProxy: ptr.To("svc.cluster.local"),
+ ProxyURL: new("http://example.com"),
+ NoProxy: new("svc.cluster.local"),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -733,7 +733,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
},
HTTPConfig: monitoringv1.HTTPConfig{
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -765,8 +765,8 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
HTTPConfigWithProxy: &monitoringv1.HTTPConfigWithProxy{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://example.com"),
- NoProxy: ptr.To("svc.cluster.local"),
+ ProxyURL: new("http://example.com"),
+ NoProxy: new("svc.cluster.local"),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -780,7 +780,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
},
HTTPConfig: monitoringv1.HTTPConfig{
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -839,29 +839,29 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
SMTPConfig: &monitoringv1.GlobalSMTPConfig{
- From: ptr.To("from"),
+ From: new("from"),
SmartHost: &monitoringv1.HostPort{
Host: "smtp.example.org",
Port: "587",
},
- Hello: ptr.To("smtp.example.org"),
- AuthUsername: ptr.To("dev@smtp.example.org"),
+ Hello: new("smtp.example.org"),
+ AuthUsername: new("dev@smtp.example.org"),
AuthPassword: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "smtp-auth",
},
Key: "password",
},
- AuthIdentity: ptr.To("dev@smtp.example.org"),
+ AuthIdentity: new("dev@smtp.example.org"),
AuthSecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "smtp-auth",
},
Key: "secret",
},
- RequireTLS: ptr.To(true),
+ RequireTLS: new(true),
TLSConfig: &monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
MinVersion: ptr.To(monitoringv1.TLSVersion12),
MaxVersion: ptr.To(monitoringv1.TLSVersion13),
},
@@ -881,11 +881,11 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
Name: "myreceiver",
EmailConfigs: []monitoringv1alpha1.EmailConfig{
{
- SendResolved: ptr.To(true),
- Smarthost: ptr.To("abc:1234"),
- From: ptr.To("a"),
- To: ptr.To("b"),
- AuthUsername: ptr.To("foo"),
+ SendResolved: new(true),
+ Smarthost: new("abc:1234"),
+ From: new("a"),
+ To: new("b"),
+ AuthUsername: new("foo"),
},
},
},
@@ -910,29 +910,29 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version21,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
SMTPConfig: &monitoringv1.GlobalSMTPConfig{
- From: ptr.To("from"),
+ From: new("from"),
SmartHost: &monitoringv1.HostPort{
Host: "smtp.example.org",
Port: "587",
},
- Hello: ptr.To("smtp.example.org"),
- AuthUsername: ptr.To("dev@smtp.example.org"),
+ Hello: new("smtp.example.org"),
+ AuthUsername: new("dev@smtp.example.org"),
AuthPassword: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "smtp-auth",
},
Key: "password",
},
- AuthIdentity: ptr.To("dev@smtp.example.org"),
+ AuthIdentity: new("dev@smtp.example.org"),
AuthSecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "smtp-auth",
},
Key: "secret",
},
- RequireTLS: ptr.To(true),
+ RequireTLS: new(true),
TLSConfig: &monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
MinVersion: ptr.To(monitoringv1.TLSVersion12),
MaxVersion: ptr.To(monitoringv1.TLSVersion13),
},
@@ -962,7 +962,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
"some": "value",
},
},
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -1001,7 +1001,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version31,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
SMTPConfig: &monitoringv1.GlobalSMTPConfig{
- ForceImplicitTLS: ptr.To(true),
+ ForceImplicitTLS: new(true),
},
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
@@ -1038,7 +1038,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
SMTPConfig: &monitoringv1.GlobalSMTPConfig{
- ForceImplicitTLS: ptr.To(true),
+ ForceImplicitTLS: new(true),
},
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
@@ -1075,7 +1075,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
TelegramConfig: &monitoringv1.GlobalTelegramConfig{
- APIURL: ptr.To(monitoringv1.URL(telegramAPIURL)),
+ APIURL: new(monitoringv1.URL(telegramAPIURL)),
},
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
@@ -1112,7 +1112,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
TelegramConfig: &monitoringv1.GlobalTelegramConfig{
- APIURL: ptr.To(monitoringv1.URL(invalidTelegramAPIURL)),
+ APIURL: new(monitoringv1.URL(invalidTelegramAPIURL)),
},
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
@@ -1149,7 +1149,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version21,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
TelegramConfig: &monitoringv1.GlobalTelegramConfig{
- APIURL: ptr.To(monitoringv1.URL(telegramAPIURL)),
+ APIURL: new(monitoringv1.URL(telegramAPIURL)),
},
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
@@ -1186,7 +1186,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
JiraConfig: &monitoringv1.GlobalJiraConfig{
- APIURL: ptr.To(monitoringv1.URL(jiraAPIURL)),
+ APIURL: new(monitoringv1.URL(jiraAPIURL)),
},
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
@@ -1223,7 +1223,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
JiraConfig: &monitoringv1.GlobalJiraConfig{
- APIURL: ptr.To(monitoringv1.URL(invalidJiraAPIURL)),
+ APIURL: new(monitoringv1.URL(invalidJiraAPIURL)),
},
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
@@ -1260,7 +1260,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version26,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
JiraConfig: &monitoringv1.GlobalJiraConfig{
- APIURL: ptr.To(monitoringv1.URL(jiraAPIURL)),
+ APIURL: new(monitoringv1.URL(jiraAPIURL)),
},
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
@@ -1297,7 +1297,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
RocketChatConfig: &monitoringv1.GlobalRocketChatConfig{
- APIURL: ptr.To(monitoringv1.URL(rocketChatAPIURL)),
+ APIURL: new(monitoringv1.URL(rocketChatAPIURL)),
Token: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "rocketchat",
@@ -1346,7 +1346,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
RocketChatConfig: &monitoringv1.GlobalRocketChatConfig{
- APIURL: ptr.To(monitoringv1.URL(invalidRocketChatAPIURL)),
+ APIURL: new(monitoringv1.URL(invalidRocketChatAPIURL)),
Token: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "rocketchat",
@@ -1395,7 +1395,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
RocketChatConfig: &monitoringv1.GlobalRocketChatConfig{
- APIURL: ptr.To(monitoringv1.URL(rocketChatAPIURL)),
+ APIURL: new(monitoringv1.URL(rocketChatAPIURL)),
Token: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "rocketchat-missing",
@@ -1444,7 +1444,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
RocketChatConfig: &monitoringv1.GlobalRocketChatConfig{
- APIURL: ptr.To(monitoringv1.URL(rocketChatAPIURL)),
+ APIURL: new(monitoringv1.URL(rocketChatAPIURL)),
Token: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "rocketchat",
@@ -1493,7 +1493,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version26,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
RocketChatConfig: &monitoringv1.GlobalRocketChatConfig{
- APIURL: ptr.To(monitoringv1.URL(rocketChatAPIURL)),
+ APIURL: new(monitoringv1.URL(rocketChatAPIURL)),
Token: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "rocketchat",
@@ -1542,7 +1542,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
WebexConfig: &monitoringv1.GlobalWebexConfig{
- APIURL: ptr.To(monitoringv1.URL(webexAPIURL)),
+ APIURL: new(monitoringv1.URL(webexAPIURL)),
},
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
@@ -1579,7 +1579,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
WebexConfig: &monitoringv1.GlobalWebexConfig{
- APIURL: ptr.To(monitoringv1.URL(invalidWebexAPIURL)),
+ APIURL: new(monitoringv1.URL(invalidWebexAPIURL)),
},
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
@@ -1616,7 +1616,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version24,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
WebexConfig: &monitoringv1.GlobalWebexConfig{
- APIURL: ptr.To(monitoringv1.URL(webexAPIURL)),
+ APIURL: new(monitoringv1.URL(webexAPIURL)),
},
},
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
@@ -1653,7 +1653,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
WeChatConfig: &monitoringv1.GlobalWeChatConfig{
- APIURL: ptr.To(monitoringv1.URL(weChatAPIURL)),
+ APIURL: new(monitoringv1.URL(weChatAPIURL)),
APISecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "wechat",
@@ -1697,7 +1697,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
WeChatConfig: &monitoringv1.GlobalWeChatConfig{
- APIURL: ptr.To(monitoringv1.URL(invalidWeChatAPIURL)),
+ APIURL: new(monitoringv1.URL(invalidWeChatAPIURL)),
APISecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "wechat",
@@ -1741,7 +1741,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
WeChatConfig: &monitoringv1.GlobalWeChatConfig{
- APIURL: ptr.To(monitoringv1.URL(weChatAPIURL)),
+ APIURL: new(monitoringv1.URL(weChatAPIURL)),
APISecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "wechat-missing",
@@ -1785,7 +1785,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
VictorOpsConfig: &monitoringv1.GlobalVictorOpsConfig{
- APIURL: ptr.To(monitoringv1.URL(victorOpsAPIURL)),
+ APIURL: new(monitoringv1.URL(victorOpsAPIURL)),
APIKey: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "victorops",
@@ -1828,7 +1828,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
VictorOpsConfig: &monitoringv1.GlobalVictorOpsConfig{
- APIURL: ptr.To(monitoringv1.URL(invalidVictorOpsAPIURL)),
+ APIURL: new(monitoringv1.URL(invalidVictorOpsAPIURL)),
APIKey: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "victorops",
@@ -1871,7 +1871,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
amVersion: &version28,
globalConfig: &monitoringv1.AlertmanagerGlobalConfig{
VictorOpsConfig: &monitoringv1.GlobalVictorOpsConfig{
- APIURL: ptr.To(monitoringv1.URL(victorOpsAPIURL)),
+ APIURL: new(monitoringv1.URL(victorOpsAPIURL)),
APIKey: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "victorops-missing",
@@ -2078,7 +2078,7 @@ func TestInitializeFromAlertmanagerConfig(t *testing.T) {
Key: "test",
},
},
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -2298,6 +2298,9 @@ func TestGenerateConfig(t *testing.T) {
version31, err := semver.ParseTolerant("v0.31.0")
require.NoError(t, err)
+ version32, err := semver.ParseTolerant("v0.32.0")
+ require.NoError(t, err)
+
globalSlackAPIURL, err := url.Parse("http://slack.example.com")
require.NoError(t, err)
@@ -2328,7 +2331,7 @@ func TestGenerateConfig(t *testing.T) {
kclient: fake.NewClientset(),
baseConfig: alertmanagerConfig{
Global: &globalConfig{
- SMTPRequireTLS: ptr.To(false),
+ SMTPRequireTLS: new(false),
},
Route: &route{Receiver: "null"},
Receivers: []*receiver{{Name: "null"}},
@@ -2340,7 +2343,7 @@ func TestGenerateConfig(t *testing.T) {
kclient: fake.NewClientset(),
baseConfig: alertmanagerConfig{
Global: &globalConfig{
- SMTPRequireTLS: ptr.To(true),
+ SMTPRequireTLS: new(true),
},
Route: &route{Receiver: "null"},
Receivers: []*receiver{{Name: "null"}},
@@ -2623,6 +2626,59 @@ func TestGenerateConfig(t *testing.T) {
},
golden: "skeleton_base_multiple_alertmanagerconfigs.golden",
},
+ {
+ name: "skeleton base, multiple CRs with namespaceMatcher disabled",
+ kclient: fake.NewClientset(),
+ baseConfig: alertmanagerConfig{
+ Route: &route{Receiver: "null"},
+ Receivers: []*receiver{{Name: "null"}},
+ },
+ matcherStrategy: monitoringv1.AlertmanagerConfigMatcherStrategy{
+ Type: "None",
+ },
+ amConfigs: map[string]*monitoringv1alpha1.AlertmanagerConfig{
+ "ns1/amc1": {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "amc1",
+ Namespace: "ns1",
+ },
+ Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
+ Route: &monitoringv1alpha1.Route{
+ Receiver: "test",
+ GroupBy: []string{"job"},
+ },
+ Receivers: []monitoringv1alpha1.Receiver{{Name: "test"}},
+ },
+ },
+ "ns2/amc1": {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "amc1",
+ Namespace: "ns2",
+ },
+ Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
+ Route: &monitoringv1alpha1.Route{
+ Receiver: "test2",
+ GroupBy: []string{"job"},
+ },
+ Receivers: []monitoringv1alpha1.Receiver{{Name: "test2"}},
+ },
+ },
+ "ns2/amc2": {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "amc2",
+ Namespace: "ns2",
+ },
+ Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
+ Route: &monitoringv1alpha1.Route{
+ Receiver: "test2",
+ GroupBy: []string{"job", "instance"},
+ },
+ Receivers: []monitoringv1alpha1.Receiver{{Name: "test2"}},
+ },
+ },
+ },
+ golden: "skeleton_base_multiple_CRs_with_namespaceMatcher_disabled.golden",
+ },
{
name: "skeleton base, simple CR with namespaceMatcher disabled",
kclient: fake.NewClientset(),
@@ -2885,15 +2941,15 @@ func TestGenerateConfig(t *testing.T) {
},
PagerDutyImageConfigs: []monitoringv1alpha1.PagerDutyImageConfig{
{
- Src: ptr.To("https://some-image.com"),
- Href: ptr.To("https://some-image.com"),
- Alt: ptr.To("some-image"),
+ Src: new("https://some-image.com"),
+ Href: new("https://some-image.com"),
+ Alt: new("some-image"),
},
},
PagerDutyLinkConfigs: []monitoringv1alpha1.PagerDutyLinkConfig{
{
- Href: ptr.To("https://some-link.com"),
- Text: ptr.To("some-link"),
+ Href: new("https://some-link.com"),
+ Text: new("some-link"),
},
},
}},
@@ -2944,7 +3000,7 @@ func TestGenerateConfig(t *testing.T) {
Receivers: []monitoringv1alpha1.Receiver{{
Name: "test",
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{{
- URL: ptr.To("http://test.url"),
+ URL: new("http://test.url"),
HTTPConfig: &monitoringv1alpha1.HTTPConfig{
OAuth2: &monitoringv1.OAuth2{
ClientID: monitoringv1.SecretOrConfigMap{
@@ -2967,7 +3023,7 @@ func TestGenerateConfig(t *testing.T) {
"some": "value",
},
},
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
}},
}},
@@ -3060,7 +3116,7 @@ func TestGenerateConfig(t *testing.T) {
Key: "apiKey",
},
Responders: []monitoringv1alpha1.OpsGenieConfigResponder{{
- Name: ptr.To("myname"),
+ Name: new("myname"),
Type: "team",
}},
}},
@@ -3154,7 +3210,7 @@ func TestGenerateConfig(t *testing.T) {
},
Key: "apiSecret",
},
- CorpID: ptr.To("wechatcorpid"),
+ CorpID: new("wechatcorpid"),
}},
}},
},
@@ -3215,9 +3271,9 @@ func TestGenerateConfig(t *testing.T) {
},
Key: "token",
},
- Retry: ptr.To("5m"),
- Expire: ptr.To("30s"),
- HTML: ptr.To(true),
+ Retry: new("5m"),
+ Expire: new("30s"),
+ HTML: new(true),
}},
}},
},
@@ -3303,7 +3359,7 @@ func TestGenerateConfig(t *testing.T) {
{
Type: "type",
Text: "text",
- Name: ptr.To("my-action"),
+ Name: new("my-action"),
ConfirmField: &monitoringv1alpha1.SlackConfirmationField{
Text: "text",
},
@@ -3347,7 +3403,7 @@ func TestGenerateConfig(t *testing.T) {
Receivers: []monitoringv1alpha1.Receiver{{
Name: "test",
SlackConfigs: []monitoringv1alpha1.SlackConfig{{
- Channel: ptr.To("#alerts"),
+ Channel: new("#alerts"),
TitleLink: "https://example.com/title",
IconURL: "https://example.com/icon.png",
ImageURL: "https://example.com/image.png",
@@ -3388,7 +3444,7 @@ func TestGenerateConfig(t *testing.T) {
{
Type: "type",
Text: "text",
- Name: ptr.To("my-action"),
+ Name: new("my-action"),
ConfirmField: &monitoringv1alpha1.SlackConfirmationField{
Text: "text",
},
@@ -3433,7 +3489,7 @@ func TestGenerateConfig(t *testing.T) {
Receivers: []monitoringv1alpha1.Receiver{{
Name: "test",
SlackConfigs: []monitoringv1alpha1.SlackConfig{{
- MessageText: ptr.To("test message text"),
+ MessageText: new("test message text"),
}},
}},
},
@@ -3474,7 +3530,7 @@ func TestGenerateConfig(t *testing.T) {
Name: "test",
SNSConfigs: []monitoringv1alpha1.SNSConfig{
{
- ApiURL: ptr.To("https://sns.us-east-2.amazonaws.com"),
+ ApiURL: new("https://sns.us-east-2.amazonaws.com"),
Sigv4: &monitoringv1.Sigv4{
Region: "us-east-2",
AccessKey: &corev1.SecretKeySelector{
@@ -3490,7 +3546,7 @@ func TestGenerateConfig(t *testing.T) {
Key: "secret",
},
},
- TopicARN: ptr.To("test-topicARN"),
+ TopicARN: new("test-topicARN"),
},
},
}},
@@ -3532,12 +3588,12 @@ func TestGenerateConfig(t *testing.T) {
Name: "test",
SNSConfigs: []monitoringv1alpha1.SNSConfig{
{
- ApiURL: ptr.To("https://sns.us-east-2.amazonaws.com"),
+ ApiURL: new("https://sns.us-east-2.amazonaws.com"),
Sigv4: &monitoringv1.Sigv4{
Region: "us-east-2",
RoleArn: "test-roleARN",
},
- TopicARN: ptr.To("test-topicARN"),
+ TopicARN: new("test-topicARN"),
},
},
}},
@@ -3580,13 +3636,13 @@ func TestGenerateConfig(t *testing.T) {
Name: "test",
SNSConfigs: []monitoringv1alpha1.SNSConfig{
{
- ApiURL: ptr.To("https://sns.us-east-2.amazonaws.com"),
+ ApiURL: new("https://sns.us-east-2.amazonaws.com"),
Sigv4: &monitoringv1.Sigv4{
Region: "us-east-2",
RoleArn: "test-roleARN",
ExternalID: "test-externalId",
},
- TopicARN: ptr.To("test-topicARN"),
+ TopicARN: new("test-topicARN"),
},
},
}},
@@ -3629,13 +3685,13 @@ func TestGenerateConfig(t *testing.T) {
Name: "test",
SNSConfigs: []monitoringv1alpha1.SNSConfig{
{
- ApiURL: ptr.To("https://sns.us-east-2.amazonaws.com"),
+ ApiURL: new("https://sns.us-east-2.amazonaws.com"),
Sigv4: &monitoringv1.Sigv4{
Region: "us-east-2",
RoleArn: "test-roleARN",
ExternalID: "test-externalId",
},
- TopicARN: ptr.To("test-topicARN"),
+ TopicARN: new("test-topicARN"),
},
},
}},
@@ -3705,7 +3761,7 @@ func TestGenerateConfig(t *testing.T) {
{
Type: "type",
Text: "text",
- Name: ptr.To("my-action"),
+ Name: new("my-action"),
ConfirmField: &monitoringv1alpha1.SlackConfirmationField{
Text: "text",
},
@@ -3786,7 +3842,7 @@ func TestGenerateConfig(t *testing.T) {
{
Type: "type",
Text: "text",
- Name: ptr.To("my-action"),
+ Name: new("my-action"),
ConfirmField: &monitoringv1alpha1.SlackConfirmationField{
Text: "text",
},
@@ -3846,8 +3902,8 @@ func TestGenerateConfig(t *testing.T) {
Name: "ms-teams-secret",
},
},
- Title: ptr.To("test title"),
- Text: ptr.To("test text"),
+ Title: new("test title"),
+ Text: new("test text"),
},
},
},
@@ -3898,9 +3954,9 @@ func TestGenerateConfig(t *testing.T) {
Name: "ms-teams-secret",
},
},
- Title: ptr.To("test title"),
- Summary: ptr.To("test summary"),
- Text: ptr.To("test text"),
+ Title: new("test title"),
+ Summary: new("test summary"),
+ Text: new("test text"),
},
},
},
@@ -4001,8 +4057,8 @@ func TestGenerateConfig(t *testing.T) {
Name: "ms-teams-secret",
},
},
- Title: ptr.To("test title"),
- Text: ptr.To("test text"),
+ Title: new("test title"),
+ Text: new("test text"),
},
},
},
@@ -4087,9 +4143,9 @@ func TestGenerateConfig(t *testing.T) {
Name: "test",
EmailConfigs: []monitoringv1alpha1.EmailConfig{
{
- Smarthost: ptr.To("example.com:25"),
- From: ptr.To("admin@example.com"),
- To: ptr.To("customers@example.com"),
+ Smarthost: new("example.com:25"),
+ From: new("admin@example.com"),
+ To: new("customers@example.com"),
},
},
},
@@ -4124,8 +4180,8 @@ func TestGenerateConfig(t *testing.T) {
Name: "test",
EmailConfigs: []monitoringv1alpha1.EmailConfig{
{
- From: ptr.To("admin@example.com"),
- To: ptr.To("customers@example.com"),
+ From: new("admin@example.com"),
+ To: new("customers@example.com"),
},
},
},
@@ -4160,8 +4216,8 @@ func TestGenerateConfig(t *testing.T) {
Name: "test",
EmailConfigs: []monitoringv1alpha1.EmailConfig{
{
- From: ptr.To("admin@example.com"),
- To: ptr.To("customers@example.com"),
+ From: new("admin@example.com"),
+ To: new("customers@example.com"),
},
},
},
@@ -4203,7 +4259,7 @@ func TestGenerateConfig(t *testing.T) {
Name: "test",
EmailConfigs: []monitoringv1alpha1.EmailConfig{
{
- To: ptr.To("customers@example.com"),
+ To: new("customers@example.com"),
},
},
},
@@ -4238,10 +4294,10 @@ func TestGenerateConfig(t *testing.T) {
Name: "test",
EmailConfigs: []monitoringv1alpha1.EmailConfig{
{
- Smarthost: ptr.To("example.com:25"),
- From: ptr.To("admin@example.com"),
- To: ptr.To("customers@example.com"),
- ForceImplicitTLS: ptr.To(true),
+ Smarthost: new("example.com:25"),
+ From: new("admin@example.com"),
+ To: new("customers@example.com"),
+ ForceImplicitTLS: new(true),
},
},
},
@@ -4276,9 +4332,9 @@ func TestGenerateConfig(t *testing.T) {
Name: "test",
EmailConfigs: []monitoringv1alpha1.EmailConfig{
{
- Smarthost: ptr.To("example.com:25"),
- From: ptr.To("admin@example.com"),
- To: ptr.To("customers@example.com"),
+ Smarthost: new("example.com:25"),
+ From: new("admin@example.com"),
+ To: new("customers@example.com"),
Threading: &monitoringv1alpha1.EmailThreadingConfig{
ThreadByDate: monitoringv1alpha1.ThreadByDateTypeDaily,
},
@@ -4316,7 +4372,7 @@ func TestGenerateConfig(t *testing.T) {
Name: "test",
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{
{
- URL: ptr.To("https://example.com/"),
+ URL: new("https://example.com/"),
Timeout: ptr.To(monitoringv1.Duration("5s")),
},
},
@@ -4352,7 +4408,7 @@ func TestGenerateConfig(t *testing.T) {
Name: "test",
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{
{
- URL: ptr.To("https://example.com/"),
+ URL: new("https://example.com/"),
Timeout: ptr.To(monitoringv1.Duration("5s")),
},
},
@@ -4363,6 +4419,78 @@ func TestGenerateConfig(t *testing.T) {
},
golden: "CR_with_WebhookConfig_with_Timeout_Setup_Older_Version.golden",
},
+ {
+ name: "CR with WebhookConfig with Payload",
+ amVersion: &version32,
+ kclient: fake.NewClientset(),
+ baseConfig: alertmanagerConfig{
+ Route: &route{
+ Receiver: "null",
+ },
+ Receivers: []*receiver{{Name: "null"}},
+ },
+ amConfigs: map[string]*monitoringv1alpha1.AlertmanagerConfig{
+ "mynamespace": {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "myamc",
+ Namespace: "mynamespace",
+ },
+ Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
+ Route: &monitoringv1alpha1.Route{
+ Receiver: "test",
+ },
+ Receivers: []monitoringv1alpha1.Receiver{
+ {
+ Name: "test",
+ WebhookConfigs: []monitoringv1alpha1.WebhookConfig{
+ {
+ URL: new("https://example.com/"),
+ Payload: new("{\"foo\": \"bar\"}"),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ golden: "CR_with_WebhookConfig_with_Payload.golden",
+ },
+ {
+ name: "CR with WebhookConfig with Payload Unsupported Version",
+ amVersion: &version31,
+ kclient: fake.NewClientset(),
+ baseConfig: alertmanagerConfig{
+ Route: &route{
+ Receiver: "null",
+ },
+ Receivers: []*receiver{{Name: "null"}},
+ },
+ amConfigs: map[string]*monitoringv1alpha1.AlertmanagerConfig{
+ "mynamespace": {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "myamc",
+ Namespace: "mynamespace",
+ },
+ Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
+ Route: &monitoringv1alpha1.Route{
+ Receiver: "test",
+ },
+ Receivers: []monitoringv1alpha1.Receiver{
+ {
+ Name: "test",
+ WebhookConfigs: []monitoringv1alpha1.WebhookConfig{
+ {
+ URL: new("https://example.com/"),
+ Payload: new("{\"foo\": \"bar\"}"),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ golden: "CR_with_WebhookConfig_with_Payload_Unsupported_Version.golden",
+ },
}
logger := newNopLogger(t)
@@ -4456,12 +4584,6 @@ func TestSanitizeConfig(t *testing.T) {
versionSlackAppConfigAllowed := semver.Version{Major: 0, Minor: 30}
versionSlackAppConfigNotAllowed := semver.Version{Major: 0, Minor: 29}
- versionSlackMessageTextAllowed := semver.Version{Major: 0, Minor: 31}
- versionSlackMessageTextNotAllowed := semver.Version{Major: 0, Minor: 30}
-
- versionSlackUpdateMessageAllowed := semver.Version{Major: 0, Minor: 32}
- versionSlackUpdateMessageNotAllowed := semver.Version{Major: 0, Minor: 31}
-
versionJiraAllowed := semver.Version{Major: 0, Minor: 28}
versionJiraNotAllowed := semver.Version{Major: 0, Minor: 27}
jiraURL := commoncfg.URL{}
@@ -4549,7 +4671,7 @@ func TestSanitizeConfig(t *testing.T) {
againstVersion: versionGlobalSMTPForceImplicitTLSAllowed,
in: &alertmanagerConfig{
Global: &globalConfig{
- SMTPForceImplicitTLS: ptr.To(true),
+ SMTPForceImplicitTLS: new(true),
},
},
golden: "test_smtp_force_implicit_tls_added_for_supported_version.golden",
@@ -4559,7 +4681,7 @@ func TestSanitizeConfig(t *testing.T) {
againstVersion: versionGlobalSMTPForceImplicitTLSNotAllowed,
in: &alertmanagerConfig{
Global: &globalConfig{
- SMTPForceImplicitTLS: ptr.To(true),
+ SMTPForceImplicitTLS: new(true),
},
},
golden: "test_smtp_force_implicit_tls_dropped_for_unsupported_version.golden",
@@ -4669,154 +4791,6 @@ func TestSanitizeConfig(t *testing.T) {
},
golden: "test_mattermost_webhook_url_takes_precedence_over_mattermost_webhook_url_file_in_global_config.golden",
},
- {
- name: "Test api_url takes precedence in slack config",
- againstVersion: versionFileURLAllowed,
- in: &alertmanagerConfig{
- Receivers: []*receiver{
- {
- SlackConfigs: []*slackConfig{
- {
- APIURL: "www.test.com",
- APIURLFile: "/test",
- },
- },
- },
- },
- },
- golden: "test_api_url_takes_precedence_in_slack_config.golden",
- },
- {
- name: "Test api_url_file is dropped in slack config for unsupported versions",
- againstVersion: versionFileURLNotAllowed,
- in: &alertmanagerConfig{
- Receivers: []*receiver{
- {
- SlackConfigs: []*slackConfig{
- {
- APIURLFile: "/test",
- },
- },
- },
- },
- },
- golden: "test_api_url_file_is_dropped_in_slack_config_for_unsupported_versions.golden",
- },
- {
- name: "Test slack config happy path",
- againstVersion: versionFileURLAllowed,
- in: &alertmanagerConfig{
- Global: &globalConfig{
- SlackAPIURLFile: "/test",
- },
- Receivers: []*receiver{
- {
- SlackConfigs: []*slackConfig{
- {
- APIURLFile: "/test/case",
- },
- },
- },
- },
- },
- golden: "test_slack_config_happy_path.golden",
- },
- {
- name: "Test timeout is dropped in slack config for unsupported versions",
- againstVersion: versionTimeoutConfigNotAllowed,
- in: &alertmanagerConfig{
- Receivers: []*receiver{
- {
- SlackConfigs: []*slackConfig{
- {
- Timeout: ptr.To(model.Duration(time.Minute)),
- },
- },
- },
- },
- },
- golden: "test_slack_timeout_is_dropped_in_slack_config_for_unsupported_versions.golden",
- },
- {
- name: "Test timeout is added in slack config for supported versions",
- againstVersion: versionTimeoutConfigAllowed,
- in: &alertmanagerConfig{
- Receivers: []*receiver{
- {
- SlackConfigs: []*slackConfig{
- {
- Timeout: ptr.To(model.Duration(time.Minute)),
- },
- },
- },
- },
- },
- golden: "test_slack_timeout_is_added_in_slack_config_for_supported_versions.golden",
- },
- {
- name: "Test message_text is dropped in slack config for unsupported versions",
- againstVersion: versionSlackMessageTextNotAllowed,
- in: &alertmanagerConfig{
- Receivers: []*receiver{
- {
- SlackConfigs: []*slackConfig{
- {
- MessageText: "test message text",
- },
- },
- },
- },
- },
- golden: "test_slack_message_text_is_dropped_in_slack_config_for_unsupported_versions.golden",
- },
- {
- name: "Test message_text is added in slack config for supported versions",
- againstVersion: versionSlackMessageTextAllowed,
- in: &alertmanagerConfig{
- Receivers: []*receiver{
- {
- SlackConfigs: []*slackConfig{
- {
- MessageText: "test message text",
- },
- },
- },
- },
- },
- golden: "test_slack_message_text_is_added_in_slack_config_for_supported_versions.golden",
- },
- {
- name: "Test slack update_message supported version",
- againstVersion: versionSlackUpdateMessageAllowed,
- in: &alertmanagerConfig{
- Receivers: []*receiver{
- {
- SlackConfigs: []*slackConfig{
- {
- UpdateMessage: ptr.To(true),
- },
- },
- },
- },
- },
- golden: "test_slack_update_message_supported_version.golden",
- },
- {
- name: "Test slack update_message unsupported version",
- againstVersion: versionSlackUpdateMessageNotAllowed,
- in: &alertmanagerConfig{
- Receivers: []*receiver{
- {
- SlackConfigs: []*slackConfig{
- {
- UpdateMessage: ptr.To(true),
- },
- },
- },
- },
- },
- golden: "test_slack_update_message_unsupported_version.golden",
- },
{
name: "Test inhibit rules error with unsupported syntax",
againstVersion: matcherV2SyntaxNotAllowed,
@@ -5747,7 +5721,8 @@ func TestSanitizeConfig(t *testing.T) {
},
},
golden: "test_slack_app_token_and_slack_api_url_with_same_url_is_allowed.golden",
- }, {
+ },
+ {
name: "jira_config for supported versions",
againstVersion: versionJiraAllowed,
in: &alertmanagerConfig{
@@ -5883,7 +5858,7 @@ func TestHTTPClientConfig(t *testing.T) {
ProxyURL: "http://example.com/",
},
},
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
TLSConfig: &tlsConfig{
MinVersion: "TLS12",
MaxVersion: "TLS12",
@@ -5949,7 +5924,7 @@ func TestHTTPClientConfig(t *testing.T) {
ProxyURL: "http://example.com/",
},
},
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
TLSConfig: &tlsConfig{
MinVersion: "TLS13",
MaxVersion: "TLS12",
@@ -5970,7 +5945,7 @@ func TestHTTPClientConfig(t *testing.T) {
ProxyURL: "http://example.com/",
},
},
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
TLSConfig: &tlsConfig{
MinVersion: "TLS14",
},
@@ -5990,7 +5965,7 @@ func TestHTTPClientConfig(t *testing.T) {
ProxyURL: "http://example.com/",
},
},
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
TLSConfig: &tlsConfig{
MaxVersion: "TLS14",
},
@@ -6010,7 +5985,7 @@ func TestHTTPClientConfig(t *testing.T) {
ProxyURL: "http://example.com/",
},
},
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
TLSConfig: &tlsConfig{
MinVersion: "TLS12",
MaxVersion: "TLS12",
@@ -6033,7 +6008,7 @@ func TestHTTPClientConfig(t *testing.T) {
ProxyFromEnvironment: true,
},
},
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
againstVersion: httpConfigV25NotAllowed,
golden: "test_HTTP_client_config_oauth2_proxyConfig_fields_dropped_before_v0_25_0.golden",
@@ -6409,8 +6384,8 @@ func TestSanitizePushoverReceiverConfig(t *testing.T) {
{
UserKey: "foo",
Token: "bar",
- HTML: ptr.To(true),
- Monospace: ptr.To(true),
+ HTML: new(true),
+ Monospace: new(true),
},
},
},
@@ -6428,7 +6403,7 @@ func TestSanitizePushoverReceiverConfig(t *testing.T) {
{
UserKey: "foo",
Token: "bar",
- HTML: ptr.To(true),
+ HTML: new(true),
},
},
},
@@ -6446,7 +6421,7 @@ func TestSanitizePushoverReceiverConfig(t *testing.T) {
{
UserKey: "foo",
Token: "bar",
- Monospace: ptr.To(true),
+ Monospace: new(true),
},
},
},
@@ -6464,7 +6439,7 @@ func TestSanitizePushoverReceiverConfig(t *testing.T) {
{
UserKey: "foo",
Token: "bar",
- Monospace: ptr.To(true),
+ Monospace: new(true),
},
},
},
@@ -6576,7 +6551,7 @@ func TestSanitizeEmailConfig(t *testing.T) {
{
EmailConfigs: []*emailConfig{
{
- ForceImplicitTLS: ptr.To(true),
+ ForceImplicitTLS: new(true),
},
},
},
@@ -6592,7 +6567,7 @@ func TestSanitizeEmailConfig(t *testing.T) {
{
EmailConfigs: []*emailConfig{
{
- ForceImplicitTLS: ptr.To(true),
+ ForceImplicitTLS: new(true),
},
},
},
@@ -6658,7 +6633,7 @@ func TestSanitizeEmailConfig(t *testing.T) {
EmailConfigs: []*emailConfig{
{
Threading: &emailThreadingConfig{
- Enabled: ptr.To(true),
+ Enabled: new(true),
ThreadByDate: "daily",
},
},
@@ -6677,7 +6652,7 @@ func TestSanitizeEmailConfig(t *testing.T) {
EmailConfigs: []*emailConfig{
{
Threading: &emailThreadingConfig{
- Enabled: ptr.To(true),
+ Enabled: new(true),
ThreadByDate: "daily",
},
},
@@ -6696,7 +6671,7 @@ func TestSanitizeEmailConfig(t *testing.T) {
EmailConfigs: []*emailConfig{
{
Threading: &emailThreadingConfig{
- Enabled: ptr.To(true),
+ Enabled: new(true),
ThreadByDate: "",
},
},
@@ -7494,7 +7469,7 @@ func TestSanitizeJiraConfig(t *testing.T) {
APIURL: "http://issues.example.com",
Project: "Monitoring",
IssueType: "Bug",
- SendResolved: ptr.To(true),
+ SendResolved: new(true),
},
},
},
@@ -7750,7 +7725,7 @@ func TestSanitizeRocketChatConfig(t *testing.T) {
RocketChatConfigs: []*rocketChatConfig{
{
APIURL: "http://example.com",
- SendResolved: ptr.To(true),
+ SendResolved: new(true),
},
},
},
@@ -7784,7 +7759,7 @@ func TestSanitizeRocketChatConfig(t *testing.T) {
RocketChatConfigs: []*rocketChatConfig{
{
APIURL: "http://example.com",
- Token: ptr.To("aaaa-bbbb-cccc-dddd"),
+ Token: new("aaaa-bbbb-cccc-dddd"),
TokenFile: "/var/kubernetes/secrets/token",
},
},
@@ -7802,7 +7777,7 @@ func TestSanitizeRocketChatConfig(t *testing.T) {
RocketChatConfigs: []*rocketChatConfig{
{
APIURL: "http://example.com",
- TokenID: ptr.To("t123456"),
+ TokenID: new("t123456"),
TokenIDFile: "/var/kubernetes/secrets/token-id",
},
},
@@ -8263,7 +8238,7 @@ func TestConvertHTTPConfig(t *testing.T) {
{
name: "proxyURL only",
cfg: monitoringv1alpha1.HTTPConfig{
- ProxyURLOriginal: ptr.To("http://example.com"),
+ ProxyURLOriginal: new("http://example.com"),
},
golden: "proxy_url_only.golden",
},
@@ -8271,7 +8246,7 @@ func TestConvertHTTPConfig(t *testing.T) {
name: "proxyUrl only",
cfg: monitoringv1alpha1.HTTPConfig{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://example.com"),
+ ProxyURL: new("http://example.com"),
},
},
golden: "proxy_config_only.golden",
@@ -8279,9 +8254,9 @@ func TestConvertHTTPConfig(t *testing.T) {
{
name: "proxyUrl and proxyURL",
cfg: monitoringv1alpha1.HTTPConfig{
- ProxyURLOriginal: ptr.To("http://example.com"),
+ ProxyURLOriginal: new("http://example.com"),
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://bad.example.com"),
+ ProxyURL: new("http://bad.example.com"),
},
},
golden: "proxy_url_and_proxy_config.golden",
@@ -8289,9 +8264,9 @@ func TestConvertHTTPConfig(t *testing.T) {
{
name: "proxyUrl and empty proxyURL",
cfg: monitoringv1alpha1.HTTPConfig{
- ProxyURLOriginal: ptr.To(""),
+ ProxyURLOriginal: new(""),
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://example.com"),
+ ProxyURL: new("http://example.com"),
},
},
golden: "proxy_url_empty_proxy_config.golden",
@@ -8299,14 +8274,14 @@ func TestConvertHTTPConfig(t *testing.T) {
{
name: "enableHTTP2",
cfg: monitoringv1alpha1.HTTPConfig{
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
golden: "http_config_enable_http2_supported.golden",
},
{
name: "enableHTTP2 not supported",
cfg: monitoringv1alpha1.HTTPConfig{
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
version: "v0.24.0",
golden: "http_config_enable_http2_not_supported.golden",
@@ -9160,6 +9135,212 @@ func TestSanitizeMSTeamsV2Config(t *testing.T) {
}
}
+func TestSanitizeSlackConfig(t *testing.T) {
+ logger := newNopLogger(t)
+
+ versionFileURLAllowed := semver.Version{Major: 0, Minor: 22}
+ versionFileURLNotAllowed := semver.Version{Major: 0, Minor: 21}
+
+ versionSlackMessageTextAllowed := semver.Version{Major: 0, Minor: 31}
+ versionSlackMessageTextNotAllowed := semver.Version{Major: 0, Minor: 30}
+
+ versionTimeoutConfigAllowed := semver.Version{Major: 0, Minor: 30}
+ versionTimeoutConfigNotAllowed := semver.Version{Major: 0, Minor: 29}
+
+ versionSlackUpdateMessageAllowed := semver.Version{Major: 0, Minor: 32}
+ versionSlackUpdateMessageNotAllowed := semver.Version{Major: 0, Minor: 31}
+
+ for _, tc := range []struct {
+ name string
+ againstVersion semver.Version
+ in *alertmanagerConfig
+ golden string
+ expectErr bool
+ }{
+ {
+ name: "Test slack config happy path",
+ againstVersion: versionFileURLAllowed,
+ in: &alertmanagerConfig{
+ Global: &globalConfig{
+ SlackAPIURLFile: "/test",
+ },
+ Receivers: []*receiver{
+ {
+ SlackConfigs: []*slackConfig{
+ {
+ APIURLFile: "/test/case",
+ },
+ },
+ },
+ },
+ },
+ golden: "test_slack_config_happy_path.golden",
+ },
+ {
+ name: "Test api_url takes precedence in slack config",
+ againstVersion: versionFileURLAllowed,
+ in: &alertmanagerConfig{
+ Receivers: []*receiver{
+ {
+ SlackConfigs: []*slackConfig{
+ {
+ APIURL: "www.test.com",
+ APIURLFile: "/test",
+ },
+ },
+ },
+ },
+ },
+ golden: "test_api_url_takes_precedence_in_slack_config.golden",
+ },
+ {
+ name: "Test api_url_file is dropped in slack config for unsupported versions",
+ againstVersion: versionFileURLNotAllowed,
+ in: &alertmanagerConfig{
+ Receivers: []*receiver{
+ {
+ SlackConfigs: []*slackConfig{
+ {
+ APIURLFile: "/test",
+ },
+ },
+ },
+ },
+ },
+ golden: "test_api_url_file_is_dropped_in_slack_config_for_unsupported_versions.golden",
+ },
+ {
+ name: "Test timeout is dropped in slack config for unsupported versions",
+ againstVersion: versionTimeoutConfigNotAllowed,
+ in: &alertmanagerConfig{
+ Receivers: []*receiver{
+ {
+ SlackConfigs: []*slackConfig{
+ {
+ Timeout: ptr.To(model.Duration(time.Minute)),
+ },
+ },
+ },
+ },
+ },
+ golden: "test_slack_timeout_is_dropped_in_slack_config_for_unsupported_versions.golden",
+ },
+ {
+ name: "Test timeout is added in slack config for supported versions",
+ againstVersion: versionTimeoutConfigAllowed,
+ in: &alertmanagerConfig{
+ Receivers: []*receiver{
+ {
+ SlackConfigs: []*slackConfig{
+ {
+ Timeout: new(model.Duration(time.Minute)),
+ },
+ },
+ },
+ },
+ },
+ golden: "test_slack_timeout_is_added_in_slack_config_for_supported_versions.golden",
+ },
+ {
+ name: "Test message_text is dropped in slack config for unsupported versions",
+ againstVersion: versionSlackMessageTextNotAllowed,
+ in: &alertmanagerConfig{
+ Receivers: []*receiver{
+ {
+ SlackConfigs: []*slackConfig{
+ {
+ MessageText: "test message text",
+ },
+ },
+ },
+ },
+ },
+ golden: "test_slack_message_text_is_dropped_in_slack_config_for_unsupported_versions.golden",
+ },
+ {
+ name: "Test message_text is added in slack config for supported versions",
+ againstVersion: versionSlackMessageTextAllowed,
+ in: &alertmanagerConfig{
+ Receivers: []*receiver{
+ {
+ SlackConfigs: []*slackConfig{
+ {
+ MessageText: "test message text",
+ },
+ },
+ },
+ },
+ },
+ golden: "test_slack_message_text_is_added_in_slack_config_for_supported_versions.golden",
+ },
+ {
+ name: "Test slack update_message unsupported version",
+ againstVersion: versionSlackUpdateMessageNotAllowed,
+ in: &alertmanagerConfig{
+ Receivers: []*receiver{
+ {
+ SlackConfigs: []*slackConfig{
+ {
+ UpdateMessage: new(true),
+ },
+ },
+ },
+ },
+ },
+ golden: "test_slack_update_message_unsupported_version.golden",
+ },
+ {
+ name: "Test slack update_message supported version",
+ againstVersion: versionSlackUpdateMessageAllowed,
+ in: &alertmanagerConfig{
+ Receivers: []*receiver{
+ {
+ SlackConfigs: []*slackConfig{
+ {
+ UpdateMessage: new(true),
+ },
+ },
+ },
+ },
+ },
+ golden: "test_slack_update_message_supported_version.golden",
+ },
+ {
+ name: "Test slack update_message custom api url",
+ againstVersion: versionSlackUpdateMessageAllowed,
+ in: &alertmanagerConfig{
+ Receivers: []*receiver{
+ {
+ SlackConfigs: []*slackConfig{
+ {
+ APIURL: "https://api.url",
+ UpdateMessage: new(true),
+ },
+ },
+ },
+ },
+ },
+ expectErr: true,
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ err := tc.in.sanitize(tc.againstVersion, logger)
+ if tc.expectErr {
+ require.Error(t, err)
+ return
+ }
+ require.NoError(t, err)
+
+ if tc.golden != "" {
+ amConfigs, err := yaml.Marshal(tc.in)
+ require.NoError(t, err)
+
+ golden.Assert(t, string(amConfigs), tc.golden)
+ }
+ })
+ }
+}
+
func newNopLogger(t *testing.T) *slog.Logger {
t.Helper()
return slog.New(slog.DiscardHandler)
diff --git a/pkg/alertmanager/clustertlsconfig/config_test.go b/pkg/alertmanager/clustertlsconfig/config_test.go
index 0b9340a6c67..bfbf43a18b1 100644
--- a/pkg/alertmanager/clustertlsconfig/config_test.go
+++ b/pkg/alertmanager/clustertlsconfig/config_test.go
@@ -21,7 +21,6 @@ import (
"gotest.tools/v3/golden"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/utils/ptr"
"github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/clustertlsconfig"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
@@ -59,7 +58,7 @@ func TestCreateOrUpdateClusterTLSConfigSecret(t *testing.T) {
},
},
ClientTLS: monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -106,7 +105,7 @@ func TestCreateOrUpdateClusterTLSConfigSecret(t *testing.T) {
},
},
ClientTLS: monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -161,7 +160,7 @@ func TestCreateOrUpdateClusterTLSConfigSecret(t *testing.T) {
},
},
ClientTLS: monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -214,15 +213,15 @@ func TestCreateOrUpdateClusterTLSConfigSecret(t *testing.T) {
},
Key: "tls.keySecret",
},
- ClientAuthType: ptr.To("RequireAnyClientCert"),
- MinVersion: ptr.To("TLS11"),
- MaxVersion: ptr.To("TLS13"),
+ ClientAuthType: new("RequireAnyClientCert"),
+ MinVersion: new("TLS11"),
+ MaxVersion: new("TLS13"),
CipherSuites: []string{"cipher-1", "cipher-2"},
- PreferServerCipherSuites: ptr.To(false),
+ PreferServerCipherSuites: new(false),
CurvePreferences: []string{"curve-1", "curve-2"},
},
ClientTLS: monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -253,12 +252,12 @@ func TestCreateOrUpdateClusterTLSConfigSecret(t *testing.T) {
name: "cluster tls config with server client CA, cert and key files",
clusterTLSConfig: &monitoringv1.ClusterTLSConfig{
ServerTLS: monitoringv1.WebTLSConfig{
- ClientCAFile: ptr.To("/etc/ssl/certs/tls.client_ca"),
- CertFile: ptr.To("/etc/ssl/certs/tls.crt"),
- KeyFile: ptr.To("/etc/ssl/secrets/tls.key"),
+ ClientCAFile: new("/etc/ssl/certs/tls.client_ca"),
+ CertFile: new("/etc/ssl/certs/tls.crt"),
+ KeyFile: new("/etc/ssl/secrets/tls.key"),
},
ClientTLS: monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
diff --git a/pkg/alertmanager/operator.go b/pkg/alertmanager/operator.go
index 4e829f1b1ed..374894216ae 100644
--- a/pkg/alertmanager/operator.go
+++ b/pkg/alertmanager/operator.go
@@ -68,12 +68,13 @@ const (
// Whenever the value of one of these parameters is changed, it triggers an
// update of the managed statefulsets.
type Config struct {
- LocalHost string
- ClusterDomain string
- ReloaderConfig operator.ContainerConfig
- AlertmanagerDefaultBaseImage string
- Annotations operator.Map
- Labels operator.Map
+ LocalHost string
+ ClusterDomain string
+ ReloaderConfig operator.ContainerConfig
+ AlertmanagerDefaultBaseImage string
+ Annotations operator.Map
+ Labels operator.Map
+ WatchObjectRefsInAllNamespaces bool
}
// Operator manages the lifecycle of the Alertmanager statefulsets and their
@@ -170,12 +171,13 @@ func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger
repairPolicy: c.RepairPolicy,
config: Config{
- LocalHost: c.LocalHost,
- ClusterDomain: c.ClusterDomain,
- ReloaderConfig: c.ReloaderConfig,
- AlertmanagerDefaultBaseImage: c.AlertmanagerDefaultBaseImage,
- Annotations: c.Annotations,
- Labels: c.Labels,
+ LocalHost: c.LocalHost,
+ ClusterDomain: c.ClusterDomain,
+ ReloaderConfig: c.ReloaderConfig,
+ AlertmanagerDefaultBaseImage: c.AlertmanagerDefaultBaseImage,
+ Annotations: c.Annotations,
+ Labels: c.Labels,
+ WatchObjectRefsInAllNamespaces: c.WatchObjectRefsInAllNamespaces,
},
}
for _, opt := range options {
@@ -240,7 +242,7 @@ func (c *Operator) bootstrap(ctx context.Context, config operator.Config) error
}
allowList := config.Namespaces.AlertmanagerConfigAllowList
- if config.WatchObjectRefsInAllNamespaces {
+ if c.config.WatchObjectRefsInAllNamespaces {
allowList = operator.MergeAllowLists(
config.Namespaces.AlertmanagerAllowList,
config.Namespaces.AlertmanagerConfigAllowList,
@@ -384,7 +386,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
monitoringv1alpha1.AlertmanagerConfigKind,
- c.enqueueForNamespace,
+ c.enqueueForNamespaceFunc(c.nsAlrtCfgInf.GetStore()),
operator.WithFilter(
operator.AnyFilter(
operator.GenerationChanged,
@@ -397,12 +399,19 @@ func (c *Operator) addHandlers() {
c.alrtInfs,
c.reconciliations,
)
+ var gbk operator.GetByKeyer = c.nsAlrtCfgInf.GetStore()
+ if c.config.WatchObjectRefsInAllNamespaces && c.nsAlrtInf != c.nsAlrtCfgInf {
+ gbk = operator.NewMultiGetByKeyer(
+ c.nsAlrtInf.GetStore(),
+ c.nsAlrtCfgInf.GetStore(),
+ )
+ }
c.secrInfs.AddEventHandler(operator.NewEventHandler(
c.logger,
c.accessor,
c.metrics,
operator.SecretGVK().Kind,
- c.enqueueForNamespace,
+ c.enqueueForNamespaceFunc(gbk),
operator.WithFilter(operator.ResourceVersionChanged),
operator.WithFilter(hasRefFunc),
))
@@ -412,7 +421,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
operator.ConfigMapGVK().Kind,
- c.enqueueForNamespace,
+ c.enqueueForNamespaceFunc(gbk),
operator.WithFilter(operator.ResourceVersionChanged),
operator.WithFilter(hasRefFunc),
))
@@ -427,10 +436,16 @@ func (c *Operator) addHandlers() {
})
}
+func (c *Operator) enqueueForNamespaceFunc(gbk operator.GetByKeyer) func(string) {
+ return func(ns string) {
+ c.enqueueForNamespace(gbk, ns)
+ }
+}
+
// enqueueForNamespace enqueues all Alertmanager object keys that belong to the
// given namespace or select objects in the given namespace.
-func (c *Operator) enqueueForNamespace(nsName string) {
- nsObject, exists, err := c.nsAlrtCfgInf.GetStore().GetByKey(nsName)
+func (c *Operator) enqueueForNamespace(gbk operator.GetByKeyer, nsName string) {
+ nsObject, exists, err := gbk.GetByKey(nsName)
if err != nil {
c.logger.Error(
"get namespace to enqueue Alertmanager instances failed",
@@ -1451,6 +1466,10 @@ func checkWebhookConfigs(
}
}
+ if config.Payload != nil && amVersion.LT(semver.MustParse("0.32.0")) {
+ return fmt.Errorf(`payload' is available in Alertmanager >= 0.32.0 only - current %s`, amVersion)
+ }
+
if err := configureHTTPConfigInStore(ctx, config.HTTPConfig, namespace, store); err != nil {
return err
}
diff --git a/pkg/alertmanager/operator_test.go b/pkg/alertmanager/operator_test.go
index 62c0316e35e..0c0db31232c 100644
--- a/pkg/alertmanager/operator_test.go
+++ b/pkg/alertmanager/operator_test.go
@@ -181,7 +181,7 @@ func TestCreateStatefulSetInputHash(t *testing.T) {
require.Equal(t, a1Hash, a2Hash, "expected two Alertmanager CRDs to produce the same hash but got different hash")
- a2Hash, err = createSSetInputHash(tc.a, Config{}, &operator.ShardedSecret{}, appsv1.StatefulSetSpec{Replicas: ptr.To(int32(2))})
+ a2Hash, err = createSSetInputHash(tc.a, Config{}, &operator.ShardedSecret{}, appsv1.StatefulSetSpec{Replicas: new(int32(2))})
require.NoError(t, err)
require.NotEqual(t, a1Hash, a2Hash, "expected same Alertmanager CRDs with different statefulset specs to produce different hashes but got equal hash")
@@ -204,13 +204,16 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
version26, err := semver.ParseTolerant("v0.26.0")
require.NoError(t, err)
- version31, err := semver.ParseTolerant("v0.31.0")
+ version29, err := semver.ParseTolerant("v0.29.0")
require.NoError(t, err)
version30, err := semver.ParseTolerant("v0.30.0")
require.NoError(t, err)
- version29, err := semver.ParseTolerant("v0.29.0")
+ version31, err := semver.ParseTolerant("v0.31.0")
+ require.NoError(t, err)
+
+ version32, err := semver.ParseTolerant("v0.31.0")
require.NoError(t, err)
c := fake.NewClientset(
@@ -489,7 +492,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{
{
- URL: ptr.To("http://test.example.com"),
+ URL: new("http://test.example.com"),
},
},
}},
@@ -511,7 +514,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{
{
- URL: ptr.To("http:test.example.com"),
+ URL: new("http:test.example.com"),
},
},
}},
@@ -533,7 +536,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{
{
- URL: ptr.To("{{ .labels.url }}"),
+ URL: new("{{ .labels.url }}"),
},
},
}},
@@ -555,7 +558,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{
{
- URL: ptr.To("{{ .labels.value "),
+ URL: new("{{ .labels.value "),
},
},
}},
@@ -663,6 +666,60 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
},
ok: false,
},
+ {
+ amConfig: &monitoringv1alpha1.AlertmanagerConfig{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "webhook-with-payload-unsupported-version",
+ Namespace: "ns1",
+ },
+ Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
+ Route: &monitoringv1alpha1.Route{
+ Receiver: "recv1",
+ },
+ Receivers: []monitoringv1alpha1.Receiver{{
+ Name: "recv1",
+ WebhookConfigs: []monitoringv1alpha1.WebhookConfig{
+ {
+ URLSecret: &corev1.SecretKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{Name: "secret"},
+ Key: "key1",
+ },
+ Payload: new(`{"foo":"bar}`),
+ },
+ },
+ }},
+ },
+ },
+ version: &version31,
+ ok: false,
+ },
+ {
+ amConfig: &monitoringv1alpha1.AlertmanagerConfig{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "webhook-with-payload",
+ Namespace: "ns1",
+ },
+ Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
+ Route: &monitoringv1alpha1.Route{
+ Receiver: "recv1",
+ },
+ Receivers: []monitoringv1alpha1.Receiver{{
+ Name: "recv1",
+ WebhookConfigs: []monitoringv1alpha1.WebhookConfig{
+ {
+ URLSecret: &corev1.SecretKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{Name: "secret"},
+ Key: "key1",
+ },
+ Payload: new(`{"foo":"bar}`),
+ },
+ },
+ }},
+ },
+ },
+ version: &version32,
+ ok: false,
+ },
{
amConfig: &monitoringv1alpha1.AlertmanagerConfig{
ObjectMeta: metav1.ObjectMeta{
@@ -677,7 +734,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
WeChatConfigs: []monitoringv1alpha1.WeChatConfig{
{
- CorpID: ptr.To("testingCorpID"),
+ CorpID: new("testingCorpID"),
},
},
}},
@@ -699,7 +756,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
WeChatConfigs: []monitoringv1alpha1.WeChatConfig{
{
- CorpID: ptr.To("testingCorpID"),
+ CorpID: new("testingCorpID"),
APIURL: ptr.To(monitoringv1alpha1.URL("http://::invalid-url")),
},
},
@@ -722,7 +779,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
WeChatConfigs: []monitoringv1alpha1.WeChatConfig{
{
- CorpID: ptr.To("testingCorpID"),
+ CorpID: new("testingCorpID"),
APISecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{Name: "secret"},
Key: "not-existing",
@@ -748,7 +805,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
WeChatConfigs: []monitoringv1alpha1.WeChatConfig{
{
- CorpID: ptr.To("testingCorpID"),
+ CorpID: new("testingCorpID"),
APISecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{Name: "secret"},
Key: "key1",
@@ -906,7 +963,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
{
Type: "type",
Text: "text",
- Name: ptr.To("my-action"),
+ Name: new("my-action"),
},
},
},
@@ -934,7 +991,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
{
Type: "type",
Text: "text",
- Name: ptr.To("my-action"),
+ Name: new("my-action"),
ConfirmField: &monitoringv1alpha1.SlackConfirmationField{
Text: "",
},
@@ -965,7 +1022,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
{
Type: "type",
Text: "text",
- Name: ptr.To("my-action"),
+ Name: new("my-action"),
ConfirmField: &monitoringv1alpha1.SlackConfirmationField{
Text: "text",
},
@@ -1075,7 +1132,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
{
Type: "type",
Text: "text",
- Name: ptr.To("my-action"),
+ Name: new("my-action"),
ConfirmField: &monitoringv1alpha1.SlackConfirmationField{
Text: "text",
},
@@ -1108,7 +1165,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
SlackConfigs: []monitoringv1alpha1.SlackConfig{
{
- MessageText: ptr.To("test message text"),
+ MessageText: new("test message text"),
},
},
}},
@@ -1285,12 +1342,12 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
SNSConfigs: []monitoringv1alpha1.SNSConfig{
{
- ApiURL: ptr.To("https:://sns.us-east-2.amazonaws.com"),
+ ApiURL: new("https:://sns.us-east-2.amazonaws.com"),
Sigv4: &monitoringv1.Sigv4{
Region: "us-east-2",
RoleArn: "test-roleARN",
},
- TopicARN: ptr.To("test-topicARN"),
+ TopicARN: new("test-topicARN"),
},
},
}},
@@ -1387,10 +1444,10 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
EmailConfigs: []monitoringv1alpha1.EmailConfig{
{
- Smarthost: ptr.To("example.com:587"),
- From: ptr.To("admin@example.com"),
- To: ptr.To("customers@example.com"),
- ForceImplicitTLS: ptr.To(true),
+ Smarthost: new("example.com:587"),
+ From: new("admin@example.com"),
+ To: new("customers@example.com"),
+ ForceImplicitTLS: new(true),
},
},
}},
@@ -1413,10 +1470,10 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
EmailConfigs: []monitoringv1alpha1.EmailConfig{
{
- Smarthost: ptr.To("example.com:587"),
- From: ptr.To("admin@example.com"),
- To: ptr.To("customers@example.com"),
- ForceImplicitTLS: ptr.To(true),
+ Smarthost: new("example.com:587"),
+ From: new("admin@example.com"),
+ To: new("customers@example.com"),
+ ForceImplicitTLS: new(true),
},
},
}},
@@ -1445,7 +1502,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "secret",
},
},
- BotTokenFile: ptr.To("/bot/token/file"),
+ BotTokenFile: new("/bot/token/file"),
},
},
}},
@@ -1468,7 +1525,7 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
TelegramConfigs: []monitoringv1alpha1.TelegramConfig{
{
- BotTokenFile: ptr.To("/bot/token/file"),
+ BotTokenFile: new("/bot/token/file"),
},
},
}},
@@ -1491,9 +1548,9 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
EmailConfigs: []monitoringv1alpha1.EmailConfig{
{
- Smarthost: ptr.To("example.com:587"),
- From: ptr.To("admin@example.com"),
- To: ptr.To("customers@example.com"),
+ Smarthost: new("example.com:587"),
+ From: new("admin@example.com"),
+ To: new("customers@example.com"),
Threading: &monitoringv1alpha1.EmailThreadingConfig{
ThreadByDate: monitoringv1alpha1.ThreadByDateTypeDaily,
},
@@ -1519,9 +1576,9 @@ func TestCheckAlertmanagerConfig(t *testing.T) {
Name: "recv1",
EmailConfigs: []monitoringv1alpha1.EmailConfig{
{
- Smarthost: ptr.To("example.com:587"),
- From: ptr.To("admin@example.com"),
- To: ptr.To("customers@example.com"),
+ Smarthost: new("example.com:587"),
+ From: new("admin@example.com"),
+ To: new("customers@example.com"),
Threading: &monitoringv1alpha1.EmailThreadingConfig{
ThreadByDate: monitoringv1alpha1.ThreadByDateTypeDaily,
},
diff --git a/pkg/alertmanager/statefulset.go b/pkg/alertmanager/statefulset.go
index cca77f84851..3aef2fb7b90 100644
--- a/pkg/alertmanager/statefulset.go
+++ b/pkg/alertmanager/statefulset.go
@@ -710,8 +710,8 @@ func makeStatefulSetSpec(logger *slog.Logger, a *monitoringv1.Alertmanager, conf
ReadinessProbe: readinessProbe,
Resources: a.Spec.Resources,
SecurityContext: &corev1.SecurityContext{
- AllowPrivilegeEscalation: ptr.To(false),
- ReadOnlyRootFilesystem: ptr.To(true),
+ AllowPrivilegeEscalation: new(false),
+ ReadOnlyRootFilesystem: new(true),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
@@ -802,7 +802,7 @@ func makeStatefulSetSpec(logger *slog.Logger, a *monitoringv1.Alertmanager, conf
NodeSelector: a.Spec.NodeSelector,
SchedulerName: a.Spec.SchedulerName,
PriorityClassName: a.Spec.PriorityClassName,
- TerminationGracePeriodSeconds: ptr.To(ptr.Deref(a.Spec.TerminationGracePeriodSeconds, defaultTerminationGracePeriodSeconds)),
+ TerminationGracePeriodSeconds: new(ptr.Deref(a.Spec.TerminationGracePeriodSeconds, defaultTerminationGracePeriodSeconds)),
InitContainers: initContainers,
Containers: containers,
Volumes: volumes,
diff --git a/pkg/alertmanager/statefulset_test.go b/pkg/alertmanager/statefulset_test.go
index 3a1a2372e24..e982b0aeb56 100644
--- a/pkg/alertmanager/statefulset_test.go
+++ b/pkg/alertmanager/statefulset_test.go
@@ -447,14 +447,14 @@ func TestMakeStatefulSetSpecWebTimeout(t *testing.T) {
scenario: "no timeout for old version",
version: "0.16.9",
web: &monitoringv1.AlertmanagerWebSpec{
- Timeout: toPtr(uint32(50)),
+ Timeout: new(uint32(50)),
},
expectTimeoutArg: false,
}, {
scenario: "timeout arg set if specified",
version: operator.DefaultAlertmanagerVersion,
web: &monitoringv1.AlertmanagerWebSpec{
- Timeout: toPtr(uint32(50)),
+ Timeout: new(uint32(50)),
},
expectTimeoutArg: true,
}}
@@ -462,7 +462,7 @@ func TestMakeStatefulSetSpecWebTimeout(t *testing.T) {
for _, ts := range tt {
t.Run(ts.scenario, func(t *testing.T) {
a := monitoringv1.Alertmanager{}
- a.Spec.Replicas = toPtr(int32(1))
+ a.Spec.Replicas = new(int32(1))
a.Spec.Version = ts.version
a.Spec.Web = ts.web
@@ -493,7 +493,7 @@ func TestMakeStatefulSetSpecWebConcurrency(t *testing.T) {
scenario: "no get-concurrency for old version",
version: "0.16.9",
web: &monitoringv1.AlertmanagerWebSpec{
- GetConcurrency: toPtr(uint32(50)),
+ GetConcurrency: new(uint32(50)),
},
expectGetConcurrencyArg: false,
}, {
@@ -501,7 +501,7 @@ func TestMakeStatefulSetSpecWebConcurrency(t *testing.T) {
version: operator.DefaultAlertmanagerVersion,
web: &monitoringv1.AlertmanagerWebSpec{
- GetConcurrency: toPtr(uint32(50)),
+ GetConcurrency: new(uint32(50)),
},
expectGetConcurrencyArg: true,
}}
@@ -509,7 +509,7 @@ func TestMakeStatefulSetSpecWebConcurrency(t *testing.T) {
for _, ts := range tt {
t.Run(ts.scenario, func(t *testing.T) {
a := monitoringv1.Alertmanager{}
- a.Spec.Replicas = toPtr(int32(1))
+ a.Spec.Replicas = new(int32(1))
a.Spec.Version = ts.version
a.Spec.Web = ts.web
@@ -540,14 +540,14 @@ func TestMakeStatefulSetSpecMaxSilences(t *testing.T) {
scenario: "no maxSilencesfor old version",
version: "0.27.9",
limits: &monitoringv1.AlertmanagerLimitsSpec{
- MaxSilences: toPtr(int32(50)),
+ MaxSilences: new(int32(50)),
},
expectMaxSilencesArg: false,
}, {
scenario: "maxSilencesfor arg set if specified",
version: operator.DefaultAlertmanagerVersion,
limits: &monitoringv1.AlertmanagerLimitsSpec{
- MaxSilences: toPtr(int32(50)),
+ MaxSilences: new(int32(50)),
},
expectMaxSilencesArg: true,
},
@@ -556,7 +556,7 @@ func TestMakeStatefulSetSpecMaxSilences(t *testing.T) {
for _, ts := range tt {
t.Run(ts.scenario, func(t *testing.T) {
a := monitoringv1.Alertmanager{}
- a.Spec.Replicas = toPtr(int32(1))
+ a.Spec.Replicas = new(int32(1))
a.Spec.Version = ts.version
a.Spec.Limits = ts.limits
@@ -587,14 +587,14 @@ func TestMakeStatefulSetSpecMaxPerSilenceBytes(t *testing.T) {
scenario: "no maxPerSilenceBytes old version",
version: "0.27.9",
limits: &monitoringv1.AlertmanagerLimitsSpec{
- MaxPerSilenceBytes: toPtr(monitoringv1.ByteSize("5MB")),
+ MaxPerSilenceBytes: new(monitoringv1.ByteSize("5MB")),
},
expectMaxPerSilenceBytesArg: false,
}, {
scenario: "maxPerSilenceBytes arg set if specified",
version: operator.DefaultAlertmanagerVersion,
limits: &monitoringv1.AlertmanagerLimitsSpec{
- MaxPerSilenceBytes: toPtr(monitoringv1.ByteSize("5MB")),
+ MaxPerSilenceBytes: new(monitoringv1.ByteSize("5MB")),
},
expectMaxPerSilenceBytesArg: true,
},
@@ -603,7 +603,7 @@ func TestMakeStatefulSetSpecMaxPerSilenceBytes(t *testing.T) {
for _, ts := range tt {
t.Run(ts.scenario, func(t *testing.T) {
a := monitoringv1.Alertmanager{}
- a.Spec.Replicas = toPtr(int32(1))
+ a.Spec.Replicas = new(int32(1))
a.Spec.Version = ts.version
a.Spec.Limits = ts.limits
@@ -1073,7 +1073,7 @@ func TestClusterListenAddressForMultiReplica(t *testing.T) {
func TestExpectStatefulSetMinReadySeconds(t *testing.T) {
a := monitoringv1.Alertmanager{}
a.Spec.Version = operator.DefaultAlertmanagerVersion
- a.Spec.Replicas = ptr.To(int32(3))
+ a.Spec.Replicas = new(int32(3))
// assert defaults to zero if nil
statefulSet, err := makeStatefulSetSpec(nil, &a, defaultTestConfig, &operator.ShardedSecret{})
@@ -1081,7 +1081,7 @@ func TestExpectStatefulSetMinReadySeconds(t *testing.T) {
require.Equal(t, int32(0), statefulSet.MinReadySeconds)
// assert set correctly if not nil
- a.Spec.MinReadySeconds = ptr.To(int32(5))
+ a.Spec.MinReadySeconds = new(int32(5))
statefulSet, err = makeStatefulSetSpec(nil, &a, defaultTestConfig, &operator.ShardedSecret{})
require.NoError(t, err)
require.Equal(t, int32(5), statefulSet.MinReadySeconds)
@@ -1146,7 +1146,7 @@ func TestPodTemplateConfig(t *testing.T) {
ImagePullSecrets: imagePullSecrets,
ImagePullPolicy: imagePullPolicy,
SchedulerName: schedulerName,
- HostUsers: ptr.To(true),
+ HostUsers: new(true),
HostNetwork: hostNetwork,
},
}, defaultTestConfig, "", &operator.ShardedSecret{})
@@ -1262,7 +1262,7 @@ func TestClusterLabel(t *testing.T) {
Namespace: "monitoring",
},
Spec: monitoringv1.AlertmanagerSpec{
- Replicas: toPtr(int32(1)),
+ Replicas: new(int32(1)),
Version: ts.version,
},
}
@@ -1392,10 +1392,6 @@ func containsString(sub string) func(string) bool {
}
}
-func toPtr[T any](t T) *T {
- return &t
-}
-
func TestEnableFeatures(t *testing.T) {
tt := []struct {
name string
@@ -1428,7 +1424,7 @@ func TestEnableFeatures(t *testing.T) {
statefulSpec, err := makeStatefulSetSpec(nil, &monitoringv1.Alertmanager{
Spec: monitoringv1.AlertmanagerSpec{
Version: test.version,
- Replicas: toPtr(int32(1)),
+ Replicas: new(int32(1)),
EnableFeatures: test.features,
},
}, defaultTestConfig, &operator.ShardedSecret{})
@@ -1453,7 +1449,7 @@ func TestValidateAdditionalArgs(t *testing.T) {
statefulSpec, err := makeStatefulSetSpec(nil, &monitoringv1.Alertmanager{
Spec: monitoringv1.AlertmanagerSpec{
- Replicas: toPtr(int32(1)),
+ Replicas: new(int32(1)),
AdditionalArgs: additionalArgs,
},
}, defaultTestConfig, &operator.ShardedSecret{})
@@ -1477,7 +1473,7 @@ func TestStatefulSetDNSPolicyAndDNSConfig(t *testing.T) {
Options: []monitoringv1.PodDNSConfigOption{
{
Name: "ndots",
- Value: ptr.To("5"),
+ Value: new("5"),
},
},
},
@@ -1493,7 +1489,7 @@ func TestStatefulSetDNSPolicyAndDNSConfig(t *testing.T) {
Options: []corev1.PodDNSConfigOption{
{
Name: "ndots",
- Value: ptr.To("5"),
+ Value: new("5"),
},
},
}, sset.Spec.Template.Spec.DNSConfig, "expected dns configuration to match")
@@ -1525,8 +1521,8 @@ func TestStatefulSetEnableServiceLinks(t *testing.T) {
enableServiceLinks *bool
expectedEnableService *bool
}{
- {enableServiceLinks: ptr.To(false), expectedEnableService: ptr.To(false)},
- {enableServiceLinks: ptr.To(true), expectedEnableService: ptr.To(true)},
+ {enableServiceLinks: new(false), expectedEnableService: new(false)},
+ {enableServiceLinks: new(true), expectedEnableService: new(true)},
{enableServiceLinks: nil, expectedEnableService: nil},
}
@@ -1600,13 +1596,13 @@ func TestStatefulSetUpdateStrategy(t *testing.T) {
updateStrategy: &monitoringv1.StatefulSetUpdateStrategy{
Type: monitoringv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &monitoringv1.RollingUpdateStatefulSetStrategy{
- MaxUnavailable: ptr.To(intstr.FromInt(1)),
+ MaxUnavailable: new(intstr.FromInt(1)),
},
},
exp: appsv1.StatefulSetUpdateStrategy{
Type: appsv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{
- MaxUnavailable: ptr.To(intstr.FromInt(1)),
+ MaxUnavailable: new(intstr.FromInt(1)),
},
},
},
@@ -1652,17 +1648,17 @@ func TestMakeStatefulSetSpecDispatchStartDelay(t *testing.T) {
},
{
version: "v0.29.0",
- minReadySeconds: ptr.To(int32(60)),
+ minReadySeconds: new(int32(60)),
expNotContains: "dispatch.start-delay",
},
{
version: "v0.30.0",
- minReadySeconds: ptr.To(int32(60)),
+ minReadySeconds: new(int32(60)),
expContains: "--dispatch.start-delay=60s",
},
{
version: "v0.30.0",
- minReadySeconds: ptr.To(int32(60)),
+ minReadySeconds: new(int32(60)),
additionalArgs: []monitoringv1.Argument{{Name: "dispatch.start-delay", Value: "10s"}},
expContains: "--dispatch.start-delay=10s",
},
@@ -1670,7 +1666,7 @@ func TestMakeStatefulSetSpecDispatchStartDelay(t *testing.T) {
t.Run("", func(t *testing.T) {
a := monitoringv1.Alertmanager{
Spec: monitoringv1.AlertmanagerSpec{
- Replicas: ptr.To(int32(1)),
+ Replicas: new(int32(1)),
Version: tc.version,
MinReadySeconds: tc.minReadySeconds,
AdditionalArgs: tc.additionalArgs,
diff --git a/pkg/alertmanager/testdata/CR_with_WebhookConfig_with_Payload.golden b/pkg/alertmanager/testdata/CR_with_WebhookConfig_with_Payload.golden
new file mode 100644
index 00000000000..e243f42961f
--- /dev/null
+++ b/pkg/alertmanager/testdata/CR_with_WebhookConfig_with_Payload.golden
@@ -0,0 +1,14 @@
+route:
+ receiver: "null"
+ routes:
+ - receiver: mynamespace/myamc/test
+ matchers:
+ - namespace="mynamespace"
+ continue: true
+receivers:
+- name: "null"
+- name: mynamespace/myamc/test
+ webhook_configs:
+ - url: https://example.com/
+ payload: '{"foo": "bar"}'
+templates: []
diff --git a/pkg/alertmanager/testdata/CR_with_WebhookConfig_with_Payload_Unsupported_Version.golden b/pkg/alertmanager/testdata/CR_with_WebhookConfig_with_Payload_Unsupported_Version.golden
new file mode 100644
index 00000000000..20b6e3987bc
--- /dev/null
+++ b/pkg/alertmanager/testdata/CR_with_WebhookConfig_with_Payload_Unsupported_Version.golden
@@ -0,0 +1,13 @@
+route:
+ receiver: "null"
+ routes:
+ - receiver: mynamespace/myamc/test
+ matchers:
+ - namespace="mynamespace"
+ continue: true
+receivers:
+- name: "null"
+- name: mynamespace/myamc/test
+ webhook_configs:
+ - url: https://example.com/
+templates: []
diff --git a/pkg/alertmanager/testdata/skeleton_base_multiple_CRs_with_namespaceMatcher_disabled.golden b/pkg/alertmanager/testdata/skeleton_base_multiple_CRs_with_namespaceMatcher_disabled.golden
new file mode 100644
index 00000000000..54b69775b27
--- /dev/null
+++ b/pkg/alertmanager/testdata/skeleton_base_multiple_CRs_with_namespaceMatcher_disabled.golden
@@ -0,0 +1,22 @@
+route:
+ receiver: "null"
+ routes:
+ - receiver: ns1/amc1/test
+ group_by:
+ - job
+ continue: true
+ - receiver: ns2/amc1/test2
+ group_by:
+ - job
+ continue: true
+ - receiver: ns2/amc2/test2
+ group_by:
+ - job
+ - instance
+ continue: true
+receivers:
+- name: "null"
+- name: ns1/amc1/test
+- name: ns2/amc1/test2
+- name: ns2/amc2/test2
+templates: []
diff --git a/pkg/alertmanager/types.go b/pkg/alertmanager/types.go
index df13a783d40..46a0c403cc5 100644
--- a/pkg/alertmanager/types.go
+++ b/pkg/alertmanager/types.go
@@ -141,7 +141,7 @@ type webhookConfig struct {
HTTPConfig *httpClientConfig `yaml:"http_config,omitempty"`
MaxAlerts int32 `yaml:"max_alerts,omitempty"`
Timeout *model.Duration `yaml:"timeout,omitempty"`
- Payload map[string]any `yaml:"payload,omitempty"`
+ Payload any `yaml:"payload,omitempty"`
}
type pagerdutyConfig struct {
diff --git a/pkg/alertmanager/validation/v1/validation.go b/pkg/alertmanager/validation/v1/validation.go
index 78ddf1d7986..42a891bc0aa 100644
--- a/pkg/alertmanager/validation/v1/validation.go
+++ b/pkg/alertmanager/validation/v1/validation.go
@@ -27,7 +27,7 @@ func ValidateAlertmanagerGlobalConfig(gc *monitoringv1.AlertmanagerGlobalConfig)
}
if err := gc.HTTPConfigWithProxy.Validate(); err != nil {
- return fmt.Errorf("httpConfig: %w", err)
+ return fmt.Errorf("'httpConfig': %w", err)
}
if err := validatingTelegramConfig(gc.TelegramConfig); err != nil {
@@ -51,7 +51,7 @@ func ValidateAlertmanagerGlobalConfig(gc *monitoringv1.AlertmanagerGlobalConfig)
}
if err := validateGlobalWeChatConfig(gc.WeChatConfig); err != nil {
- return fmt.Errorf("wechatConfig: %w", err)
+ return fmt.Errorf("'wechat': %w", err)
}
return nil
@@ -63,7 +63,7 @@ func validatingTelegramConfig(tc *monitoringv1.GlobalTelegramConfig) error {
}
if err := validation.ValidateURLPtr((*string)(tc.APIURL)); err != nil {
- return fmt.Errorf("invalid apiURL: %w", err)
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
return nil
@@ -75,7 +75,7 @@ func validateGlobalJiraConfig(jc *monitoringv1.GlobalJiraConfig) error {
}
if err := validation.ValidateURLPtr((*string)(jc.APIURL)); err != nil {
- return fmt.Errorf("invalid apiURL: %w", err)
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
return nil
@@ -87,7 +87,7 @@ func validateGlobalVictorOpsConfig(vc *monitoringv1.GlobalVictorOpsConfig) error
}
if err := validation.ValidateURLPtr((*string)(vc.APIURL)); err != nil {
- return fmt.Errorf("invalid apiURL: %w", err)
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
return nil
@@ -99,7 +99,7 @@ func validateGlobalRocketChatConfig(rc *monitoringv1.GlobalRocketChatConfig) err
}
if err := validation.ValidateURLPtr((*string)(rc.APIURL)); err != nil {
- return fmt.Errorf("invalid apiURL: %w", err)
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
return nil
@@ -111,7 +111,7 @@ func validateGlobalWebexConfig(wc *monitoringv1.GlobalWebexConfig) error {
}
if err := validation.ValidateURLPtr((*string)(wc.APIURL)); err != nil {
- return fmt.Errorf("invalid apiURL: %w", err)
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
return nil
@@ -123,7 +123,7 @@ func validateGlobalWeChatConfig(wc *monitoringv1.GlobalWeChatConfig) error {
}
if err := validation.ValidateURLPtr((*string)(wc.APIURL)); err != nil {
- return fmt.Errorf("invalid apiURL: %w", err)
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
return nil
diff --git a/pkg/alertmanager/validation/v1alpha1/validation.go b/pkg/alertmanager/validation/v1alpha1/validation.go
index a031b0d0178..676827f18f6 100644
--- a/pkg/alertmanager/validation/v1alpha1/validation.go
+++ b/pkg/alertmanager/validation/v1alpha1/validation.go
@@ -54,64 +54,68 @@ func validateReceivers(receivers []monitoringv1alpha1.Receiver) (map[string]stru
}
receiverNames[receiver.Name] = struct{}{}
- if err = validatePagerDutyConfigs(receiver.PagerDutyConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'pagerDutyConfig' - receiver %s: %w", receiver.Name, err)
+ receiverValidationFailedFormat := func(err error) (map[string]struct{}, error) {
+ return nil, fmt.Errorf("failed to validate receiver %q: %w", receiver.Name, err)
}
if err := validateOpsGenieConfigs(receiver.OpsGenieConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'opsGenieConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
+ }
+
+ if err = validatePagerDutyConfigs(receiver.PagerDutyConfigs); err != nil {
+ return receiverValidationFailedFormat(err)
+ }
+
+ if err := validateDiscordConfigs(receiver.DiscordConfigs); err != nil {
+ return receiverValidationFailedFormat(err)
}
if err := validateSlackConfigs(receiver.SlackConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'slackConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validateWebhookConfigs(receiver.WebhookConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'webhookConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validateWechatConfigs(receiver.WeChatConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'weChatConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validateEmailConfig(receiver.EmailConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'emailConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validateVictorOpsConfigs(receiver.VictorOpsConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'victorOpsConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validatePushoverConfigs(receiver.PushoverConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'pushOverConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
- if err := validateSnsConfigs(receiver.SNSConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'snsConfig' - receiver %s: %w", receiver.Name, err)
+ if err := validateSNSConfigs(receiver.SNSConfigs); err != nil {
+ return receiverValidationFailedFormat(err)
}
if err := validateTelegramConfigs(receiver.TelegramConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'telegramConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validateWebexConfigs(receiver.WebexConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'webexConfig' - receiver %s: %w", receiver.Name, err)
- }
-
- if err := validateDiscordConfigs(receiver.DiscordConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'discordConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validateMSTeamsConfigs(receiver.MSTeamsConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'msteamsConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
- if err := validateRocketchatConfigs(receiver.RocketChatConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'rocketchatConfig' - receiver %s: %w", receiver.Name, err)
+ if err := validateMSTeamsV2Configs(receiver.MSTeamsV2Configs); err != nil {
+ return receiverValidationFailedFormat(err)
}
- if err := validateMSTeamsV2Configs(receiver.MSTeamsV2Configs); err != nil {
- return nil, fmt.Errorf("failed to validate 'msteamsv2Config' - receiver %s: %w", receiver.Name, err)
+ if err := validateRocketchatConfigs(receiver.RocketChatConfigs); err != nil {
+ return receiverValidationFailedFormat(err)
}
}
@@ -119,14 +123,14 @@ func validateReceivers(receivers []monitoringv1alpha1.Receiver) (map[string]stru
}
func validatePagerDutyConfigs(configs []monitoringv1alpha1.PagerDutyConfig) error {
- for i, conf := range configs {
+ v := func(conf monitoringv1alpha1.PagerDutyConfig) error {
if err := validation.ValidateURLPtr((*string)(conf.URL)); err != nil {
- return fmt.Errorf("[%d]: url: %w", i, err)
+ return fmt.Errorf("invalid 'url': %w", err)
}
if conf.ClientURL != nil && *conf.ClientURL != "" {
if err := validation.ValidateTemplateURL(*conf.ClientURL); err != nil {
- return fmt.Errorf("[%d]: clientURL: %w", i, err)
+ return fmt.Errorf("invalid 'clientURL': %w", err)
}
}
@@ -137,7 +141,7 @@ func validatePagerDutyConfigs(configs []monitoringv1alpha1.PagerDutyConfig) erro
for j, lc := range conf.PagerDutyLinkConfigs {
if lc.Href != nil && *lc.Href != "" {
if err := validation.ValidateTemplateURL(*lc.Href); err != nil {
- return fmt.Errorf("[%d]: pagerDutyLinkConfigs[%d]: href: %w", i, j, err)
+ return fmt.Errorf("'pagerDutyLinkConfigs'[%d]: invalid 'href': %w", j, err)
}
}
}
@@ -145,30 +149,47 @@ func validatePagerDutyConfigs(configs []monitoringv1alpha1.PagerDutyConfig) erro
for j, ic := range conf.PagerDutyImageConfigs {
if ic.Href != nil && *ic.Href != "" {
if err := validation.ValidateTemplateURL(*ic.Href); err != nil {
- return fmt.Errorf("[%d]: pagerDutyImageConfigs[%d]: href: %w", i, j, err)
+ return fmt.Errorf("'pagerDutyImageConfigs'[%d]: invalid 'href': %w", j, err)
}
}
}
if err := conf.HTTPConfig.Validate(); err != nil {
- return err
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'pagerdutyConfigs'[%d]: %w", i, err)
}
}
+
return nil
}
func validateOpsGenieConfigs(configs []monitoringv1alpha1.OpsGenieConfig) error {
- for i, config := range configs {
- if err := config.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ v := func(conf monitoringv1alpha1.OpsGenieConfig) error {
+ if err := conf.Validate(); err != nil {
+ return err
}
- if err := validation.ValidateURLPtr((*string)(config.APIURL)); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ if err := validation.ValidateURLPtr((*string)(conf.APIURL)); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'opsgenieConfigs'[%d]: %w", i, err)
}
}
@@ -176,40 +197,57 @@ func validateOpsGenieConfigs(configs []monitoringv1alpha1.OpsGenieConfig) error
}
func validateDiscordConfigs(configs []monitoringv1alpha1.DiscordConfig) error {
- for _, config := range configs {
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ v := func(conf monitoringv1alpha1.DiscordConfig) error {
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'discordConfigs'[%d]: %w", i, err)
}
}
+
return nil
}
func validateRocketchatConfigs(configs []monitoringv1alpha1.RocketChatConfig) error {
- for i, config := range configs {
- if err := validation.ValidateURLPtr((*string)(config.APIURL)); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ v := func(conf monitoringv1alpha1.RocketChatConfig) error {
+ if err := validation.ValidateURLPtr((*string)(conf.APIURL)); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
- if err := validation.ValidateTemplateURLPtr(config.IconURL); err != nil {
- return fmt.Errorf("[%d]: invalid 'iconURL': %w", i, err)
+ if err := validation.ValidateTemplateURLPtr(conf.IconURL); err != nil {
+ return fmt.Errorf("invalid 'iconURL': %w", err)
}
- if err := validation.ValidateTemplateURLPtr(config.ImageURL); err != nil {
- return fmt.Errorf("[%d]: invalid 'imageURL': %w", i, err)
+ if err := validation.ValidateTemplateURLPtr(conf.ImageURL); err != nil {
+ return fmt.Errorf("invalid 'imageURL': %w", err)
}
- if err := validation.ValidateTemplateURLPtr(config.ThumbURL); err != nil {
- return fmt.Errorf("[%d]: invalid 'thumbURL': %w", i, err)
+ if err := validation.ValidateTemplateURLPtr(conf.ThumbURL); err != nil {
+ return fmt.Errorf("invalid 'thumbURL': %w", err)
}
- for j, a := range config.Actions {
+ for j, a := range conf.Actions {
if err := validation.ValidateTemplateURLPtr(a.URL); err != nil {
- return fmt.Errorf("[%d]: actions[%d]: invalid 'url': %w", i, j, err)
+ return fmt.Errorf("'actions'[%d]: invalid 'url': %w", j, err)
}
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'rocketchatConfigs'[%d]: %w", i, err)
}
}
@@ -217,30 +255,47 @@ func validateRocketchatConfigs(configs []monitoringv1alpha1.RocketChatConfig) er
}
func validateSlackConfigs(configs []monitoringv1alpha1.SlackConfig) error {
- for _, config := range configs {
- if err := config.Validate(); err != nil {
+ v := func(conf monitoringv1alpha1.SlackConfig) error {
+ if err := conf.Validate(); err != nil {
return err
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
}
+
+ return nil
}
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'slackConfigs'[%d]: %w", i, err)
+ }
+ }
+
return nil
}
func validateWebhookConfigs(configs []monitoringv1alpha1.WebhookConfig) error {
- for i, config := range configs {
- if config.URL == nil && config.URLSecret == nil {
- return fmt.Errorf("[%d]: one of 'url' or 'urlSecret' must be specified", i)
+ v := func(conf monitoringv1alpha1.WebhookConfig) error {
+ if conf.URL == nil && conf.URLSecret == nil {
+ return errors.New("one of 'url' or 'urlSecret' must be specified")
+ }
+
+ if err := validation.ValidateTemplateURLPtr(conf.URL); err != nil {
+ return fmt.Errorf("invalid 'url': %w", err)
}
- if err := validation.ValidateTemplateURLPtr(config.URL); err != nil {
- return fmt.Errorf("[%d]: url: %w", i, err)
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'webhookConfigs'[%d]: %w", i, err)
}
}
@@ -248,13 +303,21 @@ func validateWebhookConfigs(configs []monitoringv1alpha1.WebhookConfig) error {
}
func validateWechatConfigs(configs []monitoringv1alpha1.WeChatConfig) error {
- for i, config := range configs {
- if err := validation.ValidateURLPtr((*string)(config.APIURL)); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ v := func(conf monitoringv1alpha1.WeChatConfig) error {
+ if err := validation.ValidateURLPtr((*string)(conf.APIURL)); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'wechatConfigs'[%d]: %w", i, err)
}
}
@@ -262,36 +325,44 @@ func validateWechatConfigs(configs []monitoringv1alpha1.WeChatConfig) error {
}
func validateEmailConfig(configs []monitoringv1alpha1.EmailConfig) error {
- for _, config := range configs {
- if ptr.Deref(config.To, "") == "" {
+ v := func(conf monitoringv1alpha1.EmailConfig) error {
+ if ptr.Deref(conf.To, "") == "" {
return errors.New("missing 'to' address")
}
- if ptr.Deref(config.Smarthost, "") != "" {
- _, _, err := net.SplitHostPort(*config.Smarthost)
+ if ptr.Deref(conf.Smarthost, "") != "" {
+ _, _, err := net.SplitHostPort(*conf.Smarthost)
if err != nil {
- return fmt.Errorf("invalid 'smarthost' %s: %w", *config.Smarthost, err)
+ return fmt.Errorf("invalid 'smarthost' %q: %w", *conf.Smarthost, err)
}
}
- if config.Headers != nil {
+ if conf.Headers != nil {
// Header names are case-insensitive, check for collisions.
normalizedHeaders := map[string]struct{}{}
- for _, v := range config.Headers {
- normalized := strings.ToLower(v.Key)
+ for _, h := range conf.Headers {
+ normalized := strings.ToLower(h.Key)
if _, ok := normalizedHeaders[normalized]; ok {
return fmt.Errorf("duplicate header %q", normalized)
}
normalizedHeaders[normalized] = struct{}{}
}
}
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'emailConfigs'[%d]: %w", i, err)
+ }
}
+
return nil
}
func validateVictorOpsConfigs(configs []monitoringv1alpha1.VictorOpsConfig) error {
- for i, config := range configs {
-
+ v := func(conf monitoringv1alpha1.VictorOpsConfig) error {
// from https://github.com/prometheus/alertmanager/blob/a7f9fdadbecbb7e692d2cd8d3334e3d6de1602e1/config/notifiers.go#L497
reservedFields := map[string]struct{}{
"routing_key": {},
@@ -303,96 +374,130 @@ func validateVictorOpsConfigs(configs []monitoringv1alpha1.VictorOpsConfig) erro
"entity_state": {},
}
- if len(config.CustomFields) > 0 {
- for _, v := range config.CustomFields {
- if _, ok := reservedFields[v.Key]; ok {
- return fmt.Errorf("usage of reserved word %q is not allowed in custom fields", v.Key)
+ if len(conf.CustomFields) > 0 {
+ for _, f := range conf.CustomFields {
+ if _, ok := reservedFields[f.Key]; ok {
+ return fmt.Errorf("usage of reserved word %q is not allowed in custom fields", f.Key)
}
}
}
- if config.RoutingKey == "" {
+ if conf.RoutingKey == "" {
return errors.New("missing 'routingKey' key")
}
- if err := validation.ValidateURLPtr((*string)(config.APIURL)); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ if err := validation.ValidateURLPtr((*string)(conf.APIURL)); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'victoropsConfigs'[%d]: %w", i, err)
}
}
+
return nil
}
func validatePushoverConfigs(configs []monitoringv1alpha1.PushoverConfig) error {
- for i, config := range configs {
- if config.UserKey == nil && config.UserKeyFile == nil {
- return fmt.Errorf("one of userKey or userKeyFile must be configured")
+ v := func(conf monitoringv1alpha1.PushoverConfig) error {
+ if conf.UserKey == nil && conf.UserKeyFile == nil {
+ return errors.New("one of 'userKey' or 'userKeyFile' must be configured")
}
- if config.Token == nil && config.TokenFile == nil {
- return fmt.Errorf("one of token or tokenFile must be configured")
+ if conf.Token == nil && conf.TokenFile == nil {
+ return errors.New("one of 'token' or 'tokenFile' must be configured")
}
- if config.HTML != nil && *config.HTML && config.Monospace != nil && *config.Monospace {
- return fmt.Errorf("html and monospace options are mutually exclusive")
+ if conf.HTML != nil && *conf.HTML && conf.Monospace != nil && *conf.Monospace {
+ return errors.New("'html' and 'monospace' options are mutually exclusive")
}
- if config.URL != "" {
- if err := validation.ValidateTemplateURL(config.URL); err != nil {
- return fmt.Errorf("[%d]: url: %w", i, err)
+ if conf.URL != "" {
+ if err := validation.ValidateTemplateURL(conf.URL); err != nil {
+ return fmt.Errorf("invalid 'url': %w", err)
}
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'pushoverConfigs'[%d]: %w", i, err)
}
}
return nil
}
-func validateSnsConfigs(configs []monitoringv1alpha1.SNSConfig) error {
- for i, config := range configs {
- if (ptr.Deref(config.TargetARN, "") == "") != (ptr.Deref(config.TopicARN, "") == "") != (ptr.Deref(config.PhoneNumber, "") == "") {
- return fmt.Errorf("[%d]: must provide either a targetARN, topicARN, or phoneNumber for SNS config", i)
+func validateSNSConfigs(configs []monitoringv1alpha1.SNSConfig) error {
+ v := func(conf monitoringv1alpha1.SNSConfig) error {
+ if (ptr.Deref(conf.TargetARN, "") == "") != (ptr.Deref(conf.TopicARN, "") == "") != (ptr.Deref(conf.PhoneNumber, "") == "") {
+ return errors.New("must provide one of 'targetARN', 'topicARN', or 'phoneNumber'")
}
- if config.ApiURL != nil {
- if err := validation.ValidateTemplateURL(*config.ApiURL); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ if conf.ApiURL != nil {
+ if err := validation.ValidateTemplateURL(*conf.ApiURL); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
}
+
+ return nil
}
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'snsConfigs'[%d]: %w", i, err)
+ }
+ }
+
return nil
}
func validateTelegramConfigs(configs []monitoringv1alpha1.TelegramConfig) error {
- for i, config := range configs {
- if config.BotToken == nil && config.BotTokenFile == nil {
- return fmt.Errorf("[%d]: mandatory field 'botToken' or 'botTokenfile' is empty", i)
+ v := func(conf monitoringv1alpha1.TelegramConfig) error {
+ if conf.BotToken == nil && conf.BotTokenFile == nil {
+ return errors.New("mandatory field botToken or botTokenfile is empty")
}
- if config.BotToken != nil && config.BotTokenFile != nil {
- return fmt.Errorf("[%d]: only one of 'botToken' or 'botTokenfile' must be configured", i)
+ if conf.BotToken != nil && conf.BotTokenFile != nil {
+ return errors.New("only one of 'botToken' or 'botTokenfile' must be configured")
}
- if config.ChatID == 0 {
- return fmt.Errorf("[%d]: mandatory field %q is empty", i, "chatID")
+ if conf.ChatID == 0 {
+ return errors.New("mandatory field 'chatID' is empty")
}
- if err := validation.ValidateURLPtr((*string)(config.APIURL)); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ if err := validation.ValidateURLPtr((*string)(conf.APIURL)); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'telegramConfigs'[%d]: %w", i, err)
}
}
@@ -400,13 +505,21 @@ func validateTelegramConfigs(configs []monitoringv1alpha1.TelegramConfig) error
}
func validateWebexConfigs(configs []monitoringv1alpha1.WebexConfig) error {
- for i, config := range configs {
- if err := validation.ValidateURLPtr((*string)(config.APIURL)); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ v := func(conf monitoringv1alpha1.WebexConfig) error {
+ if err := validation.ValidateURLPtr((*string)(conf.APIURL)); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
+ }
+
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'webexConfigs'[%d]: %w", i, err)
}
}
@@ -414,9 +527,17 @@ func validateWebexConfigs(configs []monitoringv1alpha1.WebexConfig) error {
}
func validateMSTeamsConfigs(configs []monitoringv1alpha1.MSTeamsConfig) error {
- for _, config := range configs {
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ v := func(conf monitoringv1alpha1.MSTeamsConfig) error {
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'msteamsConfigs'[%d]: %w", i, err)
}
}
@@ -424,9 +545,17 @@ func validateMSTeamsConfigs(configs []monitoringv1alpha1.MSTeamsConfig) error {
}
func validateMSTeamsV2Configs(configs []monitoringv1alpha1.MSTeamsV2Config) error {
- for _, config := range configs {
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ v := func(conf monitoringv1alpha1.MSTeamsV2Config) error {
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'msteamsv2Configs'[%d]: %w", i, err)
}
}
diff --git a/pkg/alertmanager/validation/v1beta1/validation.go b/pkg/alertmanager/validation/v1beta1/validation.go
index b4e297a8ea8..e8e08db436e 100644
--- a/pkg/alertmanager/validation/v1beta1/validation.go
+++ b/pkg/alertmanager/validation/v1beta1/validation.go
@@ -54,64 +54,68 @@ func validateReceivers(receivers []monitoringv1beta1.Receiver) (map[string]struc
}
receiverNames[receiver.Name] = struct{}{}
- if err = validatePagerDutyConfigs(receiver.PagerDutyConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'pagerDutyConfig' - receiver %s: %w", receiver.Name, err)
+ receiverValidationFailedFormat := func(err error) (map[string]struct{}, error) {
+ return nil, fmt.Errorf("failed to validate receiver %q: %w", receiver.Name, err)
}
if err := validateOpsGenieConfigs(receiver.OpsGenieConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'opsGenieConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
+ }
+
+ if err = validatePagerDutyConfigs(receiver.PagerDutyConfigs); err != nil {
+ return receiverValidationFailedFormat(err)
+ }
+
+ if err := validateDiscordConfigs(receiver.DiscordConfigs); err != nil {
+ return receiverValidationFailedFormat(err)
}
if err := validateSlackConfigs(receiver.SlackConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'slackConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validateWebhookConfigs(receiver.WebhookConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'webhookConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validateWechatConfigs(receiver.WeChatConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'weChatConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validateEmailConfig(receiver.EmailConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'emailConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validateVictorOpsConfigs(receiver.VictorOpsConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'victorOpsConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validatePushoverConfigs(receiver.PushoverConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'pushOverConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
- if err := validateSnsConfigs(receiver.SNSConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'snsConfig' - receiver %s: %w", receiver.Name, err)
+ if err := validateSNSConfigs(receiver.SNSConfigs); err != nil {
+ return receiverValidationFailedFormat(err)
}
if err := validateTelegramConfigs(receiver.TelegramConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'telegramConfig' - receiver %s: %w", receiver.Name, err)
- }
-
- if err := validateDiscordConfigs(receiver.DiscordConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'discordConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validateWebexConfigs(receiver.WebexConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'webexConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
if err := validateMSTeamsConfigs(receiver.MSTeamsConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'msteamsConfig' - receiver %s: %w", receiver.Name, err)
+ return receiverValidationFailedFormat(err)
}
- if err := validateRocketchatConfigs(receiver.RocketChatConfigs); err != nil {
- return nil, fmt.Errorf("failed to validate 'rocketchatConfig' - receiver %s: %w", receiver.Name, err)
+ if err := validateMSTeamsV2Configs(receiver.MSTeamsV2Configs); err != nil {
+ return receiverValidationFailedFormat(err)
}
- if err := validateMSTeamsV2Configs(receiver.MSTeamsV2Configs); err != nil {
- return nil, fmt.Errorf("failed to validate 'msteamsv2Config' - receiver %s: %w", receiver.Name, err)
+ if err := validateRocketchatConfigs(receiver.RocketChatConfigs); err != nil {
+ return receiverValidationFailedFormat(err)
}
}
@@ -119,14 +123,14 @@ func validateReceivers(receivers []monitoringv1beta1.Receiver) (map[string]struc
}
func validatePagerDutyConfigs(configs []monitoringv1beta1.PagerDutyConfig) error {
- for i, conf := range configs {
+ v := func(conf monitoringv1beta1.PagerDutyConfig) error {
if err := validation.ValidateURLPtr((*string)(conf.URL)); err != nil {
- return fmt.Errorf("[%d]: url: %w", i, err)
+ return fmt.Errorf("invalid 'url': %w", err)
}
if conf.ClientURL != nil && *conf.ClientURL != "" {
if err := validation.ValidateTemplateURL(*conf.ClientURL); err != nil {
- return fmt.Errorf("[%d]: clientURL: %w", i, err)
+ return fmt.Errorf("invalid 'clientURL': %w", err)
}
}
@@ -137,7 +141,7 @@ func validatePagerDutyConfigs(configs []monitoringv1beta1.PagerDutyConfig) error
for j, lc := range conf.PagerDutyLinkConfigs {
if lc.Href != nil && *lc.Href != "" {
if err := validation.ValidateTemplateURL(*lc.Href); err != nil {
- return fmt.Errorf("[%d]: pagerDutyLinkConfigs[%d]: href: %w", i, j, err)
+ return fmt.Errorf("'pagerDutyLinkConfigs'[%d]: invalid 'href': %w", j, err)
}
}
}
@@ -145,30 +149,47 @@ func validatePagerDutyConfigs(configs []monitoringv1beta1.PagerDutyConfig) error
for j, ic := range conf.PagerDutyImageConfigs {
if ic.Href != nil && *ic.Href != "" {
if err := validation.ValidateTemplateURL(*ic.Href); err != nil {
- return fmt.Errorf("[%d]: pagerDutyImageConfigs[%d]: href: %w", i, j, err)
+ return fmt.Errorf("'pagerDutyImageConfigs'[%d]: invalid 'href': %w", j, err)
}
}
}
if err := conf.HTTPConfig.Validate(); err != nil {
- return err
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'pagerdutyConfigs'[%d]: %w", i, err)
}
}
+
return nil
}
func validateOpsGenieConfigs(configs []monitoringv1beta1.OpsGenieConfig) error {
- for i, config := range configs {
- if err := config.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ v := func(conf monitoringv1beta1.OpsGenieConfig) error {
+ if err := conf.Validate(); err != nil {
+ return err
}
- if err := validation.ValidateURLPtr((*string)(config.APIURL)); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ if err := validation.ValidateURLPtr((*string)(conf.APIURL)); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'opsgenieConfigs'[%d]: %w", i, err)
}
}
@@ -176,30 +197,47 @@ func validateOpsGenieConfigs(configs []monitoringv1beta1.OpsGenieConfig) error {
}
func validateSlackConfigs(configs []monitoringv1beta1.SlackConfig) error {
- for _, config := range configs {
- if err := config.Validate(); err != nil {
+ v := func(conf monitoringv1beta1.SlackConfig) error {
+ if err := conf.Validate(); err != nil {
return err
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'slackConfigs'[%d]: %w", i, err)
}
}
+
return nil
}
func validateWebhookConfigs(configs []monitoringv1beta1.WebhookConfig) error {
- for i, config := range configs {
- if config.URL == nil && config.URLSecret == nil {
- return fmt.Errorf("[%d]: one of 'url' or 'urlSecret' must be specified", i)
+ v := func(conf monitoringv1beta1.WebhookConfig) error {
+ if conf.URL == nil && conf.URLSecret == nil {
+ return errors.New("one of 'url' or 'urlSecret' must be specified")
}
- if err := validation.ValidateTemplateURLPtr(config.URL); err != nil {
- return fmt.Errorf("[%d]: url: %w", i, err)
+ if err := validation.ValidateTemplateURLPtr(conf.URL); err != nil {
+ return fmt.Errorf("invalid 'url': %w", err)
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'webhookConfigs'[%d]: %w", i, err)
}
}
@@ -207,13 +245,21 @@ func validateWebhookConfigs(configs []monitoringv1beta1.WebhookConfig) error {
}
func validateWechatConfigs(configs []monitoringv1beta1.WeChatConfig) error {
- for i, config := range configs {
- if err := validation.ValidateURLPtr((*string)(config.APIURL)); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ v := func(conf monitoringv1beta1.WeChatConfig) error {
+ if err := validation.ValidateURLPtr((*string)(conf.APIURL)); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'wechatConfigs'[%d]: %w", i, err)
}
}
@@ -221,36 +267,44 @@ func validateWechatConfigs(configs []monitoringv1beta1.WeChatConfig) error {
}
func validateEmailConfig(configs []monitoringv1beta1.EmailConfig) error {
- for _, config := range configs {
- if ptr.Deref(config.To, "") == "" {
+ v := func(conf monitoringv1beta1.EmailConfig) error {
+ if ptr.Deref(conf.To, "") == "" {
return errors.New("missing 'to' address")
}
- if ptr.Deref(config.Smarthost, "") != "" {
- _, _, err := net.SplitHostPort(*config.Smarthost)
+ if ptr.Deref(conf.Smarthost, "") != "" {
+ _, _, err := net.SplitHostPort(*conf.Smarthost)
if err != nil {
- return fmt.Errorf("invalid 'smarthost' %s: %w", *config.Smarthost, err)
+ return fmt.Errorf("invalid 'smarthost' %q: %w", *conf.Smarthost, err)
}
}
- if config.Headers != nil {
+ if conf.Headers != nil {
// Header names are case-insensitive, check for collisions.
normalizedHeaders := map[string]struct{}{}
- for _, v := range config.Headers {
- normalized := strings.ToLower(v.Key)
+ for _, h := range conf.Headers {
+ normalized := strings.ToLower(h.Key)
if _, ok := normalizedHeaders[normalized]; ok {
return fmt.Errorf("duplicate header %q", normalized)
}
normalizedHeaders[normalized] = struct{}{}
}
}
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'emailConfigs'[%d]: %w", i, err)
+ }
}
+
return nil
}
func validateVictorOpsConfigs(configs []monitoringv1beta1.VictorOpsConfig) error {
- for i, config := range configs {
-
+ v := func(conf monitoringv1beta1.VictorOpsConfig) error {
// from https://github.com/prometheus/alertmanager/blob/a7f9fdadbecbb7e692d2cd8d3334e3d6de1602e1/config/notifiers.go#L497
reservedFields := map[string]struct{}{
"routing_key": {},
@@ -262,96 +316,130 @@ func validateVictorOpsConfigs(configs []monitoringv1beta1.VictorOpsConfig) error
"entity_state": {},
}
- if len(config.CustomFields) > 0 {
- for _, v := range config.CustomFields {
- if _, ok := reservedFields[v.Key]; ok {
- return fmt.Errorf("usage of reserved word %q is not allowed in custom fields", v.Key)
+ if len(conf.CustomFields) > 0 {
+ for _, f := range conf.CustomFields {
+ if _, ok := reservedFields[f.Key]; ok {
+ return fmt.Errorf("usage of reserved word %q is not allowed in custom fields", f.Key)
}
}
}
- if config.RoutingKey == "" {
+ if conf.RoutingKey == "" {
return errors.New("missing 'routingKey' key")
}
- if err := validation.ValidateURLPtr((*string)(config.APIURL)); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ if err := validation.ValidateURLPtr((*string)(conf.APIURL)); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
}
+
+ return nil
}
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'victoropsConfigs'[%d]: %w", i, err)
+ }
+ }
+
return nil
}
func validatePushoverConfigs(configs []monitoringv1beta1.PushoverConfig) error {
- for i, config := range configs {
- if config.UserKey == nil && config.UserKeyFile == nil {
- return fmt.Errorf("one of userKey or userKeyFile must be configured")
+ v := func(conf monitoringv1beta1.PushoverConfig) error {
+ if conf.UserKey == nil && conf.UserKeyFile == nil {
+ return errors.New("one of 'userKey' or 'userKeyFile' must be configured")
}
- if config.Token == nil && config.TokenFile == nil {
- return fmt.Errorf("one of token or tokenFile must be configured")
+ if conf.Token == nil && conf.TokenFile == nil {
+ return errors.New("one of 'token' or 'tokenFile' must be configured")
}
- if config.HTML != nil && *config.HTML && config.Monospace != nil && *config.Monospace {
- return fmt.Errorf("html and monospace options are mutually exclusive")
+ if conf.HTML != nil && *conf.HTML && conf.Monospace != nil && *conf.Monospace {
+ return errors.New("'html' and 'monospace' options are mutually exclusive")
}
- if config.URL != "" {
- if err := validation.ValidateTemplateURL(config.URL); err != nil {
- return fmt.Errorf("[%d]: url: %w", i, err)
+ if conf.URL != "" {
+ if err := validation.ValidateTemplateURL(conf.URL); err != nil {
+ return fmt.Errorf("invalid 'url': %w", err)
}
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'pushoverConfigs'[%d]: %w", i, err)
}
}
return nil
}
-func validateSnsConfigs(configs []monitoringv1beta1.SNSConfig) error {
- for i, config := range configs {
- if (ptr.Deref(config.TargetARN, "") == "") != (ptr.Deref(config.TopicARN, "") == "") != (ptr.Deref(config.PhoneNumber, "") == "") {
- return fmt.Errorf("[%d]: must provide either a targetARN, topicARN, or phoneNumber for SNS config", i)
+func validateSNSConfigs(configs []monitoringv1beta1.SNSConfig) error {
+ v := func(conf monitoringv1beta1.SNSConfig) error {
+ if (ptr.Deref(conf.TargetARN, "") == "") != (ptr.Deref(conf.TopicARN, "") == "") != (ptr.Deref(conf.PhoneNumber, "") == "") {
+ return errors.New("must provide one of 'targetARN', 'topicARN', or 'phoneNumber'")
}
- if config.ApiURL != nil {
- if err := validation.ValidateTemplateURL(*config.ApiURL); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ if conf.ApiURL != nil {
+ if err := validation.ValidateTemplateURL(*conf.ApiURL); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
}
+
+ return nil
}
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'snsConfigs'[%d]: %w", i, err)
+ }
+ }
+
return nil
}
func validateTelegramConfigs(configs []monitoringv1beta1.TelegramConfig) error {
- for i, config := range configs {
- if config.BotToken == nil && config.BotTokenFile == nil {
- return fmt.Errorf("[%d]: mandatory field botToken or botTokenfile is empty", i)
+ v := func(conf monitoringv1beta1.TelegramConfig) error {
+ if conf.BotToken == nil && conf.BotTokenFile == nil {
+ return errors.New("mandatory field botToken or botTokenfile is empty")
}
- if config.BotToken != nil && config.BotTokenFile != nil {
- return fmt.Errorf("[%d]: only one of 'botToken' or 'botTokenfile' must be configured", i)
+ if conf.BotToken != nil && conf.BotTokenFile != nil {
+ return errors.New("only one of 'botToken' or 'botTokenfile' must be configured")
}
- if config.ChatID == 0 {
- return fmt.Errorf("[%d]: mandatory field %q is empty", i, "chatID")
+ if conf.ChatID == 0 {
+ return errors.New("mandatory field 'chatID' is empty")
}
- if err := validation.ValidateURLPtr((*string)(config.APIURL)); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ if err := validation.ValidateURLPtr((*string)(conf.APIURL)); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'telegramConfigs'[%d]: %w", i, err)
}
}
@@ -359,13 +447,21 @@ func validateTelegramConfigs(configs []monitoringv1beta1.TelegramConfig) error {
}
func validateWebexConfigs(configs []monitoringv1beta1.WebexConfig) error {
- for i, config := range configs {
- if err := validation.ValidateURLPtr((*string)(config.APIURL)); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ v := func(conf monitoringv1beta1.WebexConfig) error {
+ if err := validation.ValidateURLPtr((*string)(conf.APIURL)); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
+ }
+
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'webexConfigs'[%d]: %w", i, err)
}
}
@@ -373,9 +469,17 @@ func validateWebexConfigs(configs []monitoringv1beta1.WebexConfig) error {
}
func validateDiscordConfigs(configs []monitoringv1beta1.DiscordConfig) error {
- for _, config := range configs {
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ v := func(conf monitoringv1beta1.DiscordConfig) error {
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'discordConfigs'[%d]: %w", i, err)
}
}
@@ -383,31 +487,39 @@ func validateDiscordConfigs(configs []monitoringv1beta1.DiscordConfig) error {
}
func validateRocketchatConfigs(configs []monitoringv1beta1.RocketChatConfig) error {
- for i, config := range configs {
- if err := validation.ValidateURLPtr((*string)(config.APIURL)); err != nil {
- return fmt.Errorf("[%d]: apiURL: %w", i, err)
+ v := func(conf monitoringv1beta1.RocketChatConfig) error {
+ if err := validation.ValidateURLPtr((*string)(conf.APIURL)); err != nil {
+ return fmt.Errorf("invalid 'apiURL': %w", err)
}
- if err := validation.ValidateTemplateURLPtr(config.IconURL); err != nil {
- return fmt.Errorf("[%d]: invalid 'iconURL': %w", i, err)
+ if err := validation.ValidateTemplateURLPtr(conf.IconURL); err != nil {
+ return fmt.Errorf("invalid 'iconURL': %w", err)
}
- if err := validation.ValidateTemplateURLPtr(config.ImageURL); err != nil {
- return fmt.Errorf("[%d]: invalid 'imageURL': %w", i, err)
+ if err := validation.ValidateTemplateURLPtr(conf.ImageURL); err != nil {
+ return fmt.Errorf("invalid 'imageURL': %w", err)
}
- if err := validation.ValidateTemplateURLPtr(config.ThumbURL); err != nil {
- return fmt.Errorf("[%d]: invalid 'thumbURL': %w", i, err)
+ if err := validation.ValidateTemplateURLPtr(conf.ThumbURL); err != nil {
+ return fmt.Errorf("invalid 'thumbURL': %w", err)
}
- for j, a := range config.Actions {
+ for j, a := range conf.Actions {
if err := validation.ValidateTemplateURLPtr(a.URL); err != nil {
- return fmt.Errorf("%d: actions[%d]: invalid 'url': %w", i, j, err)
+ return fmt.Errorf("'actions'[%d]: invalid 'url': %w", j, err)
}
}
- if err := config.HTTPConfig.Validate(); err != nil {
- return fmt.Errorf("[%d]: %w", i, err)
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'rocketchatConfigs'[%d]: %w", i, err)
}
}
@@ -415,9 +527,17 @@ func validateRocketchatConfigs(configs []monitoringv1beta1.RocketChatConfig) err
}
func validateMSTeamsConfigs(configs []monitoringv1beta1.MSTeamsConfig) error {
- for _, config := range configs {
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ v := func(conf monitoringv1beta1.MSTeamsConfig) error {
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'msteamsConfigs'[%d]: %w", i, err)
}
}
@@ -425,9 +545,17 @@ func validateMSTeamsConfigs(configs []monitoringv1beta1.MSTeamsConfig) error {
}
func validateMSTeamsV2Configs(configs []monitoringv1beta1.MSTeamsV2Config) error {
- for _, config := range configs {
- if err := config.HTTPConfig.Validate(); err != nil {
- return err
+ v := func(conf monitoringv1beta1.MSTeamsV2Config) error {
+ if err := conf.HTTPConfig.Validate(); err != nil {
+ return fmt.Errorf("'httpConfig': %w", err)
+ }
+
+ return nil
+ }
+
+ for i, conf := range configs {
+ if err := v(conf); err != nil {
+ return fmt.Errorf("'msteamsv2Configs'[%d]: %w", i, err)
}
}
@@ -445,7 +573,7 @@ func validateRoute(r *monitoringv1beta1.Route, receivers, timeIntervals map[stri
if r.Receiver == "" {
if topLevelRoute {
- return fmt.Errorf("root route must define a receiver")
+ return errors.New("root route must define a receiver")
}
} else {
if _, found := receivers[r.Receiver]; !found {
diff --git a/pkg/alertmanager/validation/v1beta1/validation_test.go b/pkg/alertmanager/validation/v1beta1/validation_test.go
index 4339221fd6c..ace64293bea 100644
--- a/pkg/alertmanager/validation/v1beta1/validation_test.go
+++ b/pkg/alertmanager/validation/v1beta1/validation_test.go
@@ -84,7 +84,7 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
Type: "a",
Text: "b",
URL: "www.test.com",
- Name: ptr.To("c"),
+ Name: new("c"),
ConfirmField: &monitoringv1beta1.SlackConfirmationField{
Text: "d",
},
@@ -172,8 +172,8 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
Name: "different",
EmailConfigs: []monitoringv1beta1.EmailConfig{
{
- To: ptr.To("a"),
- Smarthost: ptr.To("invalid"),
+ To: new("a"),
+ Smarthost: new("invalid"),
},
},
},
@@ -287,7 +287,7 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
Name: "creds",
Key: "user",
},
- TokenFile: ptr.To("/path/token_file"),
+ TokenFile: new("/path/token_file"),
},
},
},
@@ -312,7 +312,7 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
Name: "creds",
Key: "user",
},
- UserKeyFile: ptr.To("/path/user_key_file"),
+ UserKeyFile: new("/path/user_key_file"),
},
},
},
@@ -365,8 +365,8 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
Name: "creds",
Key: "token",
},
- HTML: ptr.To(true),
- Monospace: ptr.To(true),
+ HTML: new(true),
+ Monospace: new(true),
},
},
},
@@ -395,7 +395,7 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
Name: "creds",
Key: "token",
},
- HTML: ptr.To(true),
+ HTML: new(true),
URL: "http://%>= v2.39.0 or PrometheusAgent >= v2.54.0.
// +optional
OutOfOrderTimeWindow *Duration `json:"outOfOrderTimeWindow,omitempty"`
+
+ // staleSeriesCompactionThreshold configures the trigger point for compacting
+ // stale series from memory into persistent blocks and removing those stale
+ // series from memory.
+ //
+ // The threshold is a number between 0.0 and 1.0. It represents the ratio of
+ // stale series in memory to the total series in memory. The stale series
+ // compaction is triggered when this ratio crosses the configured threshold.
+ // It may not trigger the stale series compaction if the usual head compaction
+ // is about to happen soon.
+ //
+ // If set to 0, stale series compaction is disabled.
+ //
+ // It requires Prometheus >= v3.10.0.
+ // +optional
+ StaleSeriesCompactionThreshold *resource.Quantity `json:"staleSeriesCompactionThreshold,omitempty"`
+}
+
+// Validate semantically validates the given TSDBSpec.
+func (ts *TSDBSpec) Validate() error {
+ if ts == nil || ts.StaleSeriesCompactionThreshold == nil {
+ return nil
+ }
+ v := ts.StaleSeriesCompactionThreshold.AsApproximateFloat64()
+ if v < 0 || v > 1 {
+ return fmt.Errorf("`staleSeriesCompactionThreshold` must be between 0 and 1. The current value is %s", ts.StaleSeriesCompactionThreshold.String())
+ }
+
+ return nil
}
type Exemplars struct {
@@ -2507,11 +2537,11 @@ func (c *SafeAuthorization) Validate() error {
}
if strings.ToLower(strings.TrimSpace(c.Type)) == "basic" {
- return errors.New("authorization type cannot be set to \"basic\", use \"basicAuth\" instead")
+ return errors.New("'authorization' type cannot be set to \"basic\", use \"basicAuth\" instead")
}
if c.Credentials == nil {
- return errors.New("authorization credentials are required")
+ return errors.New("'authorization' credentials are required")
}
return nil
@@ -2681,6 +2711,26 @@ type OTLPConfig struct {
// It requires Prometheus >= v3.6.0.
// +optional
PromoteScopeMetadata *bool `json:"promoteScopeMetadata,omitempty"` // nolint:kubeapilinter
+
+ // labelNameUnderscoreSanitization controls whether to enable prepending of 'key_' to labels starting with '_'.
+ // Reserved labels starting with '__' are not modified.
+ // This is only relevant when translation_strategy uses underscore escaping (e.g., "UnderscoreEscapingWithSuffixes" or "UnderscoreEscapingWithoutSuffixes").
+ //
+ // Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+ //
+ // It requires Prometheus >= v3.8.0.
+ // +optional
+ LabelNameUnderscoreSanitization *bool `json:"labelNameUnderscoreSanitization,omitempty"` // nolint:kubeapilinter
+
+ // labelNamePreserveMultipleUnderscores enables preserving of multiple consecutive underscores in label names when translation_strategy uses
+ // underscore escaping.
+ // When true (default), multiple consecutive underscores are preserved during label name sanitization.
+ //
+ // Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+ //
+ // It requires Prometheus >= v3.8.0.
+ // +optional
+ LabelNamePreserveMultipleUnderscores *bool `json:"labelNamePreserveMultipleUnderscores,omitempty"` // nolint:kubeapilinter
}
// Validate semantically validates the given OTLPConfig section.
diff --git a/pkg/apis/monitoring/v1/prometheus_types_test.go b/pkg/apis/monitoring/v1/prometheus_types_test.go
new file mode 100644
index 00000000000..9d2129b6560
--- /dev/null
+++ b/pkg/apis/monitoring/v1/prometheus_types_test.go
@@ -0,0 +1,91 @@
+// Copyright The prometheus-operator Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package v1
+
+import (
+ "testing"
+
+ "k8s.io/apimachinery/pkg/api/resource"
+)
+
+func TestValidateTSDBSpec(t *testing.T) {
+ for _, tc := range []struct {
+ name string
+ config *TSDBSpec
+ err bool
+ }{
+ {
+ name: "TSDBSpec nil",
+ config: nil,
+ err: false,
+ },
+ {
+ name: "StaleSeriesCompactionThreshold nil",
+ config: &TSDBSpec{
+ StaleSeriesCompactionThreshold: nil,
+ },
+ err: false,
+ },
+ {
+ name: "StaleSeriesCompactionThreshold simple value",
+ config: &TSDBSpec{
+ StaleSeriesCompactionThreshold: func(v resource.Quantity) *resource.Quantity { return &v }(resource.MustParse("0.5")),
+ },
+ err: false,
+ },
+ {
+ name: "StaleSeriesCompactionThreshold > 1",
+ config: &TSDBSpec{
+ StaleSeriesCompactionThreshold: resource.NewQuantity(10, resource.DecimalSI),
+ },
+ err: true,
+ },
+ {
+ name: "StaleSeriesCompactionThreshold < 0",
+ config: &TSDBSpec{
+ StaleSeriesCompactionThreshold: resource.NewQuantity(-1, resource.DecimalSI),
+ },
+ err: true,
+ },
+ {
+ name: "StaleSeriesCompactionThreshold == 0",
+ config: &TSDBSpec{
+ StaleSeriesCompactionThreshold: resource.NewQuantity(0, resource.DecimalSI),
+ },
+ err: false,
+ },
+ {
+ name: "StaleSeriesCompactionThreshold == 1",
+ config: &TSDBSpec{
+ StaleSeriesCompactionThreshold: resource.NewQuantity(1, resource.DecimalSI),
+ },
+ err: false,
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ err := tc.config.Validate()
+ if tc.err {
+ if err == nil {
+ t.Fatal("expected error but got none")
+ }
+ return
+ }
+
+ if err != nil {
+ t.Fatalf("expected no error but got: %s", err)
+ }
+ })
+ }
+}
diff --git a/pkg/apis/monitoring/v1/tls_types.go b/pkg/apis/monitoring/v1/tls_types.go
index 8a977fc593e..8ebc0b0c70e 100644
--- a/pkg/apis/monitoring/v1/tls_types.go
+++ b/pkg/apis/monitoring/v1/tls_types.go
@@ -81,25 +81,17 @@ func (c *TLSConfig) Validate() error {
return nil
}
- if !reflect.ValueOf(c.CA).IsZero() {
- if c.CAFile != "" {
- return fmt.Errorf("cannot specify both 'caFile' and 'ca'")
- }
+ if err := c.innerValidate(); err != nil {
+ return err
+ }
- if err := c.CA.Validate(); err != nil {
- return fmt.Errorf("ca: %w", err)
- }
+ if !reflect.ValueOf(c.CA).IsZero() && c.CAFile != "" {
+ return fmt.Errorf("cannot specify both 'caFile' and 'ca'")
}
hasCert := !reflect.ValueOf(c.Cert).IsZero()
- if hasCert {
- if c.CertFile != "" {
- return fmt.Errorf("cannot specify both 'certFile' and 'cert'")
- }
-
- if err := c.Cert.Validate(); err != nil {
- return fmt.Errorf("cert: %w", err)
- }
+ if hasCert && c.CertFile != "" {
+ return fmt.Errorf("cannot specify both 'certFile' and 'cert'")
}
if c.KeyFile != "" && c.KeySecret != nil {
@@ -117,10 +109,6 @@ func (c *TLSConfig) Validate() error {
return fmt.Errorf("cannot specify client key without client cert")
}
- if c.MaxVersion != nil && c.MinVersion != nil && strings.Compare(string(*c.MaxVersion), string(*c.MinVersion)) == -1 {
- return fmt.Errorf("'maxVersion' must greater than or equal to 'minVersion'")
- }
-
return nil
}
@@ -166,6 +154,22 @@ func (c *SafeTLSConfig) Validate() error {
return nil
}
+ if err := c.innerValidate(); err != nil {
+ return err
+ }
+
+ if c.Cert != (SecretOrConfigMap{}) && c.KeySecret == nil {
+ return fmt.Errorf("client cert specified without client key")
+ }
+
+ if c.KeySecret != nil && c.Cert == (SecretOrConfigMap{}) {
+ return fmt.Errorf("client key specified without client cert")
+ }
+
+ return nil
+}
+
+func (c *SafeTLSConfig) innerValidate() error {
if c.CA != (SecretOrConfigMap{}) {
if err := c.CA.Validate(); err != nil {
return fmt.Errorf("ca %s: %w", c.CA.String(), err)
@@ -178,14 +182,6 @@ func (c *SafeTLSConfig) Validate() error {
}
}
- if c.Cert != (SecretOrConfigMap{}) && c.KeySecret == nil {
- return fmt.Errorf("client cert specified without client key")
- }
-
- if c.KeySecret != nil && c.Cert == (SecretOrConfigMap{}) {
- return fmt.Errorf("client key specified without client cert")
- }
-
if c.MaxVersion != nil && c.MinVersion != nil && strings.Compare(string(*c.MaxVersion), string(*c.MinVersion)) == -1 {
return fmt.Errorf("maxVersion must more than or equal to minVersion")
}
diff --git a/pkg/apis/monitoring/v1/types.go b/pkg/apis/monitoring/v1/types.go
index 520efc21f5d..12a2799f175 100644
--- a/pkg/apis/monitoring/v1/types.go
+++ b/pkg/apis/monitoring/v1/types.go
@@ -547,14 +547,17 @@ type LabelName string
//
// +k8s:openapi-gen=true
type Endpoint struct {
- // port defines the name of the Service port which this endpoint refers to.
+ // port defines the name of the Service port which this endpoint refers to
+ // (e.g. `.spec.ports[].name`).
//
// It takes precedence over `targetPort`.
// +optional
Port string `json:"port,omitempty"`
- // targetPort defines the name or number of the target port of the `Pod` object behind the
- // Service. The port must be specified with the container's port property.
+ // targetPort defines the name or number of a container port on Pods selected
+ // by the Service.
+ // If a name, it matches against `.spec.containers[].ports[].name` of the Pods.
+ // If a number, it matches against `.spec.containers[].ports[].containerPort` of the Pods.
//
// +optional
TargetPort *intstr.IntOrString `json:"targetPort,omitempty"`
@@ -653,6 +656,10 @@ type AttachMetadata struct {
// The Prometheus service account must have the `list` and `watch`
// permissions on the `Nodes` objects.
//
+ // Node metadata labels are not automatically added to scraped metrics. They are
+ // exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ // with relabeling configuration.
+ //
// +optional
Node *bool `json:"node,omitempty"` // nolint:kubeapilinter
}
@@ -673,9 +680,8 @@ type OAuth2 struct {
// tokenUrl defines the URL to fetch the token from.
//
- // +kubebuilder:validation:MinLength=1
// +required
- TokenURL string `json:"tokenUrl"`
+ TokenURL URL `json:"tokenUrl"`
// scopes defines the OAuth2 scopes used for the token request.
//
@@ -707,20 +713,24 @@ func (o *OAuth2) Validate() error {
return nil
}
- if o.TokenURL == "" {
+ if string(o.TokenURL) == "" {
return errors.New("OAuth2 tokenURL must be specified")
}
if o.ClientID == (SecretOrConfigMap{}) {
- return errors.New("OAuth2 clientID must be specified")
+ return errors.New("OAuth2 'clientID' must be specified")
}
if err := o.ClientID.Validate(); err != nil {
- return fmt.Errorf("invalid OAuth2 clientID: %w", err)
+ return fmt.Errorf("invalid OAuth2 'clientID': %w", err)
}
if err := o.TLSConfig.Validate(); err != nil {
- return fmt.Errorf("invalid OAuth2 tlsConfig: %w", err)
+ return fmt.Errorf("invalid OAuth2 'tlsConfig': %w", err)
+ }
+
+ if err := o.ProxyConfig.Validate(); err != nil {
+ return fmt.Errorf("invalid OAuth2 proxyConfig: %w", err)
}
return nil
@@ -1078,10 +1088,8 @@ func (tc *TracingConfig) Validate() error {
}
if tc.SamplingFraction != nil {
- min, _ := resource.ParseQuantity("0")
- max, _ := resource.ParseQuantity("1")
-
- if tc.SamplingFraction.Cmp(min) < 0 || tc.SamplingFraction.Cmp(max) > 0 {
+ v := tc.SamplingFraction.AsApproximateFloat64()
+ if v < 0 || v > 1 {
return fmt.Errorf("`samplingFraction` must be between 0 and 1")
}
}
diff --git a/pkg/apis/monitoring/v1/types_test.go b/pkg/apis/monitoring/v1/types_test.go
index 19e24404dba..5ba0b8510de 100644
--- a/pkg/apis/monitoring/v1/types_test.go
+++ b/pkg/apis/monitoring/v1/types_test.go
@@ -505,6 +505,55 @@ func TestValidateOAuth2(t *testing.T) {
},
err: false,
},
+ {
+ name: "valid ProxyConfig with proxyUrl",
+ config: &OAuth2{
+ ClientID: SecretOrConfigMap{Secret: &v1.SecretKeySelector{}},
+ ClientSecret: v1.SecretKeySelector{},
+ TokenURL: "http://tokenurl.org",
+ ProxyConfig: ProxyConfig{
+ ProxyURL: new("http://proxy.example.com:8080"),
+ },
+ },
+ err: false,
+ },
+ {
+ name: "valid ProxyConfig with proxyFromEnvironment",
+ config: &OAuth2{
+ ClientID: SecretOrConfigMap{Secret: &v1.SecretKeySelector{}},
+ ClientSecret: v1.SecretKeySelector{},
+ TokenURL: "http://tokenurl.org",
+ ProxyConfig: ProxyConfig{
+ ProxyFromEnvironment: new(true),
+ },
+ },
+ err: false,
+ },
+ {
+ name: "invalid ProxyConfig with proxyFromEnvironment and proxyUrl",
+ config: &OAuth2{
+ ClientID: SecretOrConfigMap{Secret: &v1.SecretKeySelector{}},
+ ClientSecret: v1.SecretKeySelector{},
+ TokenURL: "http://tokenurl.org",
+ ProxyConfig: ProxyConfig{
+ ProxyFromEnvironment: new(true),
+ ProxyURL: new("http://proxy.example.com:8080"),
+ },
+ },
+ err: true,
+ },
+ {
+ name: "invalid ProxyConfig with noProxy but no proxyUrl",
+ config: &OAuth2{
+ ClientID: SecretOrConfigMap{Secret: &v1.SecretKeySelector{}},
+ ClientSecret: v1.SecretKeySelector{},
+ TokenURL: "http://tokenurl.org",
+ ProxyConfig: ProxyConfig{
+ NoProxy: new("localhost"),
+ },
+ },
+ err: true,
+ },
} {
t.Run(tc.name, func(t *testing.T) {
err := tc.config.Validate()
diff --git a/pkg/apis/monitoring/v1/zz_generated.deepcopy.go b/pkg/apis/monitoring/v1/zz_generated.deepcopy.go
index 83a1648ce0e..088d0e84fb6 100644
--- a/pkg/apis/monitoring/v1/zz_generated.deepcopy.go
+++ b/pkg/apis/monitoring/v1/zz_generated.deepcopy.go
@@ -2073,6 +2073,16 @@ func (in *OTLPConfig) DeepCopyInto(out *OTLPConfig) {
*out = new(bool)
**out = **in
}
+ if in.LabelNameUnderscoreSanitization != nil {
+ in, out := &in.LabelNameUnderscoreSanitization, &out.LabelNameUnderscoreSanitization
+ *out = new(bool)
+ **out = **in
+ }
+ if in.LabelNamePreserveMultipleUnderscores != nil {
+ in, out := &in.LabelNamePreserveMultipleUnderscores, &out.LabelNamePreserveMultipleUnderscores
+ *out = new(bool)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OTLPConfig.
@@ -3829,6 +3839,11 @@ func (in *TSDBSpec) DeepCopyInto(out *TSDBSpec) {
*out = new(Duration)
**out = **in
}
+ if in.StaleSeriesCompactionThreshold != nil {
+ in, out := &in.StaleSeriesCompactionThreshold, &out.StaleSeriesCompactionThreshold
+ x := (*in).DeepCopy()
+ *out = &x
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TSDBSpec.
diff --git a/pkg/apis/monitoring/v1alpha1/alertmanager_config_types.go b/pkg/apis/monitoring/v1alpha1/alertmanager_config_types.go
index 15e5c710de2..4e388169c5b 100644
--- a/pkg/apis/monitoring/v1alpha1/alertmanager_config_types.go
+++ b/pkg/apis/monitoring/v1alpha1/alertmanager_config_types.go
@@ -21,12 +21,12 @@ import (
"fmt"
"strings"
- monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
-
v1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
+
+ monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
const (
@@ -607,6 +607,13 @@ type WebhookConfig struct {
// It requires Alertmanager >= v0.28.0.
// +optional
Timeout *monitoringv1.Duration `json:"timeout,omitempty"`
+ // payload define custom payload to be sent to the webhook endpoint.
+ // This is an advanced configuration option that allows you
+ // to define a custom payload using Go templates.
+ // It requires Alertmanager >= v0.32.0.
+ // +kubebuilder:validation:MinLength=1
+ // +optional
+ Payload *string `json:"payload,omitempty"`
}
// OpsGenieConfig configures notifications via OpsGenie.
diff --git a/pkg/apis/monitoring/v1alpha1/prometheusagent_types.go b/pkg/apis/monitoring/v1alpha1/prometheusagent_types.go
index 4898e2ca4e1..159ddc97741 100644
--- a/pkg/apis/monitoring/v1alpha1/prometheusagent_types.go
+++ b/pkg/apis/monitoring/v1alpha1/prometheusagent_types.go
@@ -15,9 +15,10 @@
package v1alpha1
import (
- monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
+
+ monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
const (
diff --git a/pkg/apis/monitoring/v1alpha1/scrapeconfig_types.go b/pkg/apis/monitoring/v1alpha1/scrapeconfig_types.go
index d017fc72653..301b346ddfb 100644
--- a/pkg/apis/monitoring/v1alpha1/scrapeconfig_types.go
+++ b/pkg/apis/monitoring/v1alpha1/scrapeconfig_types.go
@@ -15,10 +15,11 @@
package v1alpha1
import (
- v1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
+
+ v1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
const (
diff --git a/pkg/apis/monitoring/v1alpha1/validation.go b/pkg/apis/monitoring/v1alpha1/validation.go
index c45f6548a86..2f24b43c656 100644
--- a/pkg/apis/monitoring/v1alpha1/validation.go
+++ b/pkg/apis/monitoring/v1alpha1/validation.go
@@ -31,16 +31,16 @@ func (hc *HTTPConfig) Validate() error {
}
if (hc.BasicAuth != nil || hc.OAuth2 != nil) && (hc.BearerTokenSecret != nil) {
- return fmt.Errorf("at most one of basicAuth, oauth2, bearerTokenSecret must be configured")
+ return fmt.Errorf("at most one of 'basicAuth', 'oauth2' and 'bearerTokenSecret' must be configured")
}
if hc.Authorization != nil {
if hc.BearerTokenSecret != nil {
- return fmt.Errorf("authorization is not compatible with bearerTokenSecret")
+ return fmt.Errorf("'authorization' is not compatible with 'bearerTokenSecret'")
}
if hc.BasicAuth != nil || hc.OAuth2 != nil {
- return fmt.Errorf("at most one of basicAuth, oauth2 & authorization must be configured")
+ return fmt.Errorf("at most one of 'basicAuth', 'oauth2' and 'authorization' must be configured")
}
if err := hc.Authorization.Validate(); err != nil {
@@ -50,7 +50,7 @@ func (hc *HTTPConfig) Validate() error {
if hc.OAuth2 != nil {
if hc.BasicAuth != nil {
- return fmt.Errorf("at most one of basicAuth, oauth2 & authorization must be configured")
+ return fmt.Errorf("at most one of 'basicAuth', 'oauth2' and 'authorization' must be configured")
}
if err := hc.OAuth2.Validate(); err != nil {
@@ -395,15 +395,15 @@ func (r *OpsGenieConfigResponder) Validate() error {
// Validate ensures SlackAction is valid.
func (sa *SlackAction) Validate() error {
if sa.Type == "" {
- return errors.New("missing type in Slack action configuration")
+ return errors.New("missing 'type' in Slack action configuration")
}
if sa.Text == "" {
- return errors.New("missing text in Slack action configuration")
+ return errors.New("missing 'text' in Slack action configuration")
}
if sa.URL == "" && ptr.Deref(sa.Name, "") == "" {
- return errors.New("missing name or url in Slack action configuration")
+ return errors.New("missing 'name' or 'url' in Slack action configuration")
}
if sa.ConfirmField != nil {
@@ -435,7 +435,7 @@ func (sc *SlackConfig) Validate() error {
// Validate ensures SlackConfirmationField is valid.
func (scf *SlackConfirmationField) Validate() error {
if scf.Text == "" {
- return errors.New("missing text in Slack confirmation configuration")
+ return errors.New("missing 'text' in Slack confirmation configuration")
}
return nil
}
@@ -443,11 +443,11 @@ func (scf *SlackConfirmationField) Validate() error {
// Validate ensures SlackField is valid
func (sf *SlackField) Validate() error {
if sf.Title == "" {
- return errors.New("missing title in Slack field configuration")
+ return errors.New("missing 'title' in Slack field configuration")
}
if sf.Value == "" {
- return errors.New("missing value in Slack field configuration")
+ return errors.New("missing 'value' in Slack field configuration")
}
return nil
diff --git a/pkg/apis/monitoring/v1alpha1/validation_test.go b/pkg/apis/monitoring/v1alpha1/validation_test.go
index a2408be44b2..e74e7db24f7 100644
--- a/pkg/apis/monitoring/v1alpha1/validation_test.go
+++ b/pkg/apis/monitoring/v1alpha1/validation_test.go
@@ -18,9 +18,10 @@ import (
"reflect"
"testing"
- monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/utils/ptr"
+
+ monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
func TestTimeRange_Parse(t *testing.T) {
diff --git a/pkg/apis/monitoring/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/monitoring/v1alpha1/zz_generated.deepcopy.go
index 06c47dc06b2..1efb0d86ae5 100644
--- a/pkg/apis/monitoring/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/monitoring/v1alpha1/zz_generated.deepcopy.go
@@ -3725,6 +3725,11 @@ func (in *WebhookConfig) DeepCopyInto(out *WebhookConfig) {
*out = new(v1.Duration)
**out = **in
}
+ if in.Payload != nil {
+ in, out := &in.Payload, &out.Payload
+ *out = new(string)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookConfig.
diff --git a/pkg/apis/monitoring/v1beta1/alertmanager_config_types.go b/pkg/apis/monitoring/v1beta1/alertmanager_config_types.go
index 05187889e2e..ecd0ab52ea3 100644
--- a/pkg/apis/monitoring/v1beta1/alertmanager_config_types.go
+++ b/pkg/apis/monitoring/v1beta1/alertmanager_config_types.go
@@ -21,12 +21,12 @@ import (
"fmt"
"strings"
- monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
-
v1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
+
+ monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
const (
@@ -580,6 +580,13 @@ type WebhookConfig struct {
// It requires Alertmanager >= v0.28.0.
// +optional
Timeout *monitoringv1.Duration `json:"timeout,omitempty"`
+ // payload define custom payload to be sent to the webhook endpoint.
+ // This is an advanced configuration option that allows you
+ // to define a custom payload using Go templates.
+ // It requires Alertmanager >= v0.32.0.
+ // +kubebuilder:validation:MinLength=1
+ // +optional
+ Payload *string `json:"payload,omitempty"`
}
// OpsGenieConfig configures notifications via OpsGenie.
diff --git a/pkg/apis/monitoring/v1beta1/conversion_from.go b/pkg/apis/monitoring/v1beta1/conversion_from.go
index b99c64398ab..5e6f42458b8 100644
--- a/pkg/apis/monitoring/v1beta1/conversion_from.go
+++ b/pkg/apis/monitoring/v1beta1/conversion_from.go
@@ -414,6 +414,7 @@ func convertWebhookConfigFrom(in v1alpha1.WebhookConfig) WebhookConfig {
HTTPConfig: convertHTTPConfigFrom(in.HTTPConfig),
MaxAlerts: in.MaxAlerts,
Timeout: in.Timeout,
+ Payload: in.Payload,
}
}
diff --git a/pkg/apis/monitoring/v1beta1/conversion_to.go b/pkg/apis/monitoring/v1beta1/conversion_to.go
index 98019eb81a1..22912191c1a 100644
--- a/pkg/apis/monitoring/v1beta1/conversion_to.go
+++ b/pkg/apis/monitoring/v1beta1/conversion_to.go
@@ -410,6 +410,7 @@ func convertWebhookConfigTo(in WebhookConfig) v1alpha1.WebhookConfig {
HTTPConfig: convertHTTPConfigTo(in.HTTPConfig),
MaxAlerts: in.MaxAlerts,
Timeout: in.Timeout,
+ Payload: in.Payload,
}
}
diff --git a/pkg/apis/monitoring/v1beta1/validation.go b/pkg/apis/monitoring/v1beta1/validation.go
index e559e421613..f89403a273d 100644
--- a/pkg/apis/monitoring/v1beta1/validation.go
+++ b/pkg/apis/monitoring/v1beta1/validation.go
@@ -31,16 +31,16 @@ func (hc *HTTPConfig) Validate() error {
}
if (hc.BasicAuth != nil || hc.OAuth2 != nil) && (hc.BearerTokenSecret != nil) {
- return fmt.Errorf("at most one of basicAuth, oauth2, bearerTokenSecret must be configured")
+ return fmt.Errorf("at most one of 'basicAuth', 'oauth2' and 'bearerTokenSecret' must be configured")
}
if hc.Authorization != nil {
if hc.BearerTokenSecret != nil {
- return fmt.Errorf("authorization is not compatible with bearerTokenSecret")
+ return fmt.Errorf("'authorization' is not compatible with 'bearerTokenSecret'")
}
if hc.BasicAuth != nil || hc.OAuth2 != nil {
- return fmt.Errorf("at most one of basicAuth, oauth2 & authorization must be configured")
+ return fmt.Errorf("at most one of 'basicAuth', 'oauth2' and 'authorization' must be configured")
}
if err := hc.Authorization.Validate(); err != nil {
@@ -50,7 +50,7 @@ func (hc *HTTPConfig) Validate() error {
if hc.OAuth2 != nil {
if hc.BasicAuth != nil {
- return fmt.Errorf("at most one of basicAuth, oauth2 & authorization must be configured")
+ return fmt.Errorf("at most one of 'basicAuth', 'oauth2' and 'authorization' must be configured")
}
if err := hc.OAuth2.Validate(); err != nil {
@@ -392,15 +392,15 @@ func (r *OpsGenieConfigResponder) Validate() error {
// Validate ensures SlackAction is valid.
func (sa *SlackAction) Validate() error {
if sa.Type == "" {
- return errors.New("missing type in Slack action configuration")
+ return errors.New("missing 'type' in Slack action configuration")
}
if sa.Text == "" {
- return errors.New("missing text in Slack action configuration")
+ return errors.New("missing 'text' in Slack action configuration")
}
if sa.URL == "" && ptr.Deref(sa.Name, "") == "" {
- return errors.New("missing name or url in Slack action configuration")
+ return errors.New("missing 'name' or 'url' in Slack action configuration")
}
if sa.ConfirmField != nil {
@@ -432,7 +432,7 @@ func (sc *SlackConfig) Validate() error {
// Validate ensures SlackConfirmationField is valid.
func (scf *SlackConfirmationField) Validate() error {
if scf.Text == "" {
- return errors.New("missing text in Slack confirmation configuration")
+ return errors.New("missing 'text' in Slack confirmation configuration")
}
return nil
}
@@ -440,11 +440,11 @@ func (scf *SlackConfirmationField) Validate() error {
// Validate ensures SlackField is valid
func (sf *SlackField) Validate() error {
if sf.Title == "" {
- return errors.New("missing title in Slack field configuration")
+ return errors.New("missing 'title' in Slack field configuration")
}
if sf.Value == "" {
- return errors.New("missing value in Slack field configuration")
+ return errors.New("missing 'value' in Slack field configuration")
}
return nil
diff --git a/pkg/apis/monitoring/v1beta1/validation_test.go b/pkg/apis/monitoring/v1beta1/validation_test.go
index 8ac2e2d978f..5d72caf2971 100644
--- a/pkg/apis/monitoring/v1beta1/validation_test.go
+++ b/pkg/apis/monitoring/v1beta1/validation_test.go
@@ -18,9 +18,10 @@ import (
"reflect"
"testing"
- monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/utils/ptr"
+
+ monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
func TestTimeRange_Parse(t *testing.T) {
diff --git a/pkg/apis/monitoring/v1beta1/zz_generated.deepcopy.go b/pkg/apis/monitoring/v1beta1/zz_generated.deepcopy.go
index 1301991c4cc..f0669cb5198 100644
--- a/pkg/apis/monitoring/v1beta1/zz_generated.deepcopy.go
+++ b/pkg/apis/monitoring/v1beta1/zz_generated.deepcopy.go
@@ -1801,6 +1801,11 @@ func (in *WebhookConfig) DeepCopyInto(out *WebhookConfig) {
*out = new(v1.Duration)
**out = **in
}
+ if in.Payload != nil {
+ in, out := &in.Payload, &out.Payload
+ *out = new(string)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookConfig.
diff --git a/pkg/client/applyconfiguration/monitoring/v1/attachmetadata.go b/pkg/client/applyconfiguration/monitoring/v1/attachmetadata.go
index d8a949c9b3a..bda48eb98ee 100644
--- a/pkg/client/applyconfiguration/monitoring/v1/attachmetadata.go
+++ b/pkg/client/applyconfiguration/monitoring/v1/attachmetadata.go
@@ -24,6 +24,10 @@ type AttachMetadataApplyConfiguration struct {
//
// The Prometheus service account must have the `list` and `watch`
// permissions on the `Nodes` objects.
+ //
+ // Node metadata labels are not automatically added to scraped metrics. They are
+ // exposed as `__meta_kubernetes_node_*` labels and can be copied to timeseries
+ // with relabeling configuration.
Node *bool `json:"node,omitempty"`
}
diff --git a/pkg/client/applyconfiguration/monitoring/v1/endpoint.go b/pkg/client/applyconfiguration/monitoring/v1/endpoint.go
index 013c91619cb..fdccf3e7ead 100644
--- a/pkg/client/applyconfiguration/monitoring/v1/endpoint.go
+++ b/pkg/client/applyconfiguration/monitoring/v1/endpoint.go
@@ -28,12 +28,15 @@ import (
// Endpoint defines an endpoint serving Prometheus metrics to be scraped by
// Prometheus.
type EndpointApplyConfiguration struct {
- // port defines the name of the Service port which this endpoint refers to.
+ // port defines the name of the Service port which this endpoint refers to
+ // (e.g. `.spec.ports[].name`).
//
// It takes precedence over `targetPort`.
Port *string `json:"port,omitempty"`
- // targetPort defines the name or number of the target port of the `Pod` object behind the
- // Service. The port must be specified with the container's port property.
+ // targetPort defines the name or number of a container port on Pods selected
+ // by the Service.
+ // If a name, it matches against `.spec.containers[].ports[].name` of the Pods.
+ // If a number, it matches against `.spec.containers[].ports[].containerPort` of the Pods.
TargetPort *intstr.IntOrString `json:"targetPort,omitempty"`
// path defines the HTTP path from which to scrape for metrics.
//
diff --git a/pkg/client/applyconfiguration/monitoring/v1/oauth2.go b/pkg/client/applyconfiguration/monitoring/v1/oauth2.go
index 7c6425caece..6c70ff8f14f 100644
--- a/pkg/client/applyconfiguration/monitoring/v1/oauth2.go
+++ b/pkg/client/applyconfiguration/monitoring/v1/oauth2.go
@@ -17,6 +17,7 @@
package v1
import (
+ monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
corev1 "k8s.io/api/core/v1"
)
@@ -32,7 +33,7 @@ type OAuth2ApplyConfiguration struct {
// client's secret.
ClientSecret *corev1.SecretKeySelector `json:"clientSecret,omitempty"`
// tokenUrl defines the URL to fetch the token from.
- TokenURL *string `json:"tokenUrl,omitempty"`
+ TokenURL *monitoringv1.URL `json:"tokenUrl,omitempty"`
// scopes defines the OAuth2 scopes used for the token request.
Scopes []string `json:"scopes,omitempty"`
// endpointParams configures the HTTP parameters to append to the token
@@ -71,7 +72,7 @@ func (b *OAuth2ApplyConfiguration) WithClientSecret(value corev1.SecretKeySelect
// WithTokenURL sets the TokenURL field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the TokenURL field is set to the value of the last call.
-func (b *OAuth2ApplyConfiguration) WithTokenURL(value string) *OAuth2ApplyConfiguration {
+func (b *OAuth2ApplyConfiguration) WithTokenURL(value monitoringv1.URL) *OAuth2ApplyConfiguration {
b.TokenURL = &value
return b
}
diff --git a/pkg/client/applyconfiguration/monitoring/v1/otlpconfig.go b/pkg/client/applyconfiguration/monitoring/v1/otlpconfig.go
index 07ebe48ce65..02ae8289065 100644
--- a/pkg/client/applyconfiguration/monitoring/v1/otlpconfig.go
+++ b/pkg/client/applyconfiguration/monitoring/v1/otlpconfig.go
@@ -54,6 +54,22 @@ type OTLPConfigApplyConfiguration struct {
// As per the OpenTelemetry specification, the aforementioned scope metadata should be identifying, i.e. made into metric labels.
// It requires Prometheus >= v3.6.0.
PromoteScopeMetadata *bool `json:"promoteScopeMetadata,omitempty"`
+ // labelNameUnderscoreSanitization controls whether to enable prepending of 'key_' to labels starting with '_'.
+ // Reserved labels starting with '__' are not modified.
+ // This is only relevant when translation_strategy uses underscore escaping (e.g., "UnderscoreEscapingWithSuffixes" or "UnderscoreEscapingWithoutSuffixes").
+ //
+ // Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+ //
+ // It requires Prometheus >= v3.8.0.
+ LabelNameUnderscoreSanitization *bool `json:"labelNameUnderscoreSanitization,omitempty"`
+ // labelNamePreserveMultipleUnderscores enables preserving of multiple consecutive underscores in label names when translation_strategy uses
+ // underscore escaping.
+ // When true (default), multiple consecutive underscores are preserved during label name sanitization.
+ //
+ // Notice: This one has no impact if `nameEscapingScheme` is `AllowUTF8`.
+ //
+ // It requires Prometheus >= v3.8.0.
+ LabelNamePreserveMultipleUnderscores *bool `json:"labelNamePreserveMultipleUnderscores,omitempty"`
}
// OTLPConfigApplyConfiguration constructs a declarative configuration of the OTLPConfig type for use with
@@ -121,3 +137,19 @@ func (b *OTLPConfigApplyConfiguration) WithPromoteScopeMetadata(value bool) *OTL
b.PromoteScopeMetadata = &value
return b
}
+
+// WithLabelNameUnderscoreSanitization sets the LabelNameUnderscoreSanitization field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the LabelNameUnderscoreSanitization field is set to the value of the last call.
+func (b *OTLPConfigApplyConfiguration) WithLabelNameUnderscoreSanitization(value bool) *OTLPConfigApplyConfiguration {
+ b.LabelNameUnderscoreSanitization = &value
+ return b
+}
+
+// WithLabelNamePreserveMultipleUnderscores sets the LabelNamePreserveMultipleUnderscores field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the LabelNamePreserveMultipleUnderscores field is set to the value of the last call.
+func (b *OTLPConfigApplyConfiguration) WithLabelNamePreserveMultipleUnderscores(value bool) *OTLPConfigApplyConfiguration {
+ b.LabelNamePreserveMultipleUnderscores = &value
+ return b
+}
diff --git a/pkg/client/applyconfiguration/monitoring/v1/prometheusspec.go b/pkg/client/applyconfiguration/monitoring/v1/prometheusspec.go
index 72d3b42f27e..df0277e2fa5 100644
--- a/pkg/client/applyconfiguration/monitoring/v1/prometheusspec.go
+++ b/pkg/client/applyconfiguration/monitoring/v1/prometheusspec.go
@@ -43,11 +43,8 @@ type PrometheusSpecApplyConfiguration struct {
// retentionSize defines the maximum number of bytes used by the Prometheus data.
RetentionSize *monitoringv1.ByteSize `json:"retentionSize,omitempty"`
// shardRetentionPolicy defines the retention policy for the Prometheus shards.
- // (Alpha) Using this field requires the 'PrometheusShardRetentionPolicy' feature gate to be enabled.
//
- // The final goals for this feature can be seen at https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/proposals/202310-shard-autoscaling.md#graceful-scale-down-of-prometheus-servers,
- // however, the feature is not yet fully implemented in this PR. The limitation being:
- // * Retention duration is not settable, for now, shards are retained forever.
+ // (Beta) Using this mode requires the `PrometheusShardRetentionPolicy` feature gate (enabled by default).
ShardRetentionPolicy *ShardRetentionPolicyApplyConfiguration `json:"shardRetentionPolicy,omitempty"`
// disableCompaction when true, the Prometheus compaction is disabled.
// When `spec.thanos.objectStorageConfig` or `spec.objectStorageConfigFile` are defined, the operator automatically
diff --git a/pkg/client/applyconfiguration/monitoring/v1/remotereadspec.go b/pkg/client/applyconfiguration/monitoring/v1/remotereadspec.go
index eb16390a246..6720cee0eac 100644
--- a/pkg/client/applyconfiguration/monitoring/v1/remotereadspec.go
+++ b/pkg/client/applyconfiguration/monitoring/v1/remotereadspec.go
@@ -28,7 +28,9 @@ import (
// from a remote endpoint.
type RemoteReadSpecApplyConfiguration struct {
// url defines the URL of the endpoint to query from.
- URL *string `json:"url,omitempty"`
+ //
+ // It must use the HTTP or HTTPS scheme.
+ URL *monitoringv1.URL `json:"url,omitempty"`
// name of the remote read queue, it must be unique if specified. The
// name is used in metrics and logging in order to differentiate read
// configurations.
@@ -94,7 +96,7 @@ func RemoteReadSpec() *RemoteReadSpecApplyConfiguration {
// WithURL sets the URL field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the URL field is set to the value of the last call.
-func (b *RemoteReadSpecApplyConfiguration) WithURL(value string) *RemoteReadSpecApplyConfiguration {
+func (b *RemoteReadSpecApplyConfiguration) WithURL(value monitoringv1.URL) *RemoteReadSpecApplyConfiguration {
b.URL = &value
return b
}
diff --git a/pkg/client/applyconfiguration/monitoring/v1/tsdbspec.go b/pkg/client/applyconfiguration/monitoring/v1/tsdbspec.go
index 98ce9b380f5..f15d53da37f 100644
--- a/pkg/client/applyconfiguration/monitoring/v1/tsdbspec.go
+++ b/pkg/client/applyconfiguration/monitoring/v1/tsdbspec.go
@@ -18,6 +18,7 @@ package v1
import (
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
+ resource "k8s.io/apimachinery/pkg/api/resource"
)
// TSDBSpecApplyConfiguration represents a declarative configuration of the TSDBSpec type for use
@@ -34,6 +35,20 @@ type TSDBSpecApplyConfiguration struct {
//
// It requires Prometheus >= v2.39.0 or PrometheusAgent >= v2.54.0.
OutOfOrderTimeWindow *monitoringv1.Duration `json:"outOfOrderTimeWindow,omitempty"`
+ // staleSeriesCompactionThreshold configures the trigger point for compacting
+ // stale series from memory into persistent blocks and removing those stale
+ // series from memory.
+ //
+ // The threshold is a number between 0.0 and 1.0. It represents the ratio of
+ // stale series in memory to the total series in memory. The stale series
+ // compaction is triggered when this ratio crosses the configured threshold.
+ // It may not trigger the stale series compaction if the usual head compaction
+ // is about to happen soon.
+ //
+ // If set to 0, stale series compaction is disabled.
+ //
+ // It requires Prometheus >= v3.10.0.
+ StaleSeriesCompactionThreshold *resource.Quantity `json:"staleSeriesCompactionThreshold,omitempty"`
}
// TSDBSpecApplyConfiguration constructs a declarative configuration of the TSDBSpec type for use with
@@ -49,3 +64,11 @@ func (b *TSDBSpecApplyConfiguration) WithOutOfOrderTimeWindow(value monitoringv1
b.OutOfOrderTimeWindow = &value
return b
}
+
+// WithStaleSeriesCompactionThreshold sets the StaleSeriesCompactionThreshold field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the StaleSeriesCompactionThreshold field is set to the value of the last call.
+func (b *TSDBSpecApplyConfiguration) WithStaleSeriesCompactionThreshold(value resource.Quantity) *TSDBSpecApplyConfiguration {
+ b.StaleSeriesCompactionThreshold = &value
+ return b
+}
diff --git a/pkg/client/applyconfiguration/monitoring/v1alpha1/webhookconfig.go b/pkg/client/applyconfiguration/monitoring/v1alpha1/webhookconfig.go
index a52bbef348d..e4349e710b4 100644
--- a/pkg/client/applyconfiguration/monitoring/v1alpha1/webhookconfig.go
+++ b/pkg/client/applyconfiguration/monitoring/v1alpha1/webhookconfig.go
@@ -46,6 +46,11 @@ type WebhookConfigApplyConfiguration struct {
// before failing the request and allowing it to be retried.
// It requires Alertmanager >= v0.28.0.
Timeout *monitoringv1.Duration `json:"timeout,omitempty"`
+ // payload define custom payload to be sent to the webhook endpoint.
+ // This is an advanced configuration option that allows you
+ // to define a custom payload using Go templates.
+ // It requires Alertmanager >= v0.32.0.
+ Payload *string `json:"payload,omitempty"`
}
// WebhookConfigApplyConfiguration constructs a declarative configuration of the WebhookConfig type for use with
@@ -101,3 +106,11 @@ func (b *WebhookConfigApplyConfiguration) WithTimeout(value monitoringv1.Duratio
b.Timeout = &value
return b
}
+
+// WithPayload sets the Payload field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Payload field is set to the value of the last call.
+func (b *WebhookConfigApplyConfiguration) WithPayload(value string) *WebhookConfigApplyConfiguration {
+ b.Payload = &value
+ return b
+}
diff --git a/pkg/client/applyconfiguration/monitoring/v1beta1/webhookconfig.go b/pkg/client/applyconfiguration/monitoring/v1beta1/webhookconfig.go
index 32fcfdf0f73..67026422ee4 100644
--- a/pkg/client/applyconfiguration/monitoring/v1beta1/webhookconfig.go
+++ b/pkg/client/applyconfiguration/monitoring/v1beta1/webhookconfig.go
@@ -45,6 +45,11 @@ type WebhookConfigApplyConfiguration struct {
// before failing the request and allowing it to be retried.
// It requires Alertmanager >= v0.28.0.
Timeout *v1.Duration `json:"timeout,omitempty"`
+ // payload define custom payload to be sent to the webhook endpoint.
+ // This is an advanced configuration option that allows you
+ // to define a custom payload using Go templates.
+ // It requires Alertmanager >= v0.32.0.
+ Payload *string `json:"payload,omitempty"`
}
// WebhookConfigApplyConfiguration constructs a declarative configuration of the WebhookConfig type for use with
@@ -100,3 +105,11 @@ func (b *WebhookConfigApplyConfiguration) WithTimeout(value v1.Duration) *Webhoo
b.Timeout = &value
return b
}
+
+// WithPayload sets the Payload field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Payload field is set to the value of the last call.
+func (b *WebhookConfigApplyConfiguration) WithPayload(value string) *WebhookConfigApplyConfiguration {
+ b.Payload = &value
+ return b
+}
diff --git a/pkg/client/go.mod b/pkg/client/go.mod
index 328095de209..5a9f12e22c2 100644
--- a/pkg/client/go.mod
+++ b/pkg/client/go.mod
@@ -1,60 +1,59 @@
module github.com/prometheus-operator/prometheus-operator/pkg/client
-go 1.25.0
+go 1.26.0
require (
- github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.91.0
- k8s.io/api v0.35.2
- k8s.io/apiextensions-apiserver v0.35.2
- k8s.io/apimachinery v0.35.2
- k8s.io/client-go v0.35.2
- sigs.k8s.io/structured-merge-diff/v6 v6.3.2
+ github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.92.1
+ k8s.io/api v0.36.2
+ k8s.io/apiextensions-apiserver v0.36.2
+ k8s.io/apimachinery v0.36.2
+ k8s.io/client-go v0.36.2
+ sigs.k8s.io/structured-merge-diff/v6 v6.4.0
)
require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
- github.com/fxamacker/cbor/v2 v2.9.0 // indirect
+ github.com/fxamacker/cbor/v2 v2.9.2 // indirect
github.com/go-logr/logr v1.4.3 // indirect
- github.com/go-openapi/jsonpointer v0.22.5 // indirect
- github.com/go-openapi/jsonreference v0.21.5 // indirect
- github.com/go-openapi/swag v0.25.5 // indirect
- github.com/go-openapi/swag/cmdutils v0.25.5 // indirect
- github.com/go-openapi/swag/conv v0.25.5 // indirect
- github.com/go-openapi/swag/fileutils v0.25.5 // indirect
- github.com/go-openapi/swag/jsonname v0.25.5 // indirect
- github.com/go-openapi/swag/jsonutils v0.25.5 // indirect
- github.com/go-openapi/swag/loading v0.25.5 // indirect
- github.com/go-openapi/swag/mangling v0.25.5 // indirect
- github.com/go-openapi/swag/netutils v0.25.5 // indirect
- github.com/go-openapi/swag/stringutils v0.25.5 // indirect
- github.com/go-openapi/swag/typeutils v0.25.5 // indirect
- github.com/go-openapi/swag/yamlutils v0.25.5 // indirect
+ github.com/go-openapi/jsonpointer v0.23.1 // indirect
+ github.com/go-openapi/jsonreference v0.21.6 // indirect
+ github.com/go-openapi/swag v0.26.1 // indirect
+ github.com/go-openapi/swag/cmdutils v0.26.1 // indirect
+ github.com/go-openapi/swag/conv v0.26.1 // indirect
+ github.com/go-openapi/swag/fileutils v0.26.1 // indirect
+ github.com/go-openapi/swag/jsonname v0.26.1 // indirect
+ github.com/go-openapi/swag/jsonutils v0.26.1 // indirect
+ github.com/go-openapi/swag/loading v0.26.1 // indirect
+ github.com/go-openapi/swag/mangling v0.26.1 // indirect
+ github.com/go-openapi/swag/netutils v0.26.1 // indirect
+ github.com/go-openapi/swag/stringutils v0.26.1 // indirect
+ github.com/go-openapi/swag/typeutils v0.26.1 // indirect
+ github.com/go-openapi/swag/yamlutils v0.26.1 // indirect
github.com/google/gnostic-models v0.7.1 // indirect
- github.com/google/go-cmp v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
- golang.org/x/net v0.52.0 // indirect
+ golang.org/x/net v0.56.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect
- golang.org/x/sys v0.42.0 // indirect
- golang.org/x/term v0.41.0 // indirect
- golang.org/x/text v0.35.0 // indirect
+ golang.org/x/sys v0.46.0 // indirect
+ golang.org/x/term v0.44.0 // indirect
+ golang.org/x/text v0.38.0 // indirect
golang.org/x/time v0.15.0 // indirect
- google.golang.org/protobuf v1.36.11 // indirect
+ google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/klog/v2 v2.140.0 // indirect
- k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect
- k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect
- sigs.k8s.io/controller-runtime v0.23.3 // indirect
+ k8s.io/kube-openapi v0.0.0-20260603220949-865597e52e25 // indirect
+ k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 // indirect
+ sigs.k8s.io/controller-runtime v0.24.1 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
diff --git a/pkg/client/go.sum b/pkg/client/go.sum
index 516d190ca00..c31ff9d354f 100644
--- a/pkg/client/go.sum
+++ b/pkg/client/go.sum
@@ -5,44 +5,44 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
-github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
-github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
+github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78=
+github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
-github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA=
-github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0=
-github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE=
-github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=
-github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU=
-github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA=
-github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c=
-github.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
-github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g=
-github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k=
-github.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk=
-github.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc=
-github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo=
-github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU=
-github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo=
-github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo=
-github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU=
-github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g=
-github.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw=
-github.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY=
-github.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU=
-github.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14=
-github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M=
-github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII=
-github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E=
-github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc=
-github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ=
-github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ=
-github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag=
-github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM=
-github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM=
-github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
+github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4=
+github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY=
+github.com/go-openapi/jsonreference v0.21.6 h1:NZ5nGfnaM1n4I43Xjm1e5/M2GjOwQwndQz22uhxwD+Y=
+github.com/go-openapi/jsonreference v0.21.6/go.mod h1:xzbgtQ3ZbWxvET3AxdzCJlJt6vkovbf+IfSPJjD0tUY=
+github.com/go-openapi/swag v0.26.1 h1:l5sVEyVpwj+DDYeZyo7wQI/Ebn/mKYIyGB/pFwAfGoQ=
+github.com/go-openapi/swag v0.26.1/go.mod h1:yNY38BbIVthxbkDtq1UHBCGasBqjakW3lCR6ANzdBEw=
+github.com/go-openapi/swag/cmdutils v0.26.1 h1:f2iE1ijYaJ3nuu5PaEMx3zpEhzhZFgivCJObWEObLIQ=
+github.com/go-openapi/swag/cmdutils v0.26.1/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM=
+github.com/go-openapi/swag/conv v0.26.1 h1:slr5FVkg9Wc3Y5zcwenD8Sd/PQ94b2I/QJI7N7KTBpg=
+github.com/go-openapi/swag/conv v0.26.1/go.mod h1:mvQXgPptZk9GTrFgGwWvT4q+dN+zQej9JfmGwnipz1A=
+github.com/go-openapi/swag/fileutils v0.26.1 h1:K1XCM2CGhfNsc6YDt6v7Q5+1e59rftYWdcu/isZhvFw=
+github.com/go-openapi/swag/fileutils v0.26.1/go.mod h1:mYUgxQAKX4ShS3qvvySx+/9yrlUnDhjiD1CalaQl8lQ=
+github.com/go-openapi/swag/jsonname v0.26.1 h1:VReupaV6WxlAsCn0e4DUfgV6bPmINnPpyJDLqSfNPcE=
+github.com/go-openapi/swag/jsonname v0.26.1/go.mod h1:OvdW6BoWoj33pTfi7x9vFrgmT+fk7aw0BRwvCE0YOuc=
+github.com/go-openapi/swag/jsonutils v0.26.1 h1:2hdBfFkHg+7Wrz2VsCbeyR6hzkRDs7AztnMR2u84yOY=
+github.com/go-openapi/swag/jsonutils v0.26.1/go.mod h1:U+RMJH3wa+6BRiphuRtIyI8fW9HPFqFQ4sHk2oRx0UQ=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1 h1:1CD7NiLLb/TXl3tOnFYU4b+mNfb5rtgHkaA+q7RMYYQ=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1/go.mod h1:ZWafc8nMdYzTE3uYY6W86f0n46+IF0g4uUyRhJw/kXc=
+github.com/go-openapi/swag/loading v0.26.1 h1:E9K4wqXeROlhjFQ13K9zMz6ojFGXIggGe+ad1odrK9w=
+github.com/go-openapi/swag/loading v0.26.1/go.mod h1:3qvRIlWzWdq1HvmldwmuJ2ohpcAryN6xVt2OTKd0/7E=
+github.com/go-openapi/swag/mangling v0.26.1 h1:gpYI4WuPKFJJVjV5cDLGlDVJhFIxYjQc7yN5eEb4CqM=
+github.com/go-openapi/swag/mangling v0.26.1/go.mod h1:POETDH01hqAdASXfw7ISEd9bCOE6xBHOt8NHmGZRmYM=
+github.com/go-openapi/swag/netutils v0.26.1 h1:BNctoc39WTAUMxyAs355fExOPzMZtPbZ0ZZ1Am2FR5M=
+github.com/go-openapi/swag/netutils v0.26.1/go.mod h1:y02vByhZhQPAVwOX+0KipXFZ/hUbk6G/Enhf5rGaOkQ=
+github.com/go-openapi/swag/stringutils v0.26.1 h1:f88uYyTso7TnHrKM/bUBsQ5e2wKf37cpgo6pvbzd9yU=
+github.com/go-openapi/swag/stringutils v0.26.1/go.mod h1:Sc6d3bU8fgk5AyZR8/8jEQ+Is/Ald+TD/IIggPN8UJk=
+github.com/go-openapi/swag/typeutils v0.26.1 h1:yg42FgMzRR6PVQ3M3qHz1s+Y6/P4HoJ3cBarXa3OVnU=
+github.com/go-openapi/swag/typeutils v0.26.1/go.mod h1:VfnV+oUtSP2vCSCn2aJgnr8OevUYemyIzzS1VOzS10o=
+github.com/go-openapi/swag/yamlutils v0.26.1 h1:0TSLK+lXs9vfIhAWzBeI/lOzEnIoot6WTCO1aAeWFTk=
+github.com/go-openapi/swag/yamlutils v0.26.1/go.mod h1:7W5b7PRX9MxwL7TjeG7H8HkyBGRsIDRObhyMWFgBI2M=
+github.com/go-openapi/testify/enable/yaml/v2 v2.5.1 h1:q9NtHwK4qHF7yZziBPvZyv7zWAIk8ok88Gh2mR6Jpc8=
+github.com/go-openapi/testify/enable/yaml/v2 v2.5.1/go.mod h1:JW0MXIotCYps/XsgJnG3a8Q7rE5xAiBwoOD5OfaIQBk=
+github.com/go-openapi/testify/v2 v2.5.1 h1:TMdhCaw8fUNraVSf3Omoob1dO/AzBfhtFAPW0an6sBo=
+github.com/go-openapi/testify/v2 v2.5.1/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c=
github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
@@ -64,12 +64,13 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
-github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
-github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
+github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
@@ -84,20 +85,20 @@ go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
-golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
-golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
-golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
-golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
-golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
-golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
-golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
+golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
+golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
+golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
+golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
-google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
-google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
+google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -107,27 +108,27 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-k8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw=
-k8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60=
-k8s.io/apiextensions-apiserver v0.35.2 h1:iyStXHoJZsUXPh/nFAsjC29rjJWdSgUmG1XpApE29c0=
-k8s.io/apiextensions-apiserver v0.35.2/go.mod h1:OdyGvcO1FtMDWQ+rRh/Ei3b6X3g2+ZDHd0MSRGeS8rU=
-k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8=
-k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
-k8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o=
-k8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g=
+k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY=
+k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg=
+k8s.io/apiextensions-apiserver v0.36.2 h1:3O5gqOj/dt2XWWbpMe+TXWpE9yU6pjM/tXxtHHJT/K4=
+k8s.io/apiextensions-apiserver v0.36.2/go.mod h1:cL1tBWe8XSaP1H30iWKGo7hf6iAUUUJPEU70dskmAnA=
+k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ=
+k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4=
+k8s.io/client-go v0.36.2 h1:bfgxmFKc9CgqsgX4xKLAAdmTQlWee7Ob/HlDOrJ5TBI=
+k8s.io/client-go v0.36.2/go.mod h1:1vgO4OAlfPnoLcb+Rze2GF5rAr14w8qjrYMoyXJzQj0=
k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
-k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg=
-k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0=
-k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=
-k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
-sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80=
-sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
+k8s.io/kube-openapi v0.0.0-20260603220949-865597e52e25 h1:mPMaPMpBij2V1Wv/fR+HW124vVGXXvOSS9ver/9yjWs=
+k8s.io/kube-openapi v0.0.0-20260603220949-865597e52e25/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY=
+k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 h1:wU4tMEhLGgIbLvXQb1cfN+EcM0wf7zC6CPF+C79jroc=
+k8s.io/utils v0.0.0-20260507154919-ff6756f316d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
+sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4=
+sigs.k8s.io/controller-runtime v0.24.1/go.mod h1:vFkfY5fGt5xAC/sKb8IBFKgWPNKG9OUG29dR8Y2wImw=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
-sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8=
-sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
+sigs.k8s.io/structured-merge-diff/v6 v6.4.0 h1:qmp2e3ZfFi1/jJbDGpD4mt3wyp6PE1NfKHCYLqgNQJo=
+sigs.k8s.io/structured-merge-diff/v6 v6.4.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go
index 2e5c3b9edf1..c1738e100ee 100644
--- a/pkg/client/informers/externalversions/factory.go
+++ b/pkg/client/informers/externalversions/factory.go
@@ -17,6 +17,7 @@
package externalversions
import (
+ context "context"
reflect "reflect"
sync "sync"
time "time"
@@ -27,6 +28,7 @@ import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
+ wait "k8s.io/apimachinery/pkg/util/wait"
cache "k8s.io/client-go/tools/cache"
)
@@ -41,6 +43,7 @@ type sharedInformerFactory struct {
defaultResync time.Duration
customResync map[reflect.Type]time.Duration
transform cache.TransformFunc
+ informerName *cache.InformerName
informers map[reflect.Type]cache.SharedIndexInformer
// startedInformers is used for tracking which informers have been started.
@@ -87,6 +90,21 @@ func WithTransform(transform cache.TransformFunc) SharedInformerOption {
}
}
+// WithInformerName sets the InformerName for informer identity used in metrics.
+// The InformerName must be created via cache.NewInformerName() at startup,
+// which validates global uniqueness. Each informer type will register its
+// GVR under this name.
+func WithInformerName(informerName *cache.InformerName) SharedInformerOption {
+ return func(factory *sharedInformerFactory) *sharedInformerFactory {
+ factory.informerName = informerName
+ return factory
+ }
+}
+
+func (f *sharedInformerFactory) InformerName() *cache.InformerName {
+ return f.informerName
+}
+
// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces.
func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory {
return NewSharedInformerFactoryWithOptions(client, defaultResync)
@@ -121,6 +139,10 @@ func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResy
}
func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
+ f.StartWithContext(wait.ContextForChannel(stopCh))
+}
+
+func (f *sharedInformerFactory) StartWithContext(ctx context.Context) {
f.lock.Lock()
defer f.lock.Unlock()
@@ -130,15 +152,9 @@ func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
for informerType, informer := range f.informers {
if !f.startedInformers[informerType] {
- f.wg.Add(1)
- // We need a new variable in each loop iteration,
- // otherwise the goroutine would use the loop variable
- // and that keeps changing.
- informer := informer
- go func() {
- defer f.wg.Done()
- informer.Run(stopCh)
- }()
+ f.wg.Go(func() {
+ informer.RunWithContext(ctx)
+ })
f.startedInformers[informerType] = true
}
}
@@ -151,9 +167,15 @@ func (f *sharedInformerFactory) Shutdown() {
// Will return immediately if there is nothing to wait for.
f.wg.Wait()
+ f.informerName.Release()
}
func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool {
+ result := f.WaitForCacheSyncWithContext(wait.ContextForChannel(stopCh))
+ return result.Synced
+}
+
+func (f *sharedInformerFactory) WaitForCacheSyncWithContext(ctx context.Context) cache.SyncResult {
informers := func() map[reflect.Type]cache.SharedIndexInformer {
f.lock.Lock()
defer f.lock.Unlock()
@@ -167,10 +189,31 @@ func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[ref
return informers
}()
- res := map[reflect.Type]bool{}
+ // Wait for informers to sync, without polling.
+ cacheSyncs := make([]cache.DoneChecker, 0, len(informers))
+ for _, informer := range informers {
+ cacheSyncs = append(cacheSyncs, informer.HasSyncedChecker())
+ }
+ cache.WaitFor(ctx, "" /* no logging */, cacheSyncs...)
+
+ res := cache.SyncResult{
+ Synced: make(map[reflect.Type]bool, len(informers)),
+ }
+ failed := false
for informType, informer := range informers {
- res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced)
+ hasSynced := informer.HasSynced()
+ if !hasSynced {
+ failed = true
+ }
+ res.Synced[informType] = hasSynced
}
+ if failed {
+ // context.Cause is more informative than ctx.Err().
+ // This must be non-nil, otherwise WaitFor wouldn't have stopped
+ // prematurely.
+ res.Err = context.Cause(ctx)
+ }
+
return res
}
@@ -192,7 +235,9 @@ func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internal
}
informer = newFunc(f.client, resyncPeriod)
- informer.SetTransform(f.transform)
+ if f.transform != nil {
+ informer.SetTransform(f.transform)
+ }
f.informers[informerType] = informer
return informer
@@ -209,27 +254,46 @@ func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internal
// defer factory.WaitForStop() // Returns immediately if nothing was started.
// genericInformer := factory.ForResource(resource)
// typedInformer := factory.SomeAPIGroup().V1().SomeType()
-// factory.Start(ctx.Done()) // Start processing these informers.
-// synced := factory.WaitForCacheSync(ctx.Done())
-// for v, ok := range synced {
-// if !ok {
-// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v)
-// return
-// }
+// handle, err := typeInformer.Informer().AddEventHandler(...)
+// if err != nil {
+// return fmt.Errorf("register event handler: %v", err)
+// }
+// defer typeInformer.Informer().RemoveEventHandler(handle) // Avoids leaking goroutines.
+// factory.StartWithContext(ctx) // Start processing these informers.
+// synced := factory.WaitForCacheSyncWithContext(ctx)
+// if err := synced.AsError(); err != nil {
+// return err
+// }
+// for v := range synced {
+// // Only if desired log some information similar to this.
+// fmt.Fprintf(os.Stdout, "cache synced: %s", v)
+// }
+//
+// // Also make sure that all of the initial cache events have been delivered.
+// if !WaitFor(ctx, "event handler sync", handle.HasSyncedChecker()) {
+// // Must have failed because of context.
+// return fmt.Errorf("sync event handler: %w", context.Cause(ctx))
// }
//
// // Creating informers can also be created after Start, but then
// // Start must be called again:
// anotherGenericInformer := factory.ForResource(resource)
-// factory.Start(ctx.Done())
+// factory.StartWithContext(ctx)
type SharedInformerFactory interface {
internalinterfaces.SharedInformerFactory
// Start initializes all requested informers. They are handled in goroutines
// which run until the stop channel gets closed.
// Warning: Start does not block. When run in a go-routine, it will race with a later WaitForCacheSync.
+ //
+ // Contextual logging: StartWithContext should be used instead of Start in code which supports contextual logging.
Start(stopCh <-chan struct{})
+ // StartWithContext initializes all requested informers. They are handled in goroutines
+ // which run until the context gets canceled.
+ // Warning: StartWithContext does not block. When run in a go-routine, it will race with a later WaitForCacheSync.
+ StartWithContext(ctx context.Context)
+
// Shutdown marks a factory as shutting down. At that point no new
// informers can be started anymore and Start will return without
// doing anything.
@@ -244,8 +308,14 @@ type SharedInformerFactory interface {
// WaitForCacheSync blocks until all started informers' caches were synced
// or the stop channel gets closed.
+ //
+ // Contextual logging: WaitForCacheSync should be used instead of WaitForCacheSync in code which supports contextual logging. It also returns a more useful result.
WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
+ // WaitForCacheSyncWithContext blocks until all started informers' caches were synced
+ // or the context gets canceled.
+ WaitForCacheSyncWithContext(ctx context.Context) cache.SyncResult
+
// ForResource gives generic access to a shared informer of the matching type.
ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
diff --git a/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go
index 8b7e955df89..3f9d21897b1 100644
--- a/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go
+++ b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go
@@ -32,7 +32,26 @@ type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexI
type SharedInformerFactory interface {
Start(stopCh <-chan struct{})
InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer
+ InformerName() *cache.InformerName
}
// TweakListOptionsFunc is a function that transforms a v1.ListOptions.
type TweakListOptionsFunc func(*v1.ListOptions)
+
+// InformerOptions holds the options for creating an informer.
+type InformerOptions struct {
+ // ResyncPeriod is the resync period for this informer.
+ // If not set, defaults to 0 (no resync).
+ ResyncPeriod time.Duration
+
+ // Indexers are the indexers for this informer.
+ Indexers cache.Indexers
+
+ // InformerName is used to uniquely identify this informer for metrics.
+ // If not set, metrics will not be published for this informer.
+ // Use cache.NewInformerName() to create an InformerName at startup.
+ InformerName *cache.InformerName
+
+ // TweakListOptions is an optional function to modify the list options.
+ TweakListOptions TweakListOptionsFunc
+}
diff --git a/pkg/client/informers/externalversions/monitoring/v1/alertmanager.go b/pkg/client/informers/externalversions/monitoring/v1/alertmanager.go
index 024fd904aa5..192918501ff 100644
--- a/pkg/client/informers/externalversions/monitoring/v1/alertmanager.go
+++ b/pkg/client/informers/externalversions/monitoring/v1/alertmanager.go
@@ -26,6 +26,7 @@ import (
versioned "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
@@ -47,48 +48,61 @@ type alertmanagerInformer struct {
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewAlertmanagerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
- return NewFilteredAlertmanagerInformer(client, namespace, resyncPeriod, indexers, nil)
+ return NewAlertmanagerInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredAlertmanagerInformer constructs a new informer for Alertmanager type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredAlertmanagerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
- return cache.NewSharedIndexInformer(
+ return NewAlertmanagerInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
+}
+
+// NewAlertmanagerInformerWithOptions constructs a new informer for Alertmanager type with additional options.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewAlertmanagerInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
+ gvr := schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1", Resource: "alertmanagers"}
+ identifier := options.InformerName.WithResource(gvr)
+ tweakListOptions := options.TweakListOptions
+ return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
- ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().Alertmanagers(namespace).List(context.Background(), options)
+ return client.MonitoringV1().Alertmanagers(namespace).List(context.Background(), opts)
},
- WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
+ WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().Alertmanagers(namespace).Watch(context.Background(), options)
+ return client.MonitoringV1().Alertmanagers(namespace).Watch(context.Background(), opts)
},
- ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) {
+ ListWithContextFunc: func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().Alertmanagers(namespace).List(ctx, options)
+ return client.MonitoringV1().Alertmanagers(namespace).List(ctx, opts)
},
- WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) {
+ WatchFuncWithContext: func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().Alertmanagers(namespace).Watch(ctx, options)
+ return client.MonitoringV1().Alertmanagers(namespace).Watch(ctx, opts)
},
}, client),
&apismonitoringv1.Alertmanager{},
- resyncPeriod,
- indexers,
+ cache.SharedIndexInformerOptions{
+ ResyncPeriod: options.ResyncPeriod,
+ Indexers: options.Indexers,
+ Identifier: identifier,
+ },
)
}
func (f *alertmanagerInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
- return NewFilteredAlertmanagerInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+ return NewAlertmanagerInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *alertmanagerInformer) Informer() cache.SharedIndexInformer {
diff --git a/pkg/client/informers/externalversions/monitoring/v1/podmonitor.go b/pkg/client/informers/externalversions/monitoring/v1/podmonitor.go
index 998db3477fd..223f6313ea3 100644
--- a/pkg/client/informers/externalversions/monitoring/v1/podmonitor.go
+++ b/pkg/client/informers/externalversions/monitoring/v1/podmonitor.go
@@ -26,6 +26,7 @@ import (
versioned "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
@@ -47,48 +48,61 @@ type podMonitorInformer struct {
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewPodMonitorInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
- return NewFilteredPodMonitorInformer(client, namespace, resyncPeriod, indexers, nil)
+ return NewPodMonitorInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredPodMonitorInformer constructs a new informer for PodMonitor type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredPodMonitorInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
- return cache.NewSharedIndexInformer(
+ return NewPodMonitorInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
+}
+
+// NewPodMonitorInformerWithOptions constructs a new informer for PodMonitor type with additional options.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewPodMonitorInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
+ gvr := schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1", Resource: "podmonitors"}
+ identifier := options.InformerName.WithResource(gvr)
+ tweakListOptions := options.TweakListOptions
+ return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
- ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().PodMonitors(namespace).List(context.Background(), options)
+ return client.MonitoringV1().PodMonitors(namespace).List(context.Background(), opts)
},
- WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
+ WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().PodMonitors(namespace).Watch(context.Background(), options)
+ return client.MonitoringV1().PodMonitors(namespace).Watch(context.Background(), opts)
},
- ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) {
+ ListWithContextFunc: func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().PodMonitors(namespace).List(ctx, options)
+ return client.MonitoringV1().PodMonitors(namespace).List(ctx, opts)
},
- WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) {
+ WatchFuncWithContext: func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().PodMonitors(namespace).Watch(ctx, options)
+ return client.MonitoringV1().PodMonitors(namespace).Watch(ctx, opts)
},
}, client),
&apismonitoringv1.PodMonitor{},
- resyncPeriod,
- indexers,
+ cache.SharedIndexInformerOptions{
+ ResyncPeriod: options.ResyncPeriod,
+ Indexers: options.Indexers,
+ Identifier: identifier,
+ },
)
}
func (f *podMonitorInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
- return NewFilteredPodMonitorInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+ return NewPodMonitorInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *podMonitorInformer) Informer() cache.SharedIndexInformer {
diff --git a/pkg/client/informers/externalversions/monitoring/v1/probe.go b/pkg/client/informers/externalversions/monitoring/v1/probe.go
index 8cf49089787..4c42e425b6d 100644
--- a/pkg/client/informers/externalversions/monitoring/v1/probe.go
+++ b/pkg/client/informers/externalversions/monitoring/v1/probe.go
@@ -26,6 +26,7 @@ import (
versioned "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
@@ -47,48 +48,61 @@ type probeInformer struct {
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewProbeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
- return NewFilteredProbeInformer(client, namespace, resyncPeriod, indexers, nil)
+ return NewProbeInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredProbeInformer constructs a new informer for Probe type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredProbeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
- return cache.NewSharedIndexInformer(
+ return NewProbeInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
+}
+
+// NewProbeInformerWithOptions constructs a new informer for Probe type with additional options.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewProbeInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
+ gvr := schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1", Resource: "probes"}
+ identifier := options.InformerName.WithResource(gvr)
+ tweakListOptions := options.TweakListOptions
+ return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
- ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().Probes(namespace).List(context.Background(), options)
+ return client.MonitoringV1().Probes(namespace).List(context.Background(), opts)
},
- WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
+ WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().Probes(namespace).Watch(context.Background(), options)
+ return client.MonitoringV1().Probes(namespace).Watch(context.Background(), opts)
},
- ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) {
+ ListWithContextFunc: func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().Probes(namespace).List(ctx, options)
+ return client.MonitoringV1().Probes(namespace).List(ctx, opts)
},
- WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) {
+ WatchFuncWithContext: func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().Probes(namespace).Watch(ctx, options)
+ return client.MonitoringV1().Probes(namespace).Watch(ctx, opts)
},
}, client),
&apismonitoringv1.Probe{},
- resyncPeriod,
- indexers,
+ cache.SharedIndexInformerOptions{
+ ResyncPeriod: options.ResyncPeriod,
+ Indexers: options.Indexers,
+ Identifier: identifier,
+ },
)
}
func (f *probeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
- return NewFilteredProbeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+ return NewProbeInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *probeInformer) Informer() cache.SharedIndexInformer {
diff --git a/pkg/client/informers/externalversions/monitoring/v1/prometheus.go b/pkg/client/informers/externalversions/monitoring/v1/prometheus.go
index c61eb3d49c3..0695dbb6ac0 100644
--- a/pkg/client/informers/externalversions/monitoring/v1/prometheus.go
+++ b/pkg/client/informers/externalversions/monitoring/v1/prometheus.go
@@ -26,6 +26,7 @@ import (
versioned "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
@@ -47,48 +48,61 @@ type prometheusInformer struct {
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewPrometheusInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
- return NewFilteredPrometheusInformer(client, namespace, resyncPeriod, indexers, nil)
+ return NewPrometheusInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredPrometheusInformer constructs a new informer for Prometheus type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredPrometheusInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
- return cache.NewSharedIndexInformer(
+ return NewPrometheusInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
+}
+
+// NewPrometheusInformerWithOptions constructs a new informer for Prometheus type with additional options.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewPrometheusInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
+ gvr := schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1", Resource: "prometheuss"}
+ identifier := options.InformerName.WithResource(gvr)
+ tweakListOptions := options.TweakListOptions
+ return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
- ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().Prometheuses(namespace).List(context.Background(), options)
+ return client.MonitoringV1().Prometheuses(namespace).List(context.Background(), opts)
},
- WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
+ WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().Prometheuses(namespace).Watch(context.Background(), options)
+ return client.MonitoringV1().Prometheuses(namespace).Watch(context.Background(), opts)
},
- ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) {
+ ListWithContextFunc: func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().Prometheuses(namespace).List(ctx, options)
+ return client.MonitoringV1().Prometheuses(namespace).List(ctx, opts)
},
- WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) {
+ WatchFuncWithContext: func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().Prometheuses(namespace).Watch(ctx, options)
+ return client.MonitoringV1().Prometheuses(namespace).Watch(ctx, opts)
},
}, client),
&apismonitoringv1.Prometheus{},
- resyncPeriod,
- indexers,
+ cache.SharedIndexInformerOptions{
+ ResyncPeriod: options.ResyncPeriod,
+ Indexers: options.Indexers,
+ Identifier: identifier,
+ },
)
}
func (f *prometheusInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
- return NewFilteredPrometheusInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+ return NewPrometheusInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *prometheusInformer) Informer() cache.SharedIndexInformer {
diff --git a/pkg/client/informers/externalversions/monitoring/v1/prometheusrule.go b/pkg/client/informers/externalversions/monitoring/v1/prometheusrule.go
index 59aceff1023..0cab9c4cdef 100644
--- a/pkg/client/informers/externalversions/monitoring/v1/prometheusrule.go
+++ b/pkg/client/informers/externalversions/monitoring/v1/prometheusrule.go
@@ -26,6 +26,7 @@ import (
versioned "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
@@ -47,48 +48,61 @@ type prometheusRuleInformer struct {
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewPrometheusRuleInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
- return NewFilteredPrometheusRuleInformer(client, namespace, resyncPeriod, indexers, nil)
+ return NewPrometheusRuleInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredPrometheusRuleInformer constructs a new informer for PrometheusRule type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredPrometheusRuleInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
- return cache.NewSharedIndexInformer(
+ return NewPrometheusRuleInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
+}
+
+// NewPrometheusRuleInformerWithOptions constructs a new informer for PrometheusRule type with additional options.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewPrometheusRuleInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
+ gvr := schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1", Resource: "prometheusrules"}
+ identifier := options.InformerName.WithResource(gvr)
+ tweakListOptions := options.TweakListOptions
+ return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
- ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().PrometheusRules(namespace).List(context.Background(), options)
+ return client.MonitoringV1().PrometheusRules(namespace).List(context.Background(), opts)
},
- WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
+ WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().PrometheusRules(namespace).Watch(context.Background(), options)
+ return client.MonitoringV1().PrometheusRules(namespace).Watch(context.Background(), opts)
},
- ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) {
+ ListWithContextFunc: func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().PrometheusRules(namespace).List(ctx, options)
+ return client.MonitoringV1().PrometheusRules(namespace).List(ctx, opts)
},
- WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) {
+ WatchFuncWithContext: func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().PrometheusRules(namespace).Watch(ctx, options)
+ return client.MonitoringV1().PrometheusRules(namespace).Watch(ctx, opts)
},
}, client),
&apismonitoringv1.PrometheusRule{},
- resyncPeriod,
- indexers,
+ cache.SharedIndexInformerOptions{
+ ResyncPeriod: options.ResyncPeriod,
+ Indexers: options.Indexers,
+ Identifier: identifier,
+ },
)
}
func (f *prometheusRuleInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
- return NewFilteredPrometheusRuleInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+ return NewPrometheusRuleInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *prometheusRuleInformer) Informer() cache.SharedIndexInformer {
diff --git a/pkg/client/informers/externalversions/monitoring/v1/servicemonitor.go b/pkg/client/informers/externalversions/monitoring/v1/servicemonitor.go
index c66ecbf1842..591b8e9fc2d 100644
--- a/pkg/client/informers/externalversions/monitoring/v1/servicemonitor.go
+++ b/pkg/client/informers/externalversions/monitoring/v1/servicemonitor.go
@@ -26,6 +26,7 @@ import (
versioned "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
@@ -47,48 +48,61 @@ type serviceMonitorInformer struct {
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewServiceMonitorInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
- return NewFilteredServiceMonitorInformer(client, namespace, resyncPeriod, indexers, nil)
+ return NewServiceMonitorInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredServiceMonitorInformer constructs a new informer for ServiceMonitor type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredServiceMonitorInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
- return cache.NewSharedIndexInformer(
+ return NewServiceMonitorInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
+}
+
+// NewServiceMonitorInformerWithOptions constructs a new informer for ServiceMonitor type with additional options.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewServiceMonitorInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
+ gvr := schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1", Resource: "servicemonitors"}
+ identifier := options.InformerName.WithResource(gvr)
+ tweakListOptions := options.TweakListOptions
+ return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
- ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().ServiceMonitors(namespace).List(context.Background(), options)
+ return client.MonitoringV1().ServiceMonitors(namespace).List(context.Background(), opts)
},
- WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
+ WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().ServiceMonitors(namespace).Watch(context.Background(), options)
+ return client.MonitoringV1().ServiceMonitors(namespace).Watch(context.Background(), opts)
},
- ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) {
+ ListWithContextFunc: func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().ServiceMonitors(namespace).List(ctx, options)
+ return client.MonitoringV1().ServiceMonitors(namespace).List(ctx, opts)
},
- WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) {
+ WatchFuncWithContext: func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().ServiceMonitors(namespace).Watch(ctx, options)
+ return client.MonitoringV1().ServiceMonitors(namespace).Watch(ctx, opts)
},
}, client),
&apismonitoringv1.ServiceMonitor{},
- resyncPeriod,
- indexers,
+ cache.SharedIndexInformerOptions{
+ ResyncPeriod: options.ResyncPeriod,
+ Indexers: options.Indexers,
+ Identifier: identifier,
+ },
)
}
func (f *serviceMonitorInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
- return NewFilteredServiceMonitorInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+ return NewServiceMonitorInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *serviceMonitorInformer) Informer() cache.SharedIndexInformer {
diff --git a/pkg/client/informers/externalversions/monitoring/v1/thanosruler.go b/pkg/client/informers/externalversions/monitoring/v1/thanosruler.go
index 8fdb5d028aa..5d1ca3a69a3 100644
--- a/pkg/client/informers/externalversions/monitoring/v1/thanosruler.go
+++ b/pkg/client/informers/externalversions/monitoring/v1/thanosruler.go
@@ -26,6 +26,7 @@ import (
versioned "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
@@ -47,48 +48,61 @@ type thanosRulerInformer struct {
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewThanosRulerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
- return NewFilteredThanosRulerInformer(client, namespace, resyncPeriod, indexers, nil)
+ return NewThanosRulerInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredThanosRulerInformer constructs a new informer for ThanosRuler type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredThanosRulerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
- return cache.NewSharedIndexInformer(
+ return NewThanosRulerInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
+}
+
+// NewThanosRulerInformerWithOptions constructs a new informer for ThanosRuler type with additional options.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewThanosRulerInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
+ gvr := schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1", Resource: "thanosrulers"}
+ identifier := options.InformerName.WithResource(gvr)
+ tweakListOptions := options.TweakListOptions
+ return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
- ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().ThanosRulers(namespace).List(context.Background(), options)
+ return client.MonitoringV1().ThanosRulers(namespace).List(context.Background(), opts)
},
- WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
+ WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().ThanosRulers(namespace).Watch(context.Background(), options)
+ return client.MonitoringV1().ThanosRulers(namespace).Watch(context.Background(), opts)
},
- ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) {
+ ListWithContextFunc: func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().ThanosRulers(namespace).List(ctx, options)
+ return client.MonitoringV1().ThanosRulers(namespace).List(ctx, opts)
},
- WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) {
+ WatchFuncWithContext: func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1().ThanosRulers(namespace).Watch(ctx, options)
+ return client.MonitoringV1().ThanosRulers(namespace).Watch(ctx, opts)
},
}, client),
&apismonitoringv1.ThanosRuler{},
- resyncPeriod,
- indexers,
+ cache.SharedIndexInformerOptions{
+ ResyncPeriod: options.ResyncPeriod,
+ Indexers: options.Indexers,
+ Identifier: identifier,
+ },
)
}
func (f *thanosRulerInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
- return NewFilteredThanosRulerInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+ return NewThanosRulerInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *thanosRulerInformer) Informer() cache.SharedIndexInformer {
diff --git a/pkg/client/informers/externalversions/monitoring/v1alpha1/alertmanagerconfig.go b/pkg/client/informers/externalversions/monitoring/v1alpha1/alertmanagerconfig.go
index d31a680d108..bdce2a45724 100644
--- a/pkg/client/informers/externalversions/monitoring/v1alpha1/alertmanagerconfig.go
+++ b/pkg/client/informers/externalversions/monitoring/v1alpha1/alertmanagerconfig.go
@@ -26,6 +26,7 @@ import (
versioned "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
@@ -47,48 +48,61 @@ type alertmanagerConfigInformer struct {
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewAlertmanagerConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
- return NewFilteredAlertmanagerConfigInformer(client, namespace, resyncPeriod, indexers, nil)
+ return NewAlertmanagerConfigInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredAlertmanagerConfigInformer constructs a new informer for AlertmanagerConfig type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredAlertmanagerConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
- return cache.NewSharedIndexInformer(
+ return NewAlertmanagerConfigInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
+}
+
+// NewAlertmanagerConfigInformerWithOptions constructs a new informer for AlertmanagerConfig type with additional options.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewAlertmanagerConfigInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
+ gvr := schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1alpha1", Resource: "alertmanagerconfigs"}
+ identifier := options.InformerName.WithResource(gvr)
+ tweakListOptions := options.TweakListOptions
+ return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
- ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
+ ListFunc: func(opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1alpha1().AlertmanagerConfigs(namespace).List(context.Background(), options)
+ return client.MonitoringV1alpha1().AlertmanagerConfigs(namespace).List(context.Background(), opts)
},
- WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
+ WatchFunc: func(opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1alpha1().AlertmanagerConfigs(namespace).Watch(context.Background(), options)
+ return client.MonitoringV1alpha1().AlertmanagerConfigs(namespace).Watch(context.Background(), opts)
},
- ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) {
+ ListWithContextFunc: func(ctx context.Context, opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1alpha1().AlertmanagerConfigs(namespace).List(ctx, options)
+ return client.MonitoringV1alpha1().AlertmanagerConfigs(namespace).List(ctx, opts)
},
- WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) {
+ WatchFuncWithContext: func(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1alpha1().AlertmanagerConfigs(namespace).Watch(ctx, options)
+ return client.MonitoringV1alpha1().AlertmanagerConfigs(namespace).Watch(ctx, opts)
},
}, client),
&apismonitoringv1alpha1.AlertmanagerConfig{},
- resyncPeriod,
- indexers,
+ cache.SharedIndexInformerOptions{
+ ResyncPeriod: options.ResyncPeriod,
+ Indexers: options.Indexers,
+ Identifier: identifier,
+ },
)
}
func (f *alertmanagerConfigInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
- return NewFilteredAlertmanagerConfigInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+ return NewAlertmanagerConfigInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *alertmanagerConfigInformer) Informer() cache.SharedIndexInformer {
diff --git a/pkg/client/informers/externalversions/monitoring/v1alpha1/prometheusagent.go b/pkg/client/informers/externalversions/monitoring/v1alpha1/prometheusagent.go
index ce2df0e968d..9e6bf696ae7 100644
--- a/pkg/client/informers/externalversions/monitoring/v1alpha1/prometheusagent.go
+++ b/pkg/client/informers/externalversions/monitoring/v1alpha1/prometheusagent.go
@@ -26,6 +26,7 @@ import (
versioned "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
@@ -47,48 +48,61 @@ type prometheusAgentInformer struct {
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewPrometheusAgentInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
- return NewFilteredPrometheusAgentInformer(client, namespace, resyncPeriod, indexers, nil)
+ return NewPrometheusAgentInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredPrometheusAgentInformer constructs a new informer for PrometheusAgent type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredPrometheusAgentInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
- return cache.NewSharedIndexInformer(
+ return NewPrometheusAgentInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
+}
+
+// NewPrometheusAgentInformerWithOptions constructs a new informer for PrometheusAgent type with additional options.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewPrometheusAgentInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
+ gvr := schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1alpha1", Resource: "prometheusagents"}
+ identifier := options.InformerName.WithResource(gvr)
+ tweakListOptions := options.TweakListOptions
+ return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
- ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
+ ListFunc: func(opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1alpha1().PrometheusAgents(namespace).List(context.Background(), options)
+ return client.MonitoringV1alpha1().PrometheusAgents(namespace).List(context.Background(), opts)
},
- WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
+ WatchFunc: func(opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1alpha1().PrometheusAgents(namespace).Watch(context.Background(), options)
+ return client.MonitoringV1alpha1().PrometheusAgents(namespace).Watch(context.Background(), opts)
},
- ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) {
+ ListWithContextFunc: func(ctx context.Context, opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1alpha1().PrometheusAgents(namespace).List(ctx, options)
+ return client.MonitoringV1alpha1().PrometheusAgents(namespace).List(ctx, opts)
},
- WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) {
+ WatchFuncWithContext: func(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1alpha1().PrometheusAgents(namespace).Watch(ctx, options)
+ return client.MonitoringV1alpha1().PrometheusAgents(namespace).Watch(ctx, opts)
},
}, client),
&apismonitoringv1alpha1.PrometheusAgent{},
- resyncPeriod,
- indexers,
+ cache.SharedIndexInformerOptions{
+ ResyncPeriod: options.ResyncPeriod,
+ Indexers: options.Indexers,
+ Identifier: identifier,
+ },
)
}
func (f *prometheusAgentInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
- return NewFilteredPrometheusAgentInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+ return NewPrometheusAgentInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *prometheusAgentInformer) Informer() cache.SharedIndexInformer {
diff --git a/pkg/client/informers/externalversions/monitoring/v1alpha1/scrapeconfig.go b/pkg/client/informers/externalversions/monitoring/v1alpha1/scrapeconfig.go
index 3bc9a78f076..34a3ae9cb5f 100644
--- a/pkg/client/informers/externalversions/monitoring/v1alpha1/scrapeconfig.go
+++ b/pkg/client/informers/externalversions/monitoring/v1alpha1/scrapeconfig.go
@@ -26,6 +26,7 @@ import (
versioned "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
@@ -47,48 +48,61 @@ type scrapeConfigInformer struct {
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewScrapeConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
- return NewFilteredScrapeConfigInformer(client, namespace, resyncPeriod, indexers, nil)
+ return NewScrapeConfigInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredScrapeConfigInformer constructs a new informer for ScrapeConfig type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredScrapeConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
- return cache.NewSharedIndexInformer(
+ return NewScrapeConfigInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
+}
+
+// NewScrapeConfigInformerWithOptions constructs a new informer for ScrapeConfig type with additional options.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewScrapeConfigInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
+ gvr := schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1alpha1", Resource: "scrapeconfigs"}
+ identifier := options.InformerName.WithResource(gvr)
+ tweakListOptions := options.TweakListOptions
+ return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
- ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
+ ListFunc: func(opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1alpha1().ScrapeConfigs(namespace).List(context.Background(), options)
+ return client.MonitoringV1alpha1().ScrapeConfigs(namespace).List(context.Background(), opts)
},
- WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
+ WatchFunc: func(opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1alpha1().ScrapeConfigs(namespace).Watch(context.Background(), options)
+ return client.MonitoringV1alpha1().ScrapeConfigs(namespace).Watch(context.Background(), opts)
},
- ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) {
+ ListWithContextFunc: func(ctx context.Context, opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1alpha1().ScrapeConfigs(namespace).List(ctx, options)
+ return client.MonitoringV1alpha1().ScrapeConfigs(namespace).List(ctx, opts)
},
- WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) {
+ WatchFuncWithContext: func(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1alpha1().ScrapeConfigs(namespace).Watch(ctx, options)
+ return client.MonitoringV1alpha1().ScrapeConfigs(namespace).Watch(ctx, opts)
},
}, client),
&apismonitoringv1alpha1.ScrapeConfig{},
- resyncPeriod,
- indexers,
+ cache.SharedIndexInformerOptions{
+ ResyncPeriod: options.ResyncPeriod,
+ Indexers: options.Indexers,
+ Identifier: identifier,
+ },
)
}
func (f *scrapeConfigInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
- return NewFilteredScrapeConfigInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+ return NewScrapeConfigInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *scrapeConfigInformer) Informer() cache.SharedIndexInformer {
diff --git a/pkg/client/informers/externalversions/monitoring/v1beta1/alertmanagerconfig.go b/pkg/client/informers/externalversions/monitoring/v1beta1/alertmanagerconfig.go
index 7930f670c6f..ee4cddf4e38 100644
--- a/pkg/client/informers/externalversions/monitoring/v1beta1/alertmanagerconfig.go
+++ b/pkg/client/informers/externalversions/monitoring/v1beta1/alertmanagerconfig.go
@@ -26,6 +26,7 @@ import (
versioned "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
@@ -47,48 +48,61 @@ type alertmanagerConfigInformer struct {
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewAlertmanagerConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
- return NewFilteredAlertmanagerConfigInformer(client, namespace, resyncPeriod, indexers, nil)
+ return NewAlertmanagerConfigInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredAlertmanagerConfigInformer constructs a new informer for AlertmanagerConfig type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredAlertmanagerConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
- return cache.NewSharedIndexInformer(
+ return NewAlertmanagerConfigInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
+}
+
+// NewAlertmanagerConfigInformerWithOptions constructs a new informer for AlertmanagerConfig type with additional options.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewAlertmanagerConfigInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
+ gvr := schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1beta1", Resource: "alertmanagerconfigs"}
+ identifier := options.InformerName.WithResource(gvr)
+ tweakListOptions := options.TweakListOptions
+ return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
- ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
+ ListFunc: func(opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1beta1().AlertmanagerConfigs(namespace).List(context.Background(), options)
+ return client.MonitoringV1beta1().AlertmanagerConfigs(namespace).List(context.Background(), opts)
},
- WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
+ WatchFunc: func(opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1beta1().AlertmanagerConfigs(namespace).Watch(context.Background(), options)
+ return client.MonitoringV1beta1().AlertmanagerConfigs(namespace).Watch(context.Background(), opts)
},
- ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) {
+ ListWithContextFunc: func(ctx context.Context, opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1beta1().AlertmanagerConfigs(namespace).List(ctx, options)
+ return client.MonitoringV1beta1().AlertmanagerConfigs(namespace).List(ctx, opts)
},
- WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) {
+ WatchFuncWithContext: func(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
- tweakListOptions(&options)
+ tweakListOptions(&opts)
}
- return client.MonitoringV1beta1().AlertmanagerConfigs(namespace).Watch(ctx, options)
+ return client.MonitoringV1beta1().AlertmanagerConfigs(namespace).Watch(ctx, opts)
},
}, client),
&apismonitoringv1beta1.AlertmanagerConfig{},
- resyncPeriod,
- indexers,
+ cache.SharedIndexInformerOptions{
+ ResyncPeriod: options.ResyncPeriod,
+ Indexers: options.Indexers,
+ Identifier: identifier,
+ },
)
}
func (f *alertmanagerConfigInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
- return NewFilteredAlertmanagerConfigInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+ return NewAlertmanagerConfigInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *alertmanagerConfigInformer) Informer() cache.SharedIndexInformer {
diff --git a/pkg/client/versioned/fake/clientset_generated.go b/pkg/client/versioned/fake/clientset_generated.go
index d4fc60b4439..e59ce2a851d 100644
--- a/pkg/client/versioned/fake/clientset_generated.go
+++ b/pkg/client/versioned/fake/clientset_generated.go
@@ -37,10 +37,6 @@ import (
// It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement
// for a real clientset and is mostly useful in simple unit tests.
-//
-// Deprecated: NewClientset replaces this with support for field management, which significantly improves
-// server side apply testing. NewClientset is only available when apply configurations are generated (e.g.
-// via --with-applyconfig).
func NewSimpleClientset(objects ...runtime.Object) *Clientset {
o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
for _, obj := range objects {
@@ -86,7 +82,7 @@ func (c *Clientset) Tracker() testing.ObjectTracker {
return c.tracker
}
-// IsWatchListSemanticsSupported informs the reflector that this client
+// IsWatchListSemanticsUnSupported informs the reflector that this client
// doesn't support WatchList semantics.
//
// This is a synthetic method whose sole purpose is to satisfy the optional
@@ -101,6 +97,10 @@ func (c *Clientset) IsWatchListSemanticsUnSupported() bool {
// It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
// without applying any validations and/or defaults. It shouldn't be considered a replacement
// for a real clientset and is mostly useful in simple unit tests.
+//
+// Compared to NewSimpleClientset, the Clientset returned here supports field tracking and thus
+// server-side apply. Beware though that support in that for CRDs is missing
+// (https://github.com/kubernetes/kubernetes/issues/126850).
func NewClientset(objects ...runtime.Object) *Clientset {
o := testing.NewFieldManagedObjectTracker(
scheme,
diff --git a/pkg/k8s/network_test.go b/pkg/k8s/network_test.go
index bfd3f2de088..bb014515990 100644
--- a/pkg/k8s/network_test.go
+++ b/pkg/k8s/network_test.go
@@ -24,7 +24,6 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
- "k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
@@ -396,7 +395,7 @@ func makeBarebonesPrometheus(name, ns string) *monitoringv1.Prometheus {
},
Spec: monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- Replicas: ptr.To(int32(1)),
+ Replicas: new(int32(1)),
},
},
}
diff --git a/pkg/k8s/pod_test.go b/pkg/k8s/pod_test.go
index 79de0b37e27..4a68949a306 100644
--- a/pkg/k8s/pod_test.go
+++ b/pkg/k8s/pod_test.go
@@ -19,7 +19,6 @@ import (
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
- "k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
@@ -31,11 +30,11 @@ func TestConvertToK8sDNSConfig(t *testing.T) {
Options: []monitoringv1.PodDNSConfigOption{
{
Name: "ndots",
- Value: ptr.To("5"),
+ Value: new("5"),
},
{
Name: "timeout",
- Value: ptr.To("1"),
+ Value: new("1"),
},
},
}
diff --git a/pkg/k8s/secrets_test.go b/pkg/k8s/secrets_test.go
index 44037c3183d..532d7b8265e 100644
--- a/pkg/k8s/secrets_test.go
+++ b/pkg/k8s/secrets_test.go
@@ -23,7 +23,6 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
- "k8s.io/utils/ptr"
)
func TestLoadSecretRef(t *testing.T) {
@@ -86,7 +85,7 @@ func TestLoadSecretRef(t *testing.T) {
Name: "secret2",
},
Key: "key1",
- Optional: ptr.To(true),
+ Optional: new(true),
},
expected: nil,
},
@@ -97,7 +96,7 @@ func TestLoadSecretRef(t *testing.T) {
Name: "secret",
},
Key: "key2",
- Optional: ptr.To(true),
+ Optional: new(true),
},
expected: nil,
},
diff --git a/pkg/kubelet/controller.go b/pkg/kubelet/controller.go
index 701f9ce747a..836060ead03 100644
--- a/pkg/kubelet/controller.go
+++ b/pkg/kubelet/controller.go
@@ -30,7 +30,6 @@ import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
- "k8s.io/utils/ptr"
"github.com/prometheus-operator/prometheus-operator/pkg/k8s"
"github.com/prometheus-operator/prometheus-operator/pkg/operator"
@@ -298,9 +297,9 @@ func (na *nodeAddress) discoveryV1Endpoint() discoveryv1.Endpoint {
return discoveryv1.Endpoint{
Addresses: []string{na.ipAddress},
Conditions: discoveryv1.EndpointConditions{
- Ready: ptr.To(true),
+ Ready: new(true),
},
- NodeName: ptr.To(na.name),
+ NodeName: new(na.name),
TargetRef: &corev1.ObjectReference{
Kind: "Node",
Name: na.name,
@@ -313,7 +312,7 @@ func (na *nodeAddress) discoveryV1Endpoint() discoveryv1.Endpoint {
func (na *nodeAddress) v1EndpointAddress() corev1.EndpointAddress {
return corev1.EndpointAddress{
IP: na.ipAddress,
- NodeName: ptr.To(na.name),
+ NodeName: new(na.name),
TargetRef: &corev1.ObjectReference{
Kind: "Node",
Name: na.name,
@@ -607,8 +606,8 @@ func (c *Controller) syncEndpointSlice(ctx context.Context, svc *corev1.Service,
}),
OwnerReferences: []metav1.OwnerReference{{
APIVersion: "v1",
- BlockOwnerDeletion: ptr.To(true),
- Controller: ptr.To(true),
+ BlockOwnerDeletion: new(true),
+ Controller: new(true),
Kind: "Service",
Name: c.kubeletObjectName,
UID: svc.UID,
@@ -718,19 +717,19 @@ func (c *Controller) endpointPorts() []corev1.EndpointPort {
func (c *Controller) endpointSlicePorts() []discoveryv1.EndpointPort {
ports := []discoveryv1.EndpointPort{
{
- Name: ptr.To(httpsPortName),
- Port: ptr.To(httpsPort),
+ Name: new(httpsPortName),
+ Port: new(httpsPort),
},
{
- Name: ptr.To(cAdvisorPortName),
- Port: ptr.To(cAdvisorPort),
+ Name: new(cAdvisorPortName),
+ Port: new(cAdvisorPort),
},
}
if c.httpMetricsEnabled {
ports = append(ports, discoveryv1.EndpointPort{
- Name: ptr.To(httpPortName),
- Port: ptr.To(httpPort),
+ Name: new(httpPortName),
+ Port: new(httpPort),
})
}
diff --git a/pkg/listwatch/listwatch.go b/pkg/listwatch/listwatch.go
index ecf4abb045f..7f507d2a47e 100644
--- a/pkg/listwatch/listwatch.go
+++ b/pkg/listwatch/listwatch.go
@@ -22,6 +22,7 @@ import (
"math/big"
"slices"
"strings"
+ "sync"
"time"
"github.com/blang/semver/v4"
@@ -251,6 +252,10 @@ type pollBasedListerWatcher struct {
ctx context.Context
l *slog.Logger
+ mtx sync.Mutex
+ cancelPoll context.CancelFunc
+ pollWg sync.WaitGroup
+
cache map[string]cacheEntry
}
@@ -319,19 +324,45 @@ func (pblw *pollBasedListerWatcher) Watch(_ metav1.ListOptions) (watch.Interface
return pblw, nil
}
-func (pblw *pollBasedListerWatcher) Stop() {}
+func (pblw *pollBasedListerWatcher) Stop() {
+ pblw.mtx.Lock()
+ if pblw.cancelPoll != nil {
+ pblw.cancelPoll()
+ pblw.cancelPoll = nil
+ }
+ pblw.mtx.Unlock()
+ pblw.pollWg.Wait()
+}
func (pblw *pollBasedListerWatcher) ResultChan() <-chan watch.Event {
- go func() {
+ // Cancel any previous polling goroutine to prevent goroutine leaks
+ // when the watch is re-established after a reconnection.
+ pblw.mtx.Lock()
+ if pblw.cancelPoll != nil {
+ pblw.cancelPoll()
+ }
+ pblw.mtx.Unlock()
+ pblw.pollWg.Wait()
+
+ pollCtx, cancel := context.WithCancel(pblw.ctx)
+ pblw.mtx.Lock()
+ pblw.cancelPoll = cancel
+ pblw.mtx.Unlock()
+
+ pblw.pollWg.Go(func() {
jitter, err := rand.Int(rand.Reader, big.NewInt(int64(pollInterval)))
if err == nil {
- time.Sleep(time.Duration(jitter.Int64()))
+ select {
+ case <-time.After(time.Duration(jitter.Int64())):
+ case <-pollCtx.Done():
+ return
+ }
} else {
pblw.l.Info("failed to generate random jitter", "err", err)
}
- _ = wait.PollUntilContextCancel(pblw.ctx, pollInterval, false, pblw.poll)
- }()
+ _ = wait.PollUntilContextCancel(pollCtx, pollInterval, false, pblw.poll)
+ })
return pblw.ch
}
@@ -343,6 +374,10 @@ func (pblw *pollBasedListerWatcher) poll(ctx context.Context) (bool, error) {
)
for ns, entry := range pblw.cache {
+ if ctx.Err() != nil {
+ return false, ctx.Err()
+ }
+
var resourceVersion string
if entry.ns != nil {
// The resource is in the cache.
@@ -370,9 +405,13 @@ func (pblw *pollBasedListerWatcher) poll(ctx context.Context) (bool, error) {
for _, ns := range deleted {
entry := pblw.cache[ns]
- pblw.ch <- watch.Event{
+ select {
+ case pblw.ch <- watch.Event{
Type: watch.Deleted,
Object: entry.ns,
+ }:
+ case <-ctx.Done():
+ return false, ctx.Err()
}
pblw.cache[ns] = cacheEntry{
@@ -393,9 +432,13 @@ func (pblw *pollBasedListerWatcher) poll(ctx context.Context) (bool, error) {
continue
}
- pblw.ch <- watch.Event{
+ select {
+ case pblw.ch <- watch.Event{
Type: eventType,
Object: ns,
+ }:
+ case <-ctx.Done():
+ return false, ctx.Err()
}
pblw.cache[ns.Name] = cacheEntry{
diff --git a/pkg/namespacelabeler/labeler.go b/pkg/namespacelabeler/labeler.go
index fbe16f3ec03..7e5ac3910da 100644
--- a/pkg/namespacelabeler/labeler.go
+++ b/pkg/namespacelabeler/labeler.go
@@ -22,7 +22,6 @@ import (
"github.com/prometheus/prometheus/promql/parser"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
- "k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
@@ -147,7 +146,7 @@ func (l *Labeler) GetRelabelingConfigs(monitorTypeMeta metav1.TypeMeta, monitorO
return append(rc,
monitoringv1.RelabelConfig{
TargetLabel: l.GetEnforcedNamespaceLabel(),
- Replacement: ptr.To(monitorObjectMeta.GetNamespace()),
+ Replacement: new(monitorObjectMeta.GetNamespace()),
},
)
}
diff --git a/pkg/namespacelabeler/labeler_test.go b/pkg/namespacelabeler/labeler_test.go
index e2069a77336..3138e06164e 100644
--- a/pkg/namespacelabeler/labeler_test.go
+++ b/pkg/namespacelabeler/labeler_test.go
@@ -19,7 +19,6 @@ import (
"github.com/google/go-cmp/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
- "k8s.io/utils/ptr"
"github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
@@ -296,13 +295,13 @@ func TestEnforceNamespaceLabelOnPrometheusMonitors(t *testing.T) {
MetricRelabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "namespace",
- Replacement: ptr.To("bar"),
+ Replacement: new("bar"),
},
},
RelabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "namespace",
- Replacement: ptr.To("bar"),
+ Replacement: new("bar"),
},
},
}),
diff --git a/pkg/operator/config.go b/pkg/operator/config.go
index 7700cfe8625..679e50643d0 100644
--- a/pkg/operator/config.go
+++ b/pkg/operator/config.go
@@ -104,11 +104,11 @@ func DefaultConfig(cpu, memory string) Config {
},
PrometheusTopologyShardingFeature: FeatureGate{
description: "Enables the zone aware sharding for Prometheus",
- enabled: false,
+ enabled: true,
},
PrometheusShardRetentionPolicyFeature: FeatureGate{
description: "Enables shard retention policy for Prometheus",
- enabled: false,
+ enabled: true,
},
StatusForConfigurationResourcesFeature: FeatureGate{
description: "Updates the status subresource for configuration resources",
@@ -237,8 +237,11 @@ func (m *Map) Set(value string) error {
}
for pair := range strings.SplitSeq(value, ",") {
- pair := strings.Split(pair, "=")
- (*m)[pair[0]] = pair[1]
+ k, v, ok := strings.Cut(pair, "=")
+ if !ok {
+ return fmt.Errorf("invalid key=value pair: %q", pair)
+ }
+ (*m)[k] = v
}
return nil
diff --git a/pkg/operator/config_reloader.go b/pkg/operator/config_reloader.go
index 1f1234c9429..2db66b59bdb 100644
--- a/pkg/operator/config_reloader.go
+++ b/pkg/operator/config_reloader.go
@@ -24,7 +24,6 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
- "k8s.io/utils/ptr"
)
const (
@@ -199,7 +198,7 @@ func ImagePullPolicy(imagePullPolicy corev1.PullPolicy) ReloaderOption {
func WithDaemonSetMode() ReloaderOption {
return func(c *ConfigReloader) {
c.withNodeNameEnv = true
- c.shard = ptr.To(int32(0))
+ c.shard = new(int32(0))
}
}
@@ -367,8 +366,8 @@ func CreateConfigReloader(name string, options ...ReloaderOption) corev1.Contain
VolumeMounts: configReloader.volumeMounts,
Resources: configReloader.config.ResourceRequirements(),
SecurityContext: &corev1.SecurityContext{
- AllowPrivilegeEscalation: ptr.To(false),
- ReadOnlyRootFilesystem: ptr.To(true),
+ AllowPrivilegeEscalation: new(false),
+ ReadOnlyRootFilesystem: new(true),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
diff --git a/pkg/operator/config_test.go b/pkg/operator/config_test.go
index 51b8e0d92d2..a7ec3d2f268 100644
--- a/pkg/operator/config_test.go
+++ b/pkg/operator/config_test.go
@@ -34,6 +34,30 @@ func TestMap(t *testing.T) {
require.Equal(t, "foo=bar,foo2=bar2", m.String())
require.Equal(t, map[string]string{"foo": "bar", "foo2": "bar2", "foo3": "bar3"}, m.Merge(map[string]string{"foo": "xxx", "foo3": "bar3"}))
+
+ require.NoError(t, m.Set("k=v=with=equals"))
+ require.Equal(t, "v=with=equals", m["k"])
+}
+
+func TestMapSetInvalid(t *testing.T) {
+ for _, tc := range []struct {
+ name string
+ value string
+ }{
+ {
+ name: "missing value",
+ value: "key",
+ },
+ {
+ name: "one valid one invalid",
+ value: "good=value,bad",
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ var m Map
+ require.Error(t, m.Set(tc.value))
+ })
+ }
}
func TestFieldSelector(t *testing.T) {
diff --git a/pkg/operator/defaults.go b/pkg/operator/defaults.go
index ca41abaac1c..b4093e2ad13 100644
--- a/pkg/operator/defaults.go
+++ b/pkg/operator/defaults.go
@@ -22,7 +22,7 @@ import (
const (
// DefaultAlertmanagerVersion is a default image tag for the prometheus alertmanager.
- DefaultAlertmanagerVersion = "v0.32.1"
+ DefaultAlertmanagerVersion = "v0.33.0"
// DefaultAlertmanagerBaseImage is a base container registry address for the prometheus alertmanager.
DefaultAlertmanagerBaseImage = "quay.io/prometheus/alertmanager"
// DefaultAlertmanagerImage is a default image pulling address for the prometheus alertmanager.
@@ -104,6 +104,7 @@ var (
"v3.11.1",
"v3.11.2",
"v3.11.3",
+ "v3.12.0",
}
)
diff --git a/pkg/operator/factory.go b/pkg/operator/factory.go
index ed705633e2f..490a5e67865 100644
--- a/pkg/operator/factory.go
+++ b/pkg/operator/factory.go
@@ -20,7 +20,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/utils/ptr"
)
const (
@@ -68,8 +67,8 @@ func WithManagingOwner(owner Owner) ObjectOption {
o.GetOwnerReferences(),
metav1.OwnerReference{
APIVersion: owner.GroupVersionKind().GroupVersion().String(),
- BlockOwnerDeletion: ptr.To(true),
- Controller: ptr.To(true),
+ BlockOwnerDeletion: new(true),
+ Controller: new(true),
Kind: owner.GroupVersionKind().Kind,
Name: owner.GetObjectMeta().GetName(),
UID: owner.GetObjectMeta().GetUID(),
diff --git a/pkg/operator/factory_test.go b/pkg/operator/factory_test.go
index 1dc7e0aaeec..1075b9ecf4a 100644
--- a/pkg/operator/factory_test.go
+++ b/pkg/operator/factory_test.go
@@ -20,7 +20,6 @@ import (
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/utils/ptr"
)
type fakeOwner struct {
@@ -106,8 +105,8 @@ func TestUpdateObject(t *testing.T) {
Kind: "Prometheus",
Name: "bar",
UID: "456",
- Controller: ptr.To(true),
- BlockOwnerDeletion: ptr.To(true),
+ Controller: new(true),
+ BlockOwnerDeletion: new(true),
},
},
},
diff --git a/pkg/operator/gzip_config.go b/pkg/operator/gzip_config.go
index 45f442946e4..787557246b9 100644
--- a/pkg/operator/gzip_config.go
+++ b/pkg/operator/gzip_config.go
@@ -27,11 +27,10 @@ func GzipConfig(w io.Writer, conf []byte) error {
}
buf := gzip.NewWriter(w)
- defer buf.Close()
if _, err := buf.Write(conf); err != nil {
return err
}
- return nil
+ return buf.Close()
}
func GunzipConfig(b []byte) (string, error) {
@@ -41,8 +40,10 @@ func GunzipConfig(b []byte) (string, error) {
return "", err
}
uncompressed := new(strings.Builder)
- _, err = io.Copy(uncompressed, reader)
- if err != nil {
+ if _, err = io.Copy(uncompressed, reader); err != nil {
+ return "", err
+ }
+ if err := reader.Close(); err != nil {
return "", err
}
return uncompressed.String(), nil
diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go
index 856c82a755e..63557fc7c2b 100644
--- a/pkg/operator/operator.go
+++ b/pkg/operator/operator.go
@@ -113,8 +113,8 @@ func (rt *ReconciliationTracker) init() {
// HasRefTo returns true if the object identified by key has a direct or
// indirect reference to obj (secret or configmap).
func (rt *ReconciliationTracker) HasRefTo(key string, obj runtime.Object) bool {
- rt.mtx.Lock()
- defer rt.mtx.Unlock()
+ rt.mtx.RLock()
+ defer rt.mtx.RUnlock()
refTracker, found := rt.refTracker[key]
if !found {
@@ -169,8 +169,8 @@ func (rt *ReconciliationTracker) SetReasonAndMessage(key string, reason, message
// GetStatus returns the last reconciliation status for the given object.
// The second value indicates whether the object is known or not.
func (rt *ReconciliationTracker) getStatus(k string) (ReconciliationStatus, bool) {
- rt.mtx.Lock()
- defer rt.mtx.Unlock()
+ rt.mtx.RLock()
+ defer rt.mtx.RUnlock()
s, found := rt.statusByObject[k]
if !found {
@@ -611,3 +611,29 @@ func SelectNamespacesFromCache(obj metav1.Object, sel *metav1.LabelSelector, nsI
return ns, nil
}
+
+// GetByKeyer is an interface which exposes only the GetByKey() method of the
+// cache.Store interface.
+type GetByKeyer interface {
+ GetByKey(string) (any, bool, error)
+}
+
+// NewMultiGetByKeyer returns an interface which queries multiple GetByKeyer in
+// sequence and returns the first found object.
+func NewMultiGetByKeyer(gbk ...GetByKeyer) GetByKeyer {
+ return multiGetByKeyer(gbk)
+}
+
+type multiGetByKeyer []GetByKeyer
+
+// GetByKey implements the GetByKeyer interface.
+func (m multiGetByKeyer) GetByKey(key string) (any, bool, error) {
+ for _, gbk := range m {
+ o, found, err := gbk.GetByKey(key)
+ if err != nil || found {
+ return o, found, err
+ }
+ }
+
+ return nil, false, nil
+}
diff --git a/pkg/operator/resource_reconciler.go b/pkg/operator/resource_reconciler.go
index d1d49f0d722..4264364e7dc 100644
--- a/pkg/operator/resource_reconciler.go
+++ b/pkg/operator/resource_reconciler.go
@@ -396,6 +396,7 @@ func (rr *ResourceReconciler) FindOwner(obj metav1.Object) metav1.Object {
o, err := meta.Accessor(owner)
if err != nil {
rr.logger.Error("failed to get owner meta", "err", err, "gvk", owner.GetObjectKind().GroupVersionKind().String(), "namespace", obj.GetNamespace(), "name", obj.GetName(), "kind", rr.resourceKind)
+ return nil
}
return o
diff --git a/pkg/operator/rules.go b/pkg/operator/rules.go
index 42dffa05b22..a470a8f3447 100644
--- a/pkg/operator/rules.go
+++ b/pkg/operator/rules.go
@@ -231,7 +231,7 @@ func ValidateRule(promRuleSpec monitoringv1.PrometheusRuleSpec, validationScheme
return []error{fmt.Errorf("the length of rendered Prometheus Rule is %d bytes which is above the maximum limit of %d bytes", promRuleSize, MaxConfigMapDataSize)}
}
- _, errs := rulefmt.Parse(content, false, validationScheme, parser.NewParser(parserOptions))
+ _, errs := rulefmt.Parse(content, false, validationScheme, parser.NewParser(parserOptions), slog.New(slog.DiscardHandler))
return errs
}
diff --git a/pkg/prometheus/agent/daemonset.go b/pkg/prometheus/agent/daemonset.go
index 6a9e67c15c4..244b1e85630 100644
--- a/pkg/prometheus/agent/daemonset.go
+++ b/pkg/prometheus/agent/daemonset.go
@@ -167,8 +167,8 @@ func makeDaemonSetSpec(
Resources: cpf.Resources,
TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
SecurityContext: &corev1.SecurityContext{
- ReadOnlyRootFilesystem: ptr.To(true),
- AllowPrivilegeEscalation: ptr.To(false),
+ ReadOnlyRootFilesystem: new(true),
+ AllowPrivilegeEscalation: new(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
@@ -206,11 +206,11 @@ func makeDaemonSetSpec(
InitContainers: initContainers,
SecurityContext: cpf.SecurityContext,
ServiceAccountName: cpf.ServiceAccountName,
- AutomountServiceAccountToken: ptr.To(ptr.Deref(cpf.AutomountServiceAccountToken, true)),
+ AutomountServiceAccountToken: new(ptr.Deref(cpf.AutomountServiceAccountToken, true)),
NodeSelector: cpf.NodeSelector,
SchedulerName: cpf.SchedulerName,
PriorityClassName: cpf.PriorityClassName,
- TerminationGracePeriodSeconds: ptr.To(ptr.Deref(cpf.TerminationGracePeriodSeconds, prompkg.DefaultTerminationGracePeriodSeconds)),
+ TerminationGracePeriodSeconds: new(ptr.Deref(cpf.TerminationGracePeriodSeconds, prompkg.DefaultTerminationGracePeriodSeconds)),
Volumes: volumes,
Tolerations: cpf.Tolerations,
Affinity: cpf.Affinity,
diff --git a/pkg/prometheus/agent/daemonset_test.go b/pkg/prometheus/agent/daemonset_test.go
index ef85d155c57..125fe1e7280 100644
--- a/pkg/prometheus/agent/daemonset_test.go
+++ b/pkg/prometheus/agent/daemonset_test.go
@@ -23,7 +23,6 @@ import (
"github.com/stretchr/testify/require"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
@@ -200,8 +199,8 @@ func TestDaemonSetenableServiceLinks(t *testing.T) {
enableServiceLinks *bool
expectedEnableServiceLinks *bool
}{
- {enableServiceLinks: ptr.To(false), expectedEnableServiceLinks: ptr.To(false)},
- {enableServiceLinks: ptr.To(true), expectedEnableServiceLinks: ptr.To(true)},
+ {enableServiceLinks: new(false), expectedEnableServiceLinks: new(false)},
+ {enableServiceLinks: new(true), expectedEnableServiceLinks: new(true)},
{enableServiceLinks: nil, expectedEnableServiceLinks: nil},
}
@@ -229,10 +228,10 @@ func TestHostUsersForDaemonSet(t *testing.T) {
hostUsers *bool
}{
{
- hostUsers: ptr.To(true),
+ hostUsers: new(true),
},
{
- hostUsers: ptr.To(false),
+ hostUsers: new(false),
},
} {
t.Run("", func(t *testing.T) {
diff --git a/pkg/prometheus/agent/operator.go b/pkg/prometheus/agent/operator.go
index c7f1f85548c..53d7bbf7e7c 100644
--- a/pkg/prometheus/agent/operator.go
+++ b/pkg/prometheus/agent/operator.go
@@ -99,6 +99,7 @@ type Operator struct {
daemonSetFeatureGateEnabled bool
configResourcesStatusEnabled bool
topologyShardingEnabled bool
+ podTopologyLabelsSupported bool
finalizerSyncer *operator.FinalizerSyncer
}
@@ -135,6 +136,14 @@ func WithConfigResourceStatus() ControllerOption {
}
}
+// WithPodTopologyLabels tells that the cluster runs K8s >= 1.35 where
+// PodTopologyLabelsAdmission automatically injects topology labels onto pods.
+func WithPodTopologyLabels() ControllerOption {
+ return func(o *Operator) {
+ o.podTopologyLabelsSupported = true
+ }
+}
+
// New creates a new controller.
func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger *slog.Logger, r prometheus.Registerer, options ...ControllerOption) (*Operator, error) {
logger = logger.With("component", controllerName)
@@ -163,12 +172,13 @@ func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger
mclient: mclient,
logger: logger,
config: prompkg.Config{
- LocalHost: c.LocalHost,
- ReloaderConfig: c.ReloaderConfig,
- PrometheusDefaultBaseImage: c.PrometheusDefaultBaseImage,
- ThanosDefaultBaseImage: c.ThanosDefaultBaseImage,
- Annotations: c.Annotations,
- Labels: c.Labels,
+ LocalHost: c.LocalHost,
+ ReloaderConfig: c.ReloaderConfig,
+ PrometheusDefaultBaseImage: c.PrometheusDefaultBaseImage,
+ ThanosDefaultBaseImage: c.ThanosDefaultBaseImage,
+ Annotations: c.Annotations,
+ Labels: c.Labels,
+ WatchObjectRefsInAllNamespaces: c.WatchObjectRefsInAllNamespaces,
},
metrics: operator.NewMetrics(r),
reconciliations: &operator.ReconciliationTracker{},
@@ -526,7 +536,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
monitoringv1.ServiceMonitorsKind,
- c.enqueueForMonitorNamespace,
+ c.enqueueForNamespaceFunc(c.nsMonInf.GetStore()),
operator.WithFilter(
operator.AnyFilter(
operator.GenerationChanged,
@@ -540,7 +550,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
monitoringv1.PodMonitorsKind,
- c.enqueueForMonitorNamespace,
+ c.enqueueForNamespaceFunc(c.nsMonInf.GetStore()),
operator.WithFilter(
operator.AnyFilter(
operator.GenerationChanged,
@@ -554,7 +564,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
monitoringv1.ProbesKind,
- c.enqueueForMonitorNamespace,
+ c.enqueueForNamespaceFunc(c.nsMonInf.GetStore()),
operator.WithFilter(
operator.AnyFilter(
operator.GenerationChanged,
@@ -569,7 +579,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
monitoringv1alpha1.ScrapeConfigsKind,
- c.enqueueForMonitorNamespace,
+ c.enqueueForNamespaceFunc(c.nsMonInf.GetStore()),
operator.WithFilter(
operator.AnyFilter(
operator.GenerationChanged,
@@ -583,12 +593,19 @@ func (c *Operator) addHandlers() {
c.promInfs,
c.reconciliations,
)
+ var gbk operator.GetByKeyer = c.nsPromInf.GetStore()
+ if c.config.WatchObjectRefsInAllNamespaces && c.nsPromInf != c.nsMonInf {
+ gbk = operator.NewMultiGetByKeyer(
+ c.nsPromInf.GetStore(),
+ c.nsMonInf.GetStore(),
+ )
+ }
c.cmapInfs.AddEventHandler(operator.NewEventHandler(
c.logger,
c.accessor,
c.metrics,
operator.ConfigMapGVK().Kind,
- c.enqueueForPrometheusNamespace,
+ c.enqueueForNamespaceFunc(gbk),
operator.WithFilter(operator.ResourceVersionChanged),
operator.WithFilter(hasRefFunc),
))
@@ -598,7 +615,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
operator.SecretGVK().Kind,
- c.enqueueForPrometheusNamespace,
+ c.enqueueForNamespaceFunc(gbk),
operator.WithFilter(operator.ResourceVersionChanged),
operator.WithFilter(hasRefFunc),
))
@@ -677,6 +694,9 @@ func (c *Operator) sync(ctx context.Context, key string) error {
if c.topologyShardingEnabled {
opts = append(opts, prompkg.WithPrometheusTopologySharding())
}
+ if c.podTopologyLabelsSupported {
+ opts = append(opts, prompkg.WithPodTopologyLabelsSupport())
+ }
cg, err := prompkg.NewConfigGenerator(logger, p, opts...)
if err != nil {
@@ -1088,18 +1108,16 @@ func (c *Operator) createOrUpdateWebConfigSecret(ctx context.Context, p *monitor
return nil
}
-func (c *Operator) enqueueForPrometheusNamespace(nsName string) {
- c.enqueueForNamespace(c.nsPromInf.GetStore(), nsName)
-}
-
-func (c *Operator) enqueueForMonitorNamespace(nsName string) {
- c.enqueueForNamespace(c.nsMonInf.GetStore(), nsName)
+func (c *Operator) enqueueForNamespaceFunc(gbk operator.GetByKeyer) func(string) {
+ return func(ns string) {
+ c.enqueueForNamespace(gbk, ns)
+ }
}
// enqueueForNamespace enqueues all Prometheus object keys that belong to the
// given namespace or select objects in the given namespace.
-func (c *Operator) enqueueForNamespace(store cache.Store, nsName string) {
- nsObject, found, err := store.GetByKey(nsName)
+func (c *Operator) enqueueForNamespace(gbk operator.GetByKeyer, nsName string) {
+ nsObject, found, err := gbk.GetByKey(nsName)
if err != nil {
c.logger.Error(
"get namespace to enqueue Prometheus instances failed",
diff --git a/pkg/prometheus/agent/statefulset.go b/pkg/prometheus/agent/statefulset.go
index 3075c8bfdd5..7d7fbfb9132 100644
--- a/pkg/prometheus/agent/statefulset.go
+++ b/pkg/prometheus/agent/statefulset.go
@@ -212,7 +212,7 @@ func makeStatefulSetSpec(
operator.Zone(topologyZone),
}
if topologyZone != "" {
- reloaderOpts = append(reloaderOpts, operator.InzoneShard(ptr.To(cg.InzoneShardForShard(shard))))
+ reloaderOpts = append(reloaderOpts, operator.InzoneShard(new(cg.InzoneShardForShard(shard))))
}
operatorInitContainers = append(operatorInitContainers,
prompkg.BuildConfigReloader(
@@ -249,8 +249,8 @@ func makeStatefulSetSpec(
Resources: cpf.Resources,
TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
SecurityContext: &corev1.SecurityContext{
- ReadOnlyRootFilesystem: ptr.To(true),
- AllowPrivilegeEscalation: ptr.To(false),
+ ReadOnlyRootFilesystem: new(true),
+ AllowPrivilegeEscalation: new(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
@@ -277,11 +277,11 @@ func makeStatefulSetSpec(
InitContainers: initContainers,
SecurityContext: cpf.SecurityContext,
ServiceAccountName: cpf.ServiceAccountName,
- AutomountServiceAccountToken: ptr.To(ptr.Deref(cpf.AutomountServiceAccountToken, true)),
+ AutomountServiceAccountToken: new(ptr.Deref(cpf.AutomountServiceAccountToken, true)),
NodeSelector: cg.NodeSelectorWithTopologyZone(shard),
SchedulerName: cpf.SchedulerName,
PriorityClassName: cpf.PriorityClassName,
- TerminationGracePeriodSeconds: ptr.To(ptr.Deref(cpf.TerminationGracePeriodSeconds, prompkg.DefaultTerminationGracePeriodSeconds)),
+ TerminationGracePeriodSeconds: new(ptr.Deref(cpf.TerminationGracePeriodSeconds, prompkg.DefaultTerminationGracePeriodSeconds)),
Volumes: volumes,
Tolerations: cpf.Tolerations,
Affinity: cpf.Affinity,
diff --git a/pkg/prometheus/agent/statefulset_test.go b/pkg/prometheus/agent/statefulset_test.go
index 54b3349bea7..ec81358b2d1 100644
--- a/pkg/prometheus/agent/statefulset_test.go
+++ b/pkg/prometheus/agent/statefulset_test.go
@@ -62,10 +62,10 @@ func TestWALCompression(t *testing.T) {
shouldContain bool
}{
// Nil should not have either flag.
- {"v2.30.0", ptr.To(false), "--storage.agent.wal-compression", false},
+ {"v2.30.0", new(false), "--storage.agent.wal-compression", false},
{"v2.32.0", nil, "--storage.agent.wal-compression", false},
- {"v2.32.0", ptr.To(false), "--no-storage.agent.wal-compression", true},
- {"v2.32.0", ptr.To(true), "--storage.agent.wal-compression", true},
+ {"v2.32.0", new(false), "--no-storage.agent.wal-compression", true},
+ {"v2.32.0", new(true), "--storage.agent.wal-compression", true},
}
for _, test := range tests {
@@ -232,11 +232,11 @@ func TestStatefulSetDNSPolicyAndDNSConfig(t *testing.T) {
Options: []monitoringv1.PodDNSConfigOption{
{
Name: "ndots",
- Value: ptr.To("5"),
+ Value: new("5"),
},
},
}
- monitoringDNSPolicyPtr := ptr.To(monitoringv1.DNSPolicy(monitoringDNSPolicy))
+ monitoringDNSPolicyPtr := new(monitoringv1.DNSPolicy(monitoringDNSPolicy))
// Create the PrometheusAgent object with DNS settings
prometheusAgent := monitoringv1alpha1.PrometheusAgent{
@@ -272,7 +272,7 @@ func TestScrapeFailureLogFileVolumeMountPresent(t *testing.T) {
sset, err := makeDaemonSetFromPrometheus(monitoringv1alpha1.PrometheusAgent{
Spec: monitoringv1alpha1.PrometheusAgentSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- ScrapeFailureLogFile: ptr.To("file.log"),
+ ScrapeFailureLogFile: new("file.log"),
},
},
})
@@ -307,7 +307,7 @@ func TestScrapeFailureLogFileVolumeMountNotPresent(t *testing.T) {
sset, err := makeStatefulSetFromPrometheus(monitoringv1alpha1.PrometheusAgent{
Spec: monitoringv1alpha1.PrometheusAgentSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- ScrapeFailureLogFile: ptr.To("/tmp/file.log"),
+ ScrapeFailureLogFile: new("/tmp/file.log"),
},
},
})
@@ -393,8 +393,8 @@ func TestStatefulSetenableServiceLinks(t *testing.T) {
enableServiceLinks *bool
expectedEnableServiceLinks *bool
}{
- {enableServiceLinks: ptr.To(false), expectedEnableServiceLinks: ptr.To(false)},
- {enableServiceLinks: ptr.To(true), expectedEnableServiceLinks: ptr.To(true)},
+ {enableServiceLinks: new(false), expectedEnableServiceLinks: new(false)},
+ {enableServiceLinks: new(true), expectedEnableServiceLinks: new(true)},
{enableServiceLinks: nil, expectedEnableServiceLinks: nil},
}
@@ -473,13 +473,13 @@ func TestStatefulSetUpdateStrategy(t *testing.T) {
updateStrategy: &monitoringv1.StatefulSetUpdateStrategy{
Type: monitoringv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &monitoringv1.RollingUpdateStatefulSetStrategy{
- MaxUnavailable: ptr.To(intstr.FromInt(1)),
+ MaxUnavailable: new(intstr.FromInt(1)),
},
},
exp: appsv1.StatefulSetUpdateStrategy{
Type: appsv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{
- MaxUnavailable: ptr.To(intstr.FromInt(1)),
+ MaxUnavailable: new(intstr.FromInt(1)),
},
},
},
@@ -519,7 +519,7 @@ func TestConfigReloaderTopologyZoneEnvVar(t *testing.T) {
{
name: "shard 0 gets zone-a",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{
Values: []string{"zone-a", "zone-b"},
},
@@ -530,7 +530,7 @@ func TestConfigReloaderTopologyZoneEnvVar(t *testing.T) {
{
name: "shard 1 gets zone-b",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{
Values: []string{"zone-a", "zone-b"},
},
diff --git a/pkg/prometheus/agent/test_utils.go b/pkg/prometheus/agent/test_utils.go
index 65d39e8d631..dab3aaffc62 100644
--- a/pkg/prometheus/agent/test_utils.go
+++ b/pkg/prometheus/agent/test_utils.go
@@ -204,12 +204,12 @@ func createTestCasesForTestAutomountServiceAccountToken() []testcaseForTestAutom
},
{
name: "automountServiceAccountToken set to true",
- automountServiceAccountToken: ptr.To(true),
+ automountServiceAccountToken: new(true),
expectedValue: true,
},
{
name: "automountServiceAccountToken set to false",
- automountServiceAccountToken: ptr.To(false),
+ automountServiceAccountToken: new(false),
expectedValue: false,
},
}
@@ -240,7 +240,7 @@ func createTestCasesForTestStartupProbeTimeoutSeconds() []testcaseForTestStartup
expectedStartupFailureThreshold: 60,
},
{
- maximumStartupDurationSeconds: ptr.To(int32(600)),
+ maximumStartupDurationSeconds: new(int32(600)),
expectedStartupPeriodSeconds: 60,
expectedStartupFailureThreshold: 10,
},
diff --git a/pkg/prometheus/common.go b/pkg/prometheus/common.go
index 9a1c83496a3..f2927e12f87 100644
--- a/pkg/prometheus/common.go
+++ b/pkg/prometheus/common.go
@@ -50,6 +50,7 @@ const (
DefaultPortName = "web"
DefaultLogFileVolume = "log-file"
DefaultLogDirectory = "/var/log/prometheus"
+ DefaultRetention = "24h"
// DefaultTerminationGracePeriodSeconds defines how long Kubernetes should
// wait before killing Prometheus on pod termination.
@@ -73,6 +74,16 @@ var (
LabelPrometheusName = "prometheus-name"
)
+// RetentionTimeOrDefault returns the configured time-based retention or the
+// default retention when neither time nor size are configured.
+func RetentionTimeOrDefault(retention monitoringv1.Duration, retentionSize monitoringv1.ByteSize) monitoringv1.Duration {
+ if retention == "" && retentionSize == "" {
+ return monitoringv1.Duration(DefaultRetention)
+ }
+
+ return retention
+}
+
// LabelSelectorForStatefulSets returns a label selector which selects
// statefulsets deployed with the server or agent mode.
func LabelSelectorForStatefulSets(mode string) string {
@@ -398,7 +409,7 @@ func BuildConfigReloader(
}
func ShareProcessNamespace(p monitoringv1.PrometheusInterface) *bool {
- return ptr.To(
+ return new(
ptr.Deref(
p.GetCommonPrometheusFields().ReloadStrategy,
monitoringv1.HTTPReloadStrategyType,
diff --git a/pkg/prometheus/common_test.go b/pkg/prometheus/common_test.go
index 35447847e11..68d87516f64 100644
--- a/pkg/prometheus/common_test.go
+++ b/pkg/prometheus/common_test.go
@@ -42,49 +42,49 @@ func TestStartupProbeTimeoutSeconds(t *testing.T) {
expectedMaxStartupDuration: 900,
},
{
- maximumStartupDurationSeconds: ptr.To(int32(0)),
+ maximumStartupDurationSeconds: new(int32(0)),
expectedStartupPeriodSeconds: 15,
expectedStartupFailureThreshold: 60,
expectedMaxStartupDuration: 900,
},
{
- maximumStartupDurationSeconds: ptr.To(int32(1)),
+ maximumStartupDurationSeconds: new(int32(1)),
expectedStartupPeriodSeconds: 15,
expectedStartupFailureThreshold: 60,
expectedMaxStartupDuration: 900,
},
{
- maximumStartupDurationSeconds: ptr.To(int32(60)),
+ maximumStartupDurationSeconds: new(int32(60)),
expectedStartupPeriodSeconds: 60,
expectedStartupFailureThreshold: 1,
expectedMaxStartupDuration: 60,
},
{
- maximumStartupDurationSeconds: ptr.To(int32(600)),
+ maximumStartupDurationSeconds: new(int32(600)),
expectedStartupPeriodSeconds: 60,
expectedStartupFailureThreshold: 10,
expectedMaxStartupDuration: 600,
},
{
- maximumStartupDurationSeconds: ptr.To(int32(900)),
+ maximumStartupDurationSeconds: new(int32(900)),
expectedStartupPeriodSeconds: 60,
expectedStartupFailureThreshold: 15,
expectedMaxStartupDuration: 900,
},
{
- maximumStartupDurationSeconds: ptr.To(int32(1200)),
+ maximumStartupDurationSeconds: new(int32(1200)),
expectedStartupPeriodSeconds: 60,
expectedStartupFailureThreshold: 20,
expectedMaxStartupDuration: 1200,
},
{
- maximumStartupDurationSeconds: ptr.To(int32(129)),
+ maximumStartupDurationSeconds: new(int32(129)),
expectedStartupPeriodSeconds: 43,
expectedStartupFailureThreshold: 3,
expectedMaxStartupDuration: 129,
},
{
- maximumStartupDurationSeconds: ptr.To(int32(322)),
+ maximumStartupDurationSeconds: new(int32(322)),
expectedStartupPeriodSeconds: 54,
expectedStartupFailureThreshold: 6,
expectedMaxStartupDuration: 324,
@@ -180,28 +180,28 @@ func TestBuildCommonPrometheusArgsWithOTLPReceiver(t *testing.T) {
// OTLP receiver not supported.
{
version: "2.46.0",
- enableOTLPReceiver: ptr.To(true),
+ enableOTLPReceiver: new(true),
expectedOTLPFeatureEnabled: false,
expectedOTLPReceiverFlag: false,
},
// OTLP receiver supported starting with v2.47.0.
{
version: "2.47.0",
- enableOTLPReceiver: ptr.To(true),
+ enableOTLPReceiver: new(true),
expectedOTLPFeatureEnabled: true,
expectedOTLPReceiverFlag: false,
},
// OTLP receiver supported but not enabled.
{
version: "2.47.0",
- enableOTLPReceiver: ptr.To(false),
+ enableOTLPReceiver: new(false),
expectedOTLPFeatureEnabled: false,
expectedOTLPReceiverFlag: false,
},
// OTLP receiver config supported but version not support
{
version: "2.46.0",
- enableOTLPReceiver: ptr.To(false),
+ enableOTLPReceiver: new(false),
OTLPConfig: &monitoringv1.OTLPConfig{
PromoteResourceAttributes: []string{"aa", "bb"},
},
@@ -231,21 +231,21 @@ func TestBuildCommonPrometheusArgsWithOTLPReceiver(t *testing.T) {
// Test higher version from which enable-feature available.
{
version: "2.54.0",
- enableOTLPReceiver: ptr.To(true),
+ enableOTLPReceiver: new(true),
expectedOTLPFeatureEnabled: true,
expectedOTLPReceiverFlag: false,
},
// Test higher version from which web.enable-otlp-receiver arg available.
{
version: "3.0.0",
- enableOTLPReceiver: ptr.To(true),
+ enableOTLPReceiver: new(true),
expectedOTLPFeatureEnabled: false,
expectedOTLPReceiverFlag: true,
},
// Test higher version but not enabled.
{
version: "3.0.0",
- enableOTLPReceiver: ptr.To(false),
+ enableOTLPReceiver: new(false),
expectedOTLPFeatureEnabled: false,
expectedOTLPReceiverFlag: false,
},
@@ -304,7 +304,7 @@ func TestNodeSelectorWithTopologyZone(t *testing.T) {
nodeSelector: map[string]string{"foo": "bar"},
prometheusTopologySharding: false,
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b"}},
},
expectedSelector: map[string]string{"foo": "bar"},
@@ -335,7 +335,7 @@ func TestNodeSelectorWithTopologyZone(t *testing.T) {
name: "Topology mode with no values returns original selector",
nodeSelector: map[string]string{"foo": "bar"},
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{}},
},
prometheusTopologySharding: true,
@@ -345,7 +345,7 @@ func TestNodeSelectorWithTopologyZone(t *testing.T) {
name: "Topology mode shard #0 with 2 zones assigns first zone",
nodeSelector: map[string]string{"foo": "bar"},
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b"}},
},
prometheusTopologySharding: true,
@@ -356,7 +356,7 @@ func TestNodeSelectorWithTopologyZone(t *testing.T) {
name: "Topology mode shard #1 with 2 zones assigns second zone",
nodeSelector: map[string]string{"foo": "bar"},
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b"}},
},
prometheusTopologySharding: true,
@@ -367,7 +367,7 @@ func TestNodeSelectorWithTopologyZone(t *testing.T) {
name: "Topology mode shard #2 with 2 zones assigns first zone",
nodeSelector: map[string]string{"foo": "bar"},
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b"}},
},
prometheusTopologySharding: true,
@@ -378,7 +378,7 @@ func TestNodeSelectorWithTopologyZone(t *testing.T) {
name: "Topology mode shard #3 with 2 zones assigns second zone",
nodeSelector: map[string]string{"foo": "bar"},
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b"}},
},
prometheusTopologySharding: true,
@@ -389,7 +389,7 @@ func TestNodeSelectorWithTopologyZone(t *testing.T) {
name: "Topology mode overrides existing topology.kubernetes.io/zone",
nodeSelector: map[string]string{"topology.kubernetes.io/zone": "will-be-replaced"},
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b"}},
},
prometheusTopologySharding: true,
@@ -400,7 +400,7 @@ func TestNodeSelectorWithTopologyZone(t *testing.T) {
name: "Topology mode with nil nodeSelector creates new map",
nodeSelector: nil,
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a"}},
},
prometheusTopologySharding: true,
diff --git a/pkg/prometheus/operator.go b/pkg/prometheus/operator.go
index 2ad8b50bbe3..22a2af060c6 100644
--- a/pkg/prometheus/operator.go
+++ b/pkg/prometheus/operator.go
@@ -41,12 +41,13 @@ import (
// Whenever the value of one of these parameters is changed, it triggers an
// update of the managed statefulsets.
type Config struct {
- LocalHost string
- ReloaderConfig operator.ContainerConfig
- PrometheusDefaultBaseImage string
- ThanosDefaultBaseImage string
- Annotations operator.Map
- Labels operator.Map
+ LocalHost string
+ ReloaderConfig operator.ContainerConfig
+ PrometheusDefaultBaseImage string
+ ThanosDefaultBaseImage string
+ Annotations operator.Map
+ Labels operator.Map
+ WatchObjectRefsInAllNamespaces bool
}
// StatefulSetGetter returns a statefulset object identified by
diff --git a/pkg/prometheus/operator_test.go b/pkg/prometheus/operator_test.go
index dc32e8d07d0..093493f6ae9 100644
--- a/pkg/prometheus/operator_test.go
+++ b/pkg/prometheus/operator_test.go
@@ -29,7 +29,6 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes/fake"
- "k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
@@ -116,7 +115,7 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
},
},
expectErr: true,
@@ -126,9 +125,9 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
ManagedIdentity: &monitoringv1.ManagedIdentity{
- ClientID: ptr.To("client-id"),
+ ClientID: new("client-id"),
},
OAuth: &monitoringv1.AzureOAuth{
TenantID: "00000000-a12b-3cd4-e56f-000000000000",
@@ -149,12 +148,12 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
ManagedIdentity: &monitoringv1.ManagedIdentity{
- ClientID: ptr.To("client-id"),
+ ClientID: new("client-id"),
},
SDK: &monitoringv1.AzureSDK{
- TenantID: ptr.To("00000000-a12b-3cd4-e56f-000000000000"),
+ TenantID: new("00000000-a12b-3cd4-e56f-000000000000"),
},
},
},
@@ -165,9 +164,9 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
ManagedIdentity: &monitoringv1.ManagedIdentity{
- ClientID: ptr.To(""),
+ ClientID: new(""),
},
},
},
@@ -179,9 +178,9 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
ManagedIdentity: &monitoringv1.ManagedIdentity{
- ClientID: ptr.To(""),
+ ClientID: new(""),
},
},
},
@@ -192,9 +191,9 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
SDK: &monitoringv1.AzureSDK{
- TenantID: ptr.To("00000000-a12b-3cd4-e56f-000000000000"),
+ TenantID: new("00000000-a12b-3cd4-e56f-000000000000"),
},
OAuth: &monitoringv1.AzureOAuth{
TenantID: "00000000-a12b-3cd4-e56f-000000000000",
@@ -215,7 +214,7 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
OAuth: &monitoringv1.AzureOAuth{
TenantID: "00000000-a12b-3cd4-e56f-000000000000",
ClientID: "invalid",
@@ -235,7 +234,7 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
WorkloadIdentity: &monitoringv1.AzureWorkloadIdentity{
ClientID: "00000000-a12b-3cd4-e56f-000000000000",
TenantID: "11111111-a12b-3cd4-e56f-000000000000",
@@ -248,7 +247,7 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
WorkloadIdentity: &monitoringv1.AzureWorkloadIdentity{
ClientID: "invalid-uuid",
TenantID: "11111111-a12b-3cd4-e56f-000000000000",
@@ -262,7 +261,7 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
WorkloadIdentity: &monitoringv1.AzureWorkloadIdentity{
ClientID: "00000000-a12b-3cd4-e56f-000000000000",
TenantID: "invalid-uuid",
@@ -276,9 +275,9 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
ManagedIdentity: &monitoringv1.ManagedIdentity{
- ClientID: ptr.To("00000000-a12b-3cd4-e56f-000000000000"),
+ ClientID: new("00000000-a12b-3cd4-e56f-000000000000"),
},
WorkloadIdentity: &monitoringv1.AzureWorkloadIdentity{
ClientID: "00000000-a12b-3cd4-e56f-000000000000",
@@ -293,7 +292,7 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
OAuth: &monitoringv1.AzureOAuth{
TenantID: "00000000-a12b-3cd4-e56f-000000000000",
ClientID: "00000000-0000-0000-0000-000000000000",
@@ -317,9 +316,9 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
SDK: &monitoringv1.AzureSDK{
- TenantID: ptr.To("00000000-a12b-3cd4-e56f-000000000000"),
+ TenantID: new("00000000-a12b-3cd4-e56f-000000000000"),
},
WorkloadIdentity: &monitoringv1.AzureWorkloadIdentity{
ClientID: "00000000-a12b-3cd4-e56f-000000000000",
@@ -334,7 +333,7 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
},
},
expectErr: true,
@@ -345,7 +344,7 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
WorkloadIdentity: &monitoringv1.AzureWorkloadIdentity{
ClientID: "00000000-a12b-3cd4-e56f-000000000000",
TenantID: "11111111-a12b-3cd4-e56f-000000000000",
@@ -360,7 +359,7 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
OAuth: &monitoringv1.AzureOAuth{
TenantID: "00000000-a12b-3cd4-e56f-000000000000",
ClientID: "00000000-0000-0000-0000-000000000000",
@@ -381,9 +380,9 @@ func TestValidateRemoteWriteConfig(t *testing.T) {
spec: monitoringv1.RemoteWriteSpec{
URL: monitoringv1.URL("http://example.com"),
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
SDK: &monitoringv1.AzureSDK{
- TenantID: ptr.To("00000000-a12b-3cd4-e56f-000000000000"),
+ TenantID: new("00000000-a12b-3cd4-e56f-000000000000"),
},
},
},
@@ -786,7 +785,7 @@ func TestStatefulSetReporterProcess(t *testing.T) {
},
Spec: monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- Replicas: ptr.To(int32(2)),
+ Replicas: new(int32(2)),
},
},
},
@@ -836,8 +835,8 @@ func TestStatefulSetReporterProcess(t *testing.T) {
},
Spec: monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- Replicas: ptr.To(int32(1)),
- Shards: ptr.To(int32(2)),
+ Replicas: new(int32(1)),
+ Shards: new(int32(2)),
},
},
},
@@ -892,8 +891,8 @@ func TestStatefulSetReporterProcess(t *testing.T) {
},
Spec: monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- Replicas: ptr.To(int32(1)),
- Shards: ptr.To(int32(2)),
+ Replicas: new(int32(1)),
+ Shards: new(int32(2)),
},
},
},
@@ -949,8 +948,8 @@ func TestStatefulSetReporterProcess(t *testing.T) {
},
Spec: monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- Replicas: ptr.To(int32(2)),
- Shards: ptr.To(int32(2)),
+ Replicas: new(int32(2)),
+ Shards: new(int32(2)),
},
},
},
diff --git a/pkg/prometheus/promcfg.go b/pkg/prometheus/promcfg.go
index d068fee60cb..8ff14160be9 100644
--- a/pkg/prometheus/promcfg.go
+++ b/pkg/prometheus/promcfg.go
@@ -65,6 +65,10 @@ const (
nodeZoneMetaLabel = "__meta_kubernetes_node_label_topology_kubernetes_io_zone"
nodeZonePresentMetaLabel = "__meta_kubernetes_node_labelpresent_topology_kubernetes_io_zone"
endpointSliceZoneMetaLabel = "__meta_kubernetes_endpointslice_endpoint_zone"
+ // podZoneMetaLabel and podZonePresentMetaLabel are the SD meta labels for the
+ // topology.kubernetes.io/zone pod label injected by PodTopologyLabelsAdmission (K8s >= 1.35).
+ podZoneMetaLabel = "__meta_kubernetes_pod_label_topology_kubernetes_io_zone"
+ podZonePresentMetaLabel = "__meta_kubernetes_pod_labelpresent_topology_kubernetes_io_zone"
)
var invalidLabelCharRE = regexp.MustCompile(`[^a-zA-Z0-9_]`)
@@ -86,6 +90,7 @@ type ConfigGenerator struct {
daemonSet bool
prometheusTopologySharding bool
prometheusRetentionPolicies bool
+ podTopologyLabelsSupported bool
inlineTLSConfig bool
bypassVersionCheck bool
@@ -117,6 +122,17 @@ func WithPrometheusRetentionPolicies() ConfigGeneratorOption {
}
}
+// WithPodTopologyLabelsSupport tells the config generator that the topology.kubernetes.io/zone label is injected as a pod label. In that case, the operator
+// no longer forces attach_metadata.node=true for topology sharding and instead
+// uses the pod label for zone detection.
+func WithPodTopologyLabelsSupport() ConfigGeneratorOption {
+ return func(cg *ConfigGenerator) {
+ cg.podTopologyLabelsSupported = true
+ }
+}
+
+// WithInlineTLSConfig is an API only used by
+// https://github.com/open-telemetry/opentelemetry-operator.
func WithInlineTLSConfig() ConfigGeneratorOption {
return func(cg *ConfigGenerator) {
cg.inlineTLSConfig = true
@@ -268,6 +284,7 @@ func (cg *ConfigGenerator) WithKeyVals(keyvals ...any) *ConfigGenerator {
daemonSet: cg.daemonSet,
prometheusTopologySharding: cg.prometheusTopologySharding,
prometheusRetentionPolicies: cg.prometheusRetentionPolicies,
+ podTopologyLabelsSupported: cg.podTopologyLabelsSupported,
inlineTLSConfig: cg.inlineTLSConfig,
bypassVersionCheck: cg.bypassVersionCheck,
}
@@ -294,6 +311,7 @@ func (cg *ConfigGenerator) WithMinimumVersion(version string) *ConfigGenerator {
daemonSet: cg.daemonSet,
prometheusTopologySharding: cg.prometheusTopologySharding,
prometheusRetentionPolicies: cg.prometheusRetentionPolicies,
+ podTopologyLabelsSupported: cg.podTopologyLabelsSupported,
inlineTLSConfig: cg.inlineTLSConfig,
bypassVersionCheck: cg.bypassVersionCheck,
}
@@ -323,6 +341,7 @@ func (cg *ConfigGenerator) WithMaximumVersion(version string) *ConfigGenerator {
daemonSet: cg.daemonSet,
prometheusTopologySharding: cg.prometheusTopologySharding,
prometheusRetentionPolicies: cg.prometheusRetentionPolicies,
+ podTopologyLabelsSupported: cg.podTopologyLabelsSupported,
inlineTLSConfig: cg.inlineTLSConfig,
bypassVersionCheck: cg.bypassVersionCheck,
}
@@ -1036,7 +1055,7 @@ func (cg *ConfigGenerator) GenerateServerConfiguration(
})
// Storage config
- cfg, err = cg.appendStorageSettingsConfig(cfg, p.Spec.Exemplars)
+ cfg, err = cg.appendStorageSettingsConfig(cfg, p.Spec.Exemplars, p.Spec.Retention, p.Spec.RetentionSize)
if err != nil {
return nil, fmt.Errorf("generating storage_settings configuration failed: %w", err)
}
@@ -1073,13 +1092,24 @@ func (cg *ConfigGenerator) GenerateServerConfiguration(
return yaml.Marshal(cfg)
}
-func (cg *ConfigGenerator) appendStorageSettingsConfig(cfg yaml.MapSlice, exemplars *monitoringv1.Exemplars) (yaml.MapSlice, error) {
+func (cg *ConfigGenerator) appendStorageSettingsConfig(
+ cfg yaml.MapSlice,
+ exemplars *monitoringv1.Exemplars,
+ retention monitoringv1.Duration,
+ retentionSize monitoringv1.ByteSize,
+) (yaml.MapSlice, error) {
var (
storage yaml.MapSlice
+ tsdbSlice yaml.MapSlice
cgStorage = cg.WithMinimumVersion("2.29.0")
tsdb = cg.prom.GetCommonPrometheusFields().TSDB
)
+ err := tsdb.Validate()
+ if err != nil {
+ return cfg, err
+ }
+
if exemplars != nil && exemplars.MaxSize != nil {
storage = cgStorage.AppendMapItem(storage, "exemplars", yaml.MapSlice{
{
@@ -1089,13 +1119,30 @@ func (cg *ConfigGenerator) appendStorageSettingsConfig(cfg yaml.MapSlice, exempl
})
}
- if tsdb != nil && tsdb.OutOfOrderTimeWindow != nil {
- storage = cg.WithMinimumVersion("2.39.0").AppendMapItem(storage, "tsdb", yaml.MapSlice{
- {
- Key: "out_of_order_time_window",
- Value: *tsdb.OutOfOrderTimeWindow,
- },
- })
+ if tsdb != nil {
+ if tsdb.OutOfOrderTimeWindow != nil {
+ tsdbSlice = cg.WithMinimumVersion("2.39.0").AppendMapItem(tsdbSlice, "out_of_order_time_window", *tsdb.OutOfOrderTimeWindow)
+ }
+
+ if tsdb.StaleSeriesCompactionThreshold != nil {
+ tsdbSlice = cg.WithMinimumVersion("3.10.0").AppendMapItem(tsdbSlice, "stale_series_compaction_threshold", tsdb.StaleSeriesCompactionThreshold.AsApproximateFloat64())
+ }
+ }
+
+ if cg.WithMinimumVersion("3.11.0").IsCompatible() {
+ var retentionSlice yaml.MapSlice
+ retentionTime := string(RetentionTimeOrDefault(retention, retentionSize))
+ if retentionTime != "" {
+ retentionSlice = append(retentionSlice, yaml.MapItem{Key: "time", Value: retentionTime})
+ }
+ if retentionSize != "" {
+ retentionSlice = append(retentionSlice, yaml.MapItem{Key: "size", Value: string(retentionSize)})
+ }
+ tsdbSlice = append(tsdbSlice, yaml.MapItem{Key: "retention", Value: retentionSlice})
+ }
+
+ if len(tsdbSlice) > 0 {
+ storage = append(storage, yaml.MapItem{Key: "tsdb", Value: tsdbSlice})
}
if len(storage) == 0 {
@@ -2250,8 +2297,9 @@ func (cg *ConfigGenerator) appendShardingRelabelingWithLabel(relabelings []yaml.
if cg.isTopologyShardingActive() {
modulus = cg.shardsPerZone(shards)
shardEnvVar = operator.InzoneShardEnvVar
+
+ // Step 1: populate __tmp_topology from endpointslice zone (no-op for pod role).
relabelings = append(relabelings,
- // Populate __tmp_topology from endpointslice zone label (no-op for pod role).
yaml.MapSlice{
{Key: "source_labels", Value: []string{endpointSliceZoneMetaLabel, topologyTmpLabel}},
{Key: "target_label", Value: topologyTmpLabel},
@@ -2259,15 +2307,35 @@ func (cg *ConfigGenerator) appendShardingRelabelingWithLabel(relabelings []yaml.
{Key: "replacement", Value: "$1"},
{Key: "action", Value: "replace"},
},
- // Fallback to node topology label (requires attach_metadata: {node: true}).
- yaml.MapSlice{
- {Key: "source_labels", Value: []string{nodeZoneMetaLabel, nodeZonePresentMetaLabel, topologyTmpLabel}},
- {Key: "target_label", Value: topologyTmpLabel},
- {Key: "regex", Value: "(.+);true;"},
- {Key: "replacement", Value: "$1"},
- {Key: "action", Value: "replace"},
- },
- // Keep only targets in the assigned zone, unless __tmp_disable_sharding is set.
+ )
+
+ // Step 2: if __tmp_topology is still empty, use the pod topology label
+ // (K8s >= 1.35, PodTopologyLabelsAdmission) or the node label (older clusters,
+ // requires attach_metadata: {node: true}) as fallback.
+ if cg.podTopologyLabelsSupported {
+ relabelings = append(relabelings,
+ yaml.MapSlice{
+ {Key: "source_labels", Value: []string{podZoneMetaLabel, podZonePresentMetaLabel, topologyTmpLabel}},
+ {Key: "target_label", Value: topologyTmpLabel},
+ {Key: "regex", Value: "(.+);true;"},
+ {Key: "replacement", Value: "$1"},
+ {Key: "action", Value: "replace"},
+ },
+ )
+ } else {
+ relabelings = append(relabelings,
+ yaml.MapSlice{
+ {Key: "source_labels", Value: []string{nodeZoneMetaLabel, nodeZonePresentMetaLabel, topologyTmpLabel}},
+ {Key: "target_label", Value: topologyTmpLabel},
+ {Key: "regex", Value: "(.+);true;"},
+ {Key: "replacement", Value: "$1"},
+ {Key: "action", Value: "replace"},
+ },
+ )
+ }
+
+ // Step 3: keep only targets in the assigned zone, unless __tmp_disable_sharding is set.
+ relabelings = append(relabelings,
yaml.MapSlice{
{Key: "source_labels", Value: []string{topologyTmpLabel, hashLabelNameForDisablingSharding}},
{Key: "regex", Value: fmt.Sprintf("$(%s);|.+;.+", operator.TopologyZoneEnvVar)},
@@ -3254,15 +3322,34 @@ func (cg *ConfigGenerator) GenerateAgentConfiguration(
// TSDB
tsdb := cpf.TSDB
- if tsdb != nil && tsdb.OutOfOrderTimeWindow != nil {
- var storage yaml.MapSlice
- storage = cg.AppendMapItem(storage, "tsdb", yaml.MapSlice{
- {
- Key: "out_of_order_time_window",
- Value: *tsdb.OutOfOrderTimeWindow,
- },
- })
- cfg = cg.WithMinimumVersion("2.54.0").AppendMapItem(cfg, "storage", storage)
+
+ err = tsdb.Validate()
+ if err != nil {
+ return nil, err
+ }
+
+ if tsdb != nil {
+ if tsdb.OutOfOrderTimeWindow != nil {
+ var storage yaml.MapSlice
+ storage = cg.AppendMapItem(storage, "tsdb", yaml.MapSlice{
+ {
+ Key: "out_of_order_time_window",
+ Value: *tsdb.OutOfOrderTimeWindow,
+ },
+ })
+ cfg = cg.WithMinimumVersion("2.54.0").AppendMapItem(cfg, "storage", storage)
+ }
+
+ if tsdb.StaleSeriesCompactionThreshold != nil {
+ var storage yaml.MapSlice
+ storage = cg.AppendMapItem(storage, "tsdb", yaml.MapSlice{
+ {
+ Key: "stale_series_compaction_threshold",
+ Value: tsdb.StaleSeriesCompactionThreshold.AsApproximateFloat64(),
+ },
+ })
+ cfg = cg.WithMinimumVersion("3.10.0").AppendMapItem(cfg, "storage", storage)
+ }
}
// Remote write config
@@ -5025,6 +5112,18 @@ func (cg *ConfigGenerator) appendOTLPConfig(cfg yaml.MapSlice) (yaml.MapSlice, e
otlpConfig.PromoteScopeMetadata)
}
+ if otlpConfig.LabelNameUnderscoreSanitization != nil {
+ otlp = cg.WithMinimumVersion("3.8.0").AppendMapItem(otlp,
+ "label_name_underscore_sanitization",
+ otlpConfig.LabelNameUnderscoreSanitization)
+ }
+
+ if otlpConfig.LabelNamePreserveMultipleUnderscores != nil {
+ otlp = cg.WithMinimumVersion("3.8.0").AppendMapItem(otlp,
+ "label_name_preserve_multiple_underscores",
+ otlpConfig.LabelNamePreserveMultipleUnderscores)
+ }
+
if len(otlp) == 0 {
return cfg, nil
}
@@ -5319,21 +5418,25 @@ func (cg *ConfigGenerator) InzoneShardForShard(shardIndex int32) int32 {
return shardIndex / numZones
}
-// mergeAttachMetadataForTopology forces attach_metadata.node=true when topology
-// sharding is active. Node metadata is required to determine the target's zone via
-// the __meta_kubernetes_node_label_topology_kubernetes_io_zone label.
-// Returns amc unchanged when topology sharding is not active or node is already true.
+// mergeAttachMetadataForTopology returns amc unchanged when topology sharding is
+// not active, when podTopologyLabelsSupported is true (zone label is injected
+// directly onto pods), or when node metadata is already requested.
+// Otherwise it forces attach_metadata.node=true so that zone detection via node
+// labels is available.
func (cg *ConfigGenerator) mergeAttachMetadataForTopology(amc *attachMetadataConfig, minimumVersion string) *attachMetadataConfig {
if !cg.isTopologyShardingActive() {
return amc
}
+ if cg.podTopologyLabelsSupported {
+ return amc
+ }
if amc != nil && amc.node() {
return amc
}
return &attachMetadataConfig{
MinimumVersion: minimumVersion,
attachMetadata: &monitoringv1.AttachMetadata{
- Node: ptr.To(true),
+ Node: new(true),
},
}
}
diff --git a/pkg/prometheus/promcfg_test.go b/pkg/prometheus/promcfg_test.go
index 5f0e344e016..697d59fdb04 100644
--- a/pkg/prometheus/promcfg_test.go
+++ b/pkg/prometheus/promcfg_test.go
@@ -184,8 +184,8 @@ func TestGlobalSettings(t *testing.T) {
"prometheus": "prometheus-k8s-1",
"some-other-key": "some-value",
},
- PrometheusExternalLabelName: ptr.To("prometheus"),
- ReplicaExternalLabelName: ptr.To("prometheus_replica"),
+ PrometheusExternalLabelName: new("prometheus"),
+ ReplicaExternalLabelName: new("prometheus_replica"),
Golden: "external_label_specified_along_with_reserved_labels.golden",
},
{
@@ -201,7 +201,7 @@ func TestGlobalSettings(t *testing.T) {
Version: "v2.55.0",
ScrapeInterval: "30s",
EvaluationInterval: "30s",
- ScrapeFailureLogFile: ptr.To("/tmp/file.log"),
+ ScrapeFailureLogFile: new("/tmp/file.log"),
Golden: "scrape_failure_log_file.golden",
},
{
@@ -209,7 +209,7 @@ func TestGlobalSettings(t *testing.T) {
Version: "v2.55.0",
ScrapeInterval: "30s",
EvaluationInterval: "30s",
- ScrapeFailureLogFile: ptr.To("file.log"),
+ ScrapeFailureLogFile: new("file.log"),
Golden: "scrape_failure_log_file_empty_path.golden",
},
{
@@ -217,7 +217,7 @@ func TestGlobalSettings(t *testing.T) {
Version: "v2.54.0",
ScrapeInterval: "30s",
EvaluationInterval: "30s",
- ScrapeFailureLogFile: ptr.To("file.log"),
+ ScrapeFailureLogFile: new("file.log"),
Golden: "scrape_failure_log_file_unsupported_version.golden",
},
{
@@ -385,7 +385,7 @@ func TestTopologyZoneExternalLabel(t *testing.T) {
shardingStrategy: &monitoringv1.ShardingStrategy{
Mode: ptr.To(monitoringv1.TopologyShardingStrategyMode),
Topology: &monitoringv1.TopologyShardingStrategy{
- ExternalLabelName: ptr.To("topology_zone"),
+ ExternalLabelName: new("topology_zone"),
Values: []string{"zone-a", "zone-b"},
},
},
@@ -397,7 +397,7 @@ func TestTopologyZoneExternalLabel(t *testing.T) {
shardingStrategy: &monitoringv1.ShardingStrategy{
Mode: ptr.To(monitoringv1.TopologyShardingStrategyMode),
Topology: &monitoringv1.TopologyShardingStrategy{
- ExternalLabelName: ptr.To(""),
+ ExternalLabelName: new(""),
Values: []string{"zone-a", "zone-b"},
},
},
@@ -486,7 +486,7 @@ func TestNamespaceSetCorrectly(t *testing.T) {
MatchNames: []string{"test1", "test2"},
},
AttachMetadata: &monitoringv1.AttachMetadata{
- Node: ptr.To(true),
+ Node: new(true),
},
},
},
@@ -605,7 +605,7 @@ func TestNamespaceSetCorrectlyForPodMonitor(t *testing.T) {
MatchNames: []string{"test"},
},
AttachMetadata: &monitoringv1.AttachMetadata{
- Node: ptr.To(true),
+ Node: new(true),
},
},
}
@@ -830,7 +830,7 @@ func TestProbeIngressSDConfigGeneration(t *testing.T) {
RelabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "foo",
- Replacement: ptr.To("bar"),
+ Replacement: new("bar"),
Action: "replace",
},
},
@@ -853,7 +853,7 @@ func TestProbeIngressSDConfigGeneration(t *testing.T) {
func TestProbeIngressSDConfigGenerationWithShards(t *testing.T) {
p := defaultPrometheus()
- p.Spec.Shards = ptr.To(int32(2))
+ p.Spec.Shards = new(int32(2))
cg := mustNewConfigGenerator(t, p)
cfg, err := cg.GenerateServerConfiguration(
@@ -889,7 +889,7 @@ func TestProbeIngressSDConfigGenerationWithShards(t *testing.T) {
RelabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "foo",
- Replacement: ptr.To("bar"),
+ Replacement: new("bar"),
Action: "replace",
},
},
@@ -947,7 +947,7 @@ func TestProbeIngressSDConfigGenerationWithLabelEnforce(t *testing.T) {
RelabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "foo",
- Replacement: ptr.To("bar"),
+ Replacement: new("bar"),
Action: "replace",
},
},
@@ -1146,7 +1146,7 @@ func TestAlertmanagerBearerToken(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
BearerTokenFile: "/some/file/on/disk",
},
@@ -1203,7 +1203,7 @@ func TestAlertmanagerBasicAuth(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
BasicAuth: &monitoringv1.BasicAuth{
Username: corev1.SecretKeySelector{
@@ -1279,7 +1279,7 @@ func TestAlertmanagerSigv4(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
Sigv4: &monitoringv1.Sigv4{
Profile: "profilename",
@@ -1345,7 +1345,7 @@ func TestAlertmanagerAPIVersion(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion1),
},
@@ -1360,7 +1360,7 @@ func TestAlertmanagerAPIVersion(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion2),
},
@@ -1375,7 +1375,7 @@ func TestAlertmanagerAPIVersion(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion2),
},
@@ -1390,7 +1390,7 @@ func TestAlertmanagerAPIVersion(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion1),
},
@@ -1405,7 +1405,7 @@ func TestAlertmanagerAPIVersion(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion1),
},
@@ -1420,7 +1420,7 @@ func TestAlertmanagerAPIVersion(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion2),
},
@@ -1462,7 +1462,7 @@ func TestAlertmanagerTimeoutConfig(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion2),
Timeout: ptr.To(monitoringv1.Duration("60s")),
@@ -1520,10 +1520,10 @@ func TestAlertmanagerEnableHttp2(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion2),
- EnableHttp2: ptr.To(tc.enableHTTP2),
+ EnableHttp2: new(tc.enableHTTP2),
},
},
}
@@ -1554,24 +1554,24 @@ func TestAlertmanagerRelabelConfigs(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion2),
RelabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "namespace",
- Replacement: ptr.To("ns1"),
+ Replacement: new("ns1"),
},
{
Action: "replace",
Regex: "(.+)(?::d+)",
- Replacement: ptr.To("$1:9537"),
+ Replacement: new("$1:9537"),
SourceLabels: []monitoringv1.LabelName{"__address__"},
TargetLabel: "__address__",
},
{
Action: "replace",
- Replacement: ptr.To("crio"),
+ Replacement: new("crio"),
TargetLabel: "job",
},
},
@@ -1621,13 +1621,13 @@ func TestAlertmanagerAlertRelabelConfigs(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion2),
AlertRelabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "namespace",
- Replacement: ptr.To("ns1"),
+ Replacement: new("ns1"),
},
},
},
@@ -1688,12 +1688,12 @@ func TestAdditionalScrapeConfigs(t *testing.T) {
},
{
name: "one prometheus shard",
- result: getCfg(ptr.To(int32(1))),
+ result: getCfg(new(int32(1))),
golden: "AdditionalScrapeConfigs_one_prometheus_shard.golden",
},
{
name: "sharded prometheus",
- result: getCfg(ptr.To(int32(3))),
+ result: getCfg(new(int32(3))),
golden: "AdditionalScrapeConfigs_sharded prometheus.golden",
},
}
@@ -1711,7 +1711,7 @@ func TestAdditionalAlertRelabelConfigs(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
},
},
@@ -1768,13 +1768,13 @@ func TestNoEnforcedNamespaceLabelServiceMonitor(t *testing.T) {
{
Action: "replace",
Regex: "(.+)(?::d+)",
- Replacement: ptr.To("$1:9537"),
+ Replacement: new("$1:9537"),
SourceLabels: []monitoringv1.LabelName{"__address__"},
TargetLabel: "__address__",
},
{
Action: "replace",
- Replacement: ptr.To("crio"),
+ Replacement: new("crio"),
TargetLabel: "job",
},
},
@@ -1905,7 +1905,7 @@ func TestEnforcedNamespaceLabelPodMonitor(t *testing.T) {
PodTargetLabels: []string{"example", "env"},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
MetricRelabelConfigs: []monitoringv1.RelabelConfig{
{
@@ -1919,7 +1919,7 @@ func TestEnforcedNamespaceLabelPodMonitor(t *testing.T) {
{
Action: "replace",
Regex: "(.*)",
- Replacement: ptr.To("$1"),
+ Replacement: new("$1"),
SourceLabels: []monitoringv1.LabelName{"__meta_kubernetes_pod_ready"},
TargetLabel: "pod_ready",
},
@@ -1973,7 +1973,7 @@ func TestEnforcedNamespaceLabelOnExcludedPodMonitor(t *testing.T) {
PodTargetLabels: []string{"example", "env"},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
MetricRelabelConfigs: []monitoringv1.RelabelConfig{
{
@@ -1987,7 +1987,7 @@ func TestEnforcedNamespaceLabelOnExcludedPodMonitor(t *testing.T) {
{
Action: "replace",
Regex: "(.*)",
- Replacement: ptr.To("$1"),
+ Replacement: new("$1"),
SourceLabels: []monitoringv1.LabelName{"__meta_kubernetes_pod_ready"},
TargetLabel: "pod_ready",
},
@@ -2051,7 +2051,7 @@ func TestEnforcedNamespaceLabelServiceMonitor(t *testing.T) {
{
Action: "replace",
Regex: "(.*)",
- Replacement: ptr.To("$1"),
+ Replacement: new("$1"),
SourceLabels: []monitoringv1.LabelName{"__meta_kubernetes_pod_ready"},
TargetLabel: "pod_ready",
},
@@ -2123,7 +2123,7 @@ func TestEnforcedNamespaceLabelOnExcludedServiceMonitor(t *testing.T) {
{
Action: "replace",
Regex: "(.*)",
- Replacement: ptr.To("$1"),
+ Replacement: new("$1"),
SourceLabels: []monitoringv1.LabelName{"__meta_kubernetes_pod_ready"},
TargetLabel: "pod_ready",
},
@@ -2152,7 +2152,7 @@ func TestAdditionalAlertmanagers(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
},
},
@@ -2195,7 +2195,7 @@ func TestSettingHonorTimestampsInServiceMonitor(t *testing.T) {
TargetLabels: []string{"example", "env"},
Endpoints: []monitoringv1.Endpoint{
{
- HonorTimestamps: ptr.To(false),
+ HonorTimestamps: new(false),
Port: "web",
Interval: "30s",
},
@@ -2233,8 +2233,8 @@ func TestSettingHonorTimestampsInPodMonitor(t *testing.T) {
PodTargetLabels: []string{"example", "env"},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- HonorTimestamps: ptr.To(false),
- Port: ptr.To("web"),
+ HonorTimestamps: new(false),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -2269,7 +2269,7 @@ func TestSettingTrackTimestampsStalenessInServiceMonitor(t *testing.T) {
TargetLabels: []string{"example", "env"},
Endpoints: []monitoringv1.Endpoint{
{
- TrackTimestampsStaleness: ptr.To(false),
+ TrackTimestampsStaleness: new(false),
Port: "web",
Interval: "30s",
},
@@ -2307,8 +2307,8 @@ func TestSettingTrackTimestampsStalenessInPodMonitor(t *testing.T) {
PodTargetLabels: []string{"example", "env"},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- TrackTimestampsStaleness: ptr.To(false),
- Port: ptr.To("web"),
+ TrackTimestampsStaleness: new(false),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -2371,7 +2371,7 @@ func TestSettingScrapeProtocolsInServiceMonitor(t *testing.T) {
ScrapeProtocols: tc.scrape,
Endpoints: []monitoringv1.Endpoint{
{
- HonorTimestamps: ptr.To(false),
+ HonorTimestamps: new(false),
Port: "web",
Interval: "30s",
},
@@ -2432,7 +2432,7 @@ func TestSettingScrapeFallbackProtocolInServiceMonitor(t *testing.T) {
FallbackScrapeProtocol: tc.fallbackScrapeProtocol,
Endpoints: []monitoringv1.Endpoint{
{
- HonorTimestamps: ptr.To(false),
+ HonorTimestamps: new(false),
Port: "web",
Interval: "30s",
},
@@ -2500,8 +2500,8 @@ func TestSettingScrapeProtocolsInPodMonitor(t *testing.T) {
ScrapeProtocols: tc.scrape,
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- TrackTimestampsStaleness: ptr.To(false),
- Port: ptr.To("web"),
+ TrackTimestampsStaleness: new(false),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -2561,8 +2561,8 @@ func TestSettingScrapeFallbackProtocolInPodMonitor(t *testing.T) {
FallbackScrapeProtocol: tc.fallbackScrapeProtocol,
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- TrackTimestampsStaleness: ptr.To(false),
- Port: ptr.To("web"),
+ TrackTimestampsStaleness: new(false),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -2600,7 +2600,7 @@ func TestHonorTimestampsOverriding(t *testing.T) {
TargetLabels: []string{"example", "env"},
Endpoints: []monitoringv1.Endpoint{
{
- HonorTimestamps: ptr.To(true),
+ HonorTimestamps: new(true),
Port: "web",
Interval: "30s",
},
@@ -2761,7 +2761,7 @@ func TestEndpointOAuth2(t *testing.T) {
"param2": "value2",
},
TLSConfig: &monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -2772,9 +2772,9 @@ func TestEndpointOAuth2(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -2881,7 +2881,7 @@ func TestEndpointOAuth2(t *testing.T) {
Spec: monitoringv1.PodMonitorSpec{
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
HTTPConfig: monitoringv1.HTTPConfig{
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
@@ -3007,7 +3007,7 @@ func TestPodTargetLabelsFromPodMonitor(t *testing.T) {
PodTargetLabels: []string{"example", "env"},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -3047,7 +3047,7 @@ func TestPodTargetLabelsFromPodMonitorAndGlobal(t *testing.T) {
PodTargetLabels: []string{"local"},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -3117,7 +3117,7 @@ func generateTestConfig(t *testing.T, version string) ([]byte, error) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "alertmanager-main",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
},
},
@@ -3128,7 +3128,7 @@ func generateTestConfig(t *testing.T, version string) ([]byte, error) {
"label2": "value2",
},
Version: version,
- Replicas: ptr.To(int32(1)),
+ Replicas: new(int32(1)),
ServiceMonitorSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"group": "group1",
@@ -3308,14 +3308,14 @@ func makeServiceMonitors() map[string]*monitoringv1.ServiceMonitor {
{
Action: "replace",
Regex: "(.*)",
- Replacement: ptr.To("$1"),
+ Replacement: new("$1"),
SourceLabels: []monitoringv1.LabelName{"__meta_kubernetes_pod_ready"},
TargetLabel: "pod_ready",
},
{
Action: "replace",
Regex: "(.*)",
- Replacement: ptr.To("$1"),
+ Replacement: new("$1"),
SourceLabels: []monitoringv1.LabelName{"__meta_kubernetes_pod_node_name"},
TargetLabel: "nodename",
},
@@ -3347,7 +3347,7 @@ func makePodMonitors() map[string]*monitoringv1.PodMonitor {
},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -3371,7 +3371,7 @@ func makePodMonitors() map[string]*monitoringv1.PodMonitor {
},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -3395,7 +3395,7 @@ func makePodMonitors() map[string]*monitoringv1.PodMonitor {
},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
Path: "/federate",
Params: map[string][]string{"metrics[]": {"{__name__=~\"job:.*\"}"}},
@@ -3421,7 +3421,7 @@ func makePodMonitors() map[string]*monitoringv1.PodMonitor {
},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
MetricRelabelConfigs: []monitoringv1.RelabelConfig{
{
@@ -3457,20 +3457,20 @@ func makePodMonitors() map[string]*monitoringv1.PodMonitor {
},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
RelabelConfigs: []monitoringv1.RelabelConfig{
{
Action: "replace",
Regex: "(.*)",
- Replacement: ptr.To("$1"),
+ Replacement: new("$1"),
SourceLabels: []monitoringv1.LabelName{"__meta_kubernetes_pod_ready"},
TargetLabel: "pod_ready",
},
{
Action: "replace",
Regex: "(.*)",
- Replacement: ptr.To("$1"),
+ Replacement: new("$1"),
SourceLabels: []monitoringv1.LabelName{"__meta_kubernetes_pod_node_name"},
TargetLabel: "nodename",
},
@@ -3550,22 +3550,22 @@ func TestHonorTimestamps(t *testing.T) {
Expected: "{}\n",
},
{
- UserHonorTimestamps: ptr.To(false),
+ UserHonorTimestamps: new(false),
OverrideHonorTimestamps: true,
Expected: "honor_timestamps: false\n",
},
{
- UserHonorTimestamps: ptr.To(false),
+ UserHonorTimestamps: new(false),
OverrideHonorTimestamps: false,
Expected: "honor_timestamps: false\n",
},
{
- UserHonorTimestamps: ptr.To(true),
+ UserHonorTimestamps: new(true),
OverrideHonorTimestamps: true,
Expected: "honor_timestamps: false\n",
},
{
- UserHonorTimestamps: ptr.To(true),
+ UserHonorTimestamps: new(true),
OverrideHonorTimestamps: false,
Expected: "honor_timestamps: true\n",
},
@@ -3600,11 +3600,11 @@ func TestTrackTimestampsStaleness(t *testing.T) {
Expected: "{}\n",
},
{
- UserTrackTimestampsStaleness: ptr.To(false),
+ UserTrackTimestampsStaleness: new(false),
Expected: "track_timestamps_staleness: false\n",
},
{
- UserTrackTimestampsStaleness: ptr.To(true),
+ UserTrackTimestampsStaleness: new(true),
Expected: "track_timestamps_staleness: true\n",
},
}
@@ -3694,7 +3694,7 @@ func TestSampleLimits(t *testing.T) {
p := defaultPrometheus()
p.Spec.CommonPrometheusFields.Version = tc.version
if tc.globalLimit >= 0 {
- p.Spec.SampleLimit = ptr.To(uint64(tc.globalLimit))
+ p.Spec.SampleLimit = new(uint64(tc.globalLimit))
}
if tc.golden == "SampleLimits_GlobalLimit1000_Enforce2000.golden" {
@@ -3921,7 +3921,7 @@ func TestRemoteReadConfig(t *testing.T) {
version: "v2.25.0",
remoteRead: monitoringv1.RemoteReadSpec{
URL: "http://example.com",
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
golden: "RemoteReadConfig_v2.25.0.golden",
},
@@ -3929,7 +3929,7 @@ func TestRemoteReadConfig(t *testing.T) {
version: "v2.26.0",
remoteRead: monitoringv1.RemoteReadSpec{
URL: "http://example.com",
- FollowRedirects: ptr.To(false),
+ FollowRedirects: new(false),
},
golden: "RemoteReadConfig_v2.26.0_NotFollowRedirects.golden",
},
@@ -3937,7 +3937,7 @@ func TestRemoteReadConfig(t *testing.T) {
version: "v2.26.0",
remoteRead: monitoringv1.RemoteReadSpec{
URL: "http://example.com",
- FilterExternalLabels: ptr.To(true),
+ FilterExternalLabels: new(true),
},
golden: "RemoteReadConfig_v2.26.0_FilterExternalLabels.golden",
},
@@ -3952,7 +3952,7 @@ func TestRemoteReadConfig(t *testing.T) {
version: "v2.34.0",
remoteRead: monitoringv1.RemoteReadSpec{
URL: "http://example.com",
- FilterExternalLabels: ptr.To(false),
+ FilterExternalLabels: new(false),
},
golden: "RemoteReadConfig_v2.34.0_NotFilterExternalLabels.golden",
},
@@ -3960,7 +3960,7 @@ func TestRemoteReadConfig(t *testing.T) {
version: "v2.34.0",
remoteRead: monitoringv1.RemoteReadSpec{
URL: "http://example.com",
- FilterExternalLabels: ptr.To(true),
+ FilterExternalLabels: new(true),
},
golden: "RemoteReadConfig_v2.34.0_FilterExternalLabels.golden",
},
@@ -3986,9 +3986,9 @@ func TestRemoteReadConfig(t *testing.T) {
remoteRead: monitoringv1.RemoteReadSpec{
URL: "http://example.com",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -4197,9 +4197,9 @@ func TestRemoteWriteConfig(t *testing.T) {
remoteWrite: monitoringv1.RemoteWriteSpec{
URL: "http://example.com",
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
ManagedIdentity: &monitoringv1.ManagedIdentity{
- ClientID: ptr.To("00000000-0000-0000-0000-000000000000"),
+ ClientID: new("00000000-0000-0000-0000-000000000000"),
},
},
},
@@ -4210,7 +4210,7 @@ func TestRemoteWriteConfig(t *testing.T) {
remoteWrite: monitoringv1.RemoteWriteSpec{
URL: "http://example.com",
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
OAuth: &monitoringv1.AzureOAuth{
TenantID: "00000000-a12b-3cd4-e56f-000000000000",
ClientID: "00000000-0000-0000-0000-000000000000",
@@ -4230,9 +4230,9 @@ func TestRemoteWriteConfig(t *testing.T) {
remoteWrite: monitoringv1.RemoteWriteSpec{
URL: "http://example.com",
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
SDK: &monitoringv1.AzureSDK{
- TenantID: ptr.To("00000000-a12b-3cd4-e56f-000000000000"),
+ TenantID: new("00000000-a12b-3cd4-e56f-000000000000"),
},
},
},
@@ -4243,9 +4243,9 @@ func TestRemoteWriteConfig(t *testing.T) {
remoteWrite: monitoringv1.RemoteWriteSpec{
URL: "http://example.com",
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
ManagedIdentity: &monitoringv1.ManagedIdentity{
- ClientID: ptr.To("00000000-0000-0000-0000-000000000000"),
+ ClientID: new("00000000-0000-0000-0000-000000000000"),
},
},
},
@@ -4256,7 +4256,7 @@ func TestRemoteWriteConfig(t *testing.T) {
remoteWrite: monitoringv1.RemoteWriteSpec{
URL: "http://example.com",
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzureGovernment"),
+ Cloud: new("AzureGovernment"),
WorkloadIdentity: &monitoringv1.AzureWorkloadIdentity{
ClientID: "00000000-a12b-3cd4-e56f-000000000000",
TenantID: "11111111-a12b-3cd4-e56f-000000000000",
@@ -4521,9 +4521,9 @@ func TestRemoteWriteConfig(t *testing.T) {
URL: "http://example.com",
FollowRedirects: &followRedirects,
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -4544,9 +4544,9 @@ func TestRemoteWriteConfig(t *testing.T) {
URL: "http://example.com",
FollowRedirects: &followRedirects,
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -4588,7 +4588,7 @@ func TestRemoteWriteConfig(t *testing.T) {
remoteWrite: monitoringv1.RemoteWriteSpec{
URL: "http://example.com",
MessageVersion: ptr.To(monitoringv1.RemoteWriteMessageVersion2_0),
- RoundRobinDNS: ptr.To(true),
+ RoundRobinDNS: new(true),
},
golden: "RemoteWriteConfig_v3.1.0.golden",
},
@@ -4597,7 +4597,7 @@ func TestRemoteWriteConfig(t *testing.T) {
remoteWrite: monitoringv1.RemoteWriteSpec{
URL: "http://example.com",
MetadataConfig: &monitoringv1.MetadataConfig{
- MaxSamplesPerSend: ptr.To(int32(10)),
+ MaxSamplesPerSend: new(int32(10)),
},
},
golden: "RemoteWriteConfig_v2.28.0_MaxSamplesPerSendMetadataConfig.golden",
@@ -4607,7 +4607,7 @@ func TestRemoteWriteConfig(t *testing.T) {
remoteWrite: monitoringv1.RemoteWriteSpec{
URL: "http://example.com",
MetadataConfig: &monitoringv1.MetadataConfig{
- MaxSamplesPerSend: ptr.To(int32(10)),
+ MaxSamplesPerSend: new(int32(10)),
},
},
golden: "RemoteWriteConfig_v2.29.0_MaxSamplesPerSendMetadataConfig.golden",
@@ -4632,7 +4632,7 @@ func TestRemoteWriteConfig(t *testing.T) {
Key: "secret-key",
},
Region: "us-central-0",
- UseFIPSSTSEndpoint: ptr.To(true),
+ UseFIPSSTSEndpoint: new(true),
},
QueueConfig: &monitoringv1.QueueConfig{
Capacity: 1000,
@@ -4671,7 +4671,7 @@ func TestRemoteWriteConfig(t *testing.T) {
Key: "secret-key",
},
Region: "us-central-0",
- UseFIPSSTSEndpoint: ptr.To(true),
+ UseFIPSSTSEndpoint: new(true),
},
QueueConfig: &monitoringv1.QueueConfig{
Capacity: 1000,
@@ -4703,11 +4703,11 @@ func TestRemoteWriteConfig(t *testing.T) {
remoteWrite: monitoringv1.RemoteWriteSpec{
URL: "http://example.com",
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzurePublic"),
+ Cloud: new("AzurePublic"),
ManagedIdentity: &monitoringv1.ManagedIdentity{
- ClientID: ptr.To("00000000-a12b-3cd4-e56f-000000000000"),
+ ClientID: new("00000000-a12b-3cd4-e56f-000000000000"),
},
- Scope: ptr.To("https://custom.monitor.azure.com/.default"),
+ Scope: new("https://custom.monitor.azure.com/.default"),
},
},
golden: "RemoteWriteConfig_AzureADScope_v3.8.0.golden",
@@ -4717,11 +4717,11 @@ func TestRemoteWriteConfig(t *testing.T) {
remoteWrite: monitoringv1.RemoteWriteSpec{
URL: "http://example.com",
AzureAD: &monitoringv1.AzureAD{
- Cloud: ptr.To("AzurePublic"),
+ Cloud: new("AzurePublic"),
ManagedIdentity: &monitoringv1.ManagedIdentity{
- ClientID: ptr.To("00000000-a12b-3cd4-e56f-000000000000"),
+ ClientID: new("00000000-a12b-3cd4-e56f-000000000000"),
},
- Scope: ptr.To("https://custom.monitor.azure.com/.default"),
+ Scope: new("https://custom.monitor.azure.com/.default"),
},
},
golden: "RemoteWriteConfig_AzureADScope_v3.9.0.golden",
@@ -4890,7 +4890,7 @@ func TestLabelLimits(t *testing.T) {
p.Spec.CommonPrometheusFields.Version = tc.version
if tc.enforcedLabelLimit >= 0 {
- p.Spec.EnforcedLabelLimit = ptr.To(uint64(tc.enforcedLabelLimit))
+ p.Spec.EnforcedLabelLimit = new(uint64(tc.enforcedLabelLimit))
}
serviceMonitor := monitoringv1.ServiceMonitor{
@@ -4997,7 +4997,7 @@ func TestLabelNameLengthLimits(t *testing.T) {
p.Spec.CommonPrometheusFields.Version = tc.version
if tc.enforcedLabelNameLengthLimit >= 0 {
- p.Spec.EnforcedLabelNameLengthLimit = ptr.To(uint64(tc.enforcedLabelNameLengthLimit))
+ p.Spec.EnforcedLabelNameLengthLimit = new(uint64(tc.enforcedLabelNameLengthLimit))
}
podMonitor := monitoringv1.PodMonitor{
@@ -5011,7 +5011,7 @@ func TestLabelNameLengthLimits(t *testing.T) {
Spec: monitoringv1.PodMonitorSpec{
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -5104,7 +5104,7 @@ func TestLabelValueLengthLimits(t *testing.T) {
p.Spec.CommonPrometheusFields.Version = tc.version
if tc.enforcedLabelValueLengthLimit >= 0 {
- p.Spec.EnforcedLabelValueLengthLimit = ptr.To(uint64(tc.enforcedLabelValueLengthLimit))
+ p.Spec.EnforcedLabelValueLengthLimit = new(uint64(tc.enforcedLabelValueLengthLimit))
}
probe := monitoringv1.Probe{
@@ -5121,9 +5121,9 @@ func TestLabelValueLengthLimits(t *testing.T) {
URL: "blackbox.exporter.io",
Path: "/probe",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -5197,20 +5197,20 @@ func TestKeepDroppedTargets(t *testing.T) {
}{
{
version: "v2.46.0",
- enforcedKeepDroppedTargets: ptr.To(uint64(1000)),
- keepDroppedTargets: ptr.To(uint64(50)),
+ enforcedKeepDroppedTargets: new(uint64(1000)),
+ keepDroppedTargets: new(uint64(50)),
golden: "KeepDroppedTargetsNotAddedInConfig.golden",
},
{
version: "v2.47.0",
- enforcedKeepDroppedTargets: ptr.To(uint64(1000)),
- keepDroppedTargets: ptr.To(uint64(2000)),
+ enforcedKeepDroppedTargets: new(uint64(1000)),
+ keepDroppedTargets: new(uint64(2000)),
golden: "KeepDroppedTargetsOverridedWithEnforcedValue.golden",
},
{
version: "v2.47.0",
- enforcedKeepDroppedTargets: ptr.To(uint64(1000)),
- keepDroppedTargets: ptr.To(uint64(500)),
+ enforcedKeepDroppedTargets: new(uint64(1000)),
+ keepDroppedTargets: new(uint64(500)),
golden: "KeepDroppedTargets.golden",
},
} {
@@ -5270,79 +5270,79 @@ func TestNativeHistogramConfig(t *testing.T) {
{
version: "v3.0.0",
nativeHistogramConfig: monitoringv1.NativeHistogramConfig{
- NativeHistogramBucketLimit: ptr.To(uint64(10)),
- ScrapeClassicHistograms: ptr.To(true),
- NativeHistogramMinBucketFactor: ptr.To(resource.MustParse("12.124")),
- ConvertClassicHistogramsToNHCB: ptr.To(true),
+ NativeHistogramBucketLimit: new(uint64(10)),
+ ScrapeClassicHistograms: new(true),
+ NativeHistogramMinBucketFactor: new(resource.MustParse("12.124")),
+ ConvertClassicHistogramsToNHCB: new(true),
},
golden: "NativeHistogramConfig.golden",
},
{
version: "v2.54.0",
nativeHistogramConfig: monitoringv1.NativeHistogramConfig{
- NativeHistogramBucketLimit: ptr.To(uint64(10)),
- ScrapeClassicHistograms: ptr.To(true),
- NativeHistogramMinBucketFactor: ptr.To(resource.MustParse("12.124")),
- ConvertClassicHistogramsToNHCB: ptr.To(true),
+ NativeHistogramBucketLimit: new(uint64(10)),
+ ScrapeClassicHistograms: new(true),
+ NativeHistogramMinBucketFactor: new(resource.MustParse("12.124")),
+ ConvertClassicHistogramsToNHCB: new(true),
},
golden: "native-histograms/NativeHistogramConfigMissConvertClassicHistogramsToNHCB.golden",
},
{
version: "v2.46.0",
nativeHistogramConfig: monitoringv1.NativeHistogramConfig{
- NativeHistogramBucketLimit: ptr.To(uint64(10)),
- ScrapeClassicHistograms: ptr.To(true),
- NativeHistogramMinBucketFactor: ptr.To(resource.MustParse("12.124")),
- ConvertClassicHistogramsToNHCB: ptr.To(true),
+ NativeHistogramBucketLimit: new(uint64(10)),
+ ScrapeClassicHistograms: new(true),
+ NativeHistogramMinBucketFactor: new(resource.MustParse("12.124")),
+ ConvertClassicHistogramsToNHCB: new(true),
},
golden: "native-histograms/NativeHistogramConfigWithMissNativeHistogramMinBucketFactor.golden",
},
{
version: "v2.44.0",
nativeHistogramConfig: monitoringv1.NativeHistogramConfig{
- NativeHistogramBucketLimit: ptr.To(uint64(10)),
- ScrapeClassicHistograms: ptr.To(true),
- NativeHistogramMinBucketFactor: ptr.To(resource.MustParse("12.124")),
- ConvertClassicHistogramsToNHCB: ptr.To(true),
+ NativeHistogramBucketLimit: new(uint64(10)),
+ ScrapeClassicHistograms: new(true),
+ NativeHistogramMinBucketFactor: new(resource.MustParse("12.124")),
+ ConvertClassicHistogramsToNHCB: new(true),
},
golden: "NativeHistogramConfigWithMissALL.golden",
},
{
version: "3.0.0-rc.0",
nativeHistogramConfig: monitoringv1.NativeHistogramConfig{
- NativeHistogramBucketLimit: ptr.To(uint64(10)),
- ScrapeClassicHistograms: ptr.To(true),
- NativeHistogramMinBucketFactor: ptr.To(resource.MustParse("12.124")),
- ConvertClassicHistogramsToNHCB: ptr.To(true),
+ NativeHistogramBucketLimit: new(uint64(10)),
+ ScrapeClassicHistograms: new(true),
+ NativeHistogramMinBucketFactor: new(resource.MustParse("12.124")),
+ ConvertClassicHistogramsToNHCB: new(true),
},
golden: "NativeHistogramConfigAlwaysScrapeClassicHistograms.golden",
},
{
version: "v3.8.0",
nativeHistogramConfig: monitoringv1.NativeHistogramConfig{
- ScrapeNativeHistograms: ptr.To(true),
- NativeHistogramBucketLimit: ptr.To(uint64(10)),
- ScrapeClassicHistograms: ptr.To(true),
- NativeHistogramMinBucketFactor: ptr.To(resource.MustParse("12.124")),
- ConvertClassicHistogramsToNHCB: ptr.To(true),
+ ScrapeNativeHistograms: new(true),
+ NativeHistogramBucketLimit: new(uint64(10)),
+ ScrapeClassicHistograms: new(true),
+ NativeHistogramMinBucketFactor: new(resource.MustParse("12.124")),
+ ConvertClassicHistogramsToNHCB: new(true),
},
golden: "NativeHistogramConfigWithScrapeNativeHistograms.golden",
},
{
version: "v3.7.0",
nativeHistogramConfig: monitoringv1.NativeHistogramConfig{
- ScrapeNativeHistograms: ptr.To(true),
- NativeHistogramBucketLimit: ptr.To(uint64(10)),
- ScrapeClassicHistograms: ptr.To(true),
- NativeHistogramMinBucketFactor: ptr.To(resource.MustParse("12.124")),
- ConvertClassicHistogramsToNHCB: ptr.To(true),
+ ScrapeNativeHistograms: new(true),
+ NativeHistogramBucketLimit: new(uint64(10)),
+ ScrapeClassicHistograms: new(true),
+ NativeHistogramMinBucketFactor: new(resource.MustParse("12.124")),
+ ConvertClassicHistogramsToNHCB: new(true),
},
golden: "NativeHistogramConfigMissScrapeNativeHistograms.golden",
},
{
version: "v3.8.0",
nativeHistogramConfig: monitoringv1.NativeHistogramConfig{
- ScrapeNativeHistograms: ptr.To(true),
+ ScrapeNativeHistograms: new(true),
},
golden: "NativeHistogramConfigOnlyScrapeNativeHistograms.golden",
},
@@ -5609,7 +5609,7 @@ func TestServiceMonitorEndpointFollowRedirects(t *testing.T) {
HTTPConfigWithProxyAndTLSFiles: monitoringv1.HTTPConfigWithProxyAndTLSFiles{
HTTPConfigWithTLSFiles: monitoringv1.HTTPConfigWithTLSFiles{
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
- FollowRedirects: ptr.To(tc.followRedirects),
+ FollowRedirects: new(tc.followRedirects),
},
},
},
@@ -5681,12 +5681,12 @@ func TestPodMonitorEndpointFollowRedirects(t *testing.T) {
Spec: monitoringv1.PodMonitorSpec{
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
HTTPConfig: monitoringv1.HTTPConfig{
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
- FollowRedirects: ptr.To(tc.followRedirects),
+ FollowRedirects: new(tc.followRedirects),
},
},
},
@@ -5764,7 +5764,7 @@ func TestServiceMonitorEndpointEnableHttp2(t *testing.T) {
HTTPConfigWithProxyAndTLSFiles: monitoringv1.HTTPConfigWithProxyAndTLSFiles{
HTTPConfigWithTLSFiles: monitoringv1.HTTPConfigWithTLSFiles{
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
- EnableHTTP2: ptr.To(tc.enableHTTP2),
+ EnableHTTP2: new(tc.enableHTTP2),
},
},
},
@@ -5813,8 +5813,8 @@ func TestPodMonitorPhaseFilter(t *testing.T) {
Spec: monitoringv1.PodMonitorSpec{
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- FilterRunning: ptr.To(false),
- Port: ptr.To("test"),
+ FilterRunning: new(false),
+ Port: new("test"),
},
},
},
@@ -5874,12 +5874,12 @@ func TestPodMonitorEndpointEnableHttp2(t *testing.T) {
Spec: monitoringv1.PodMonitorSpec{
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
HTTPConfig: monitoringv1.HTTPConfig{
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
- EnableHTTP2: ptr.To(tc.enableHTTP2),
+ EnableHTTP2: new(tc.enableHTTP2),
},
},
},
@@ -5920,7 +5920,7 @@ func TestRuntimeConfig(t *testing.T) {
Scenario: "Runtime GoGC is set to 25",
Version: "v2.53.0",
Runtime: &monitoringv1.RuntimeConfig{
- GoGC: ptr.To(int32(25)),
+ GoGC: new(int32(25)),
},
Golden: "RuntimeConfig_GoGC25.golden",
},
@@ -5928,12 +5928,13 @@ func TestRuntimeConfig(t *testing.T) {
Scenario: "Runtime GoGC is set to 25 but unsupported Prometheus Version",
Version: "v2.52.0",
Runtime: &monitoringv1.RuntimeConfig{
- GoGC: ptr.To(int32(25)),
+ GoGC: new(int32(25)),
},
Golden: "RuntimeConfig_GoGC_Not_Set.golden",
},
{
Scenario: "Runtime GoGC not specified",
+ Version: "v2.52.0",
Golden: "RuntimeConfig_GoGC_Not_Set.golden",
},
} {
@@ -5972,7 +5973,7 @@ func TestStorageSettingMaxExemplars(t *testing.T) {
{
Scenario: "Exemplars maxSize is set to 5000000",
Exemplars: &monitoringv1.Exemplars{
- MaxSize: ptr.To(int64(5000000)),
+ MaxSize: new(int64(5000000)),
},
Golden: "StorageSettingMaxExemplars_MaxSize5000000.golden",
},
@@ -5980,7 +5981,7 @@ func TestStorageSettingMaxExemplars(t *testing.T) {
Scenario: "max_exemplars is not set if version is less than v2.29.0",
Version: "v2.28.0",
Exemplars: &monitoringv1.Exemplars{
- MaxSize: ptr.To(int64(5000000)),
+ MaxSize: new(int64(5000000)),
},
Golden: "StorageSettingMaxExemplars_MaxSizeNotSet_v2.29.0.golden",
},
@@ -6019,11 +6020,12 @@ func TestStorageSettingMaxExemplars(t *testing.T) {
func TestTSDBConfig(t *testing.T) {
for _, tc := range []struct {
- name string
- p *monitoringv1.Prometheus
- version string
- tsdb *monitoringv1.TSDBSpec
- golden string
+ name string
+ p *monitoringv1.Prometheus
+ version string
+ tsdb *monitoringv1.TSDBSpec
+ golden string
+ expectErr bool
}{
{
name: "no TSDB config",
@@ -6045,6 +6047,36 @@ func TestTSDBConfig(t *testing.T) {
},
golden: "TSDB_config_greater_than_or_equal_to_v2.39.0.golden",
},
+ {
+ name: "TSDB StaleSeriesCompactionThreshold < v3.10.0",
+ version: "v3.9.0",
+ tsdb: &monitoringv1.TSDBSpec{
+ StaleSeriesCompactionThreshold: resource.NewQuantity(1, resource.DecimalSI),
+ },
+ golden: "TSDB_StaleSeriesCompactionThreshold_less_than_v3.10.0.golden",
+ },
+ {
+ name: "TSDB StaleSeriesCompactionThreshold >= v3.10.0",
+ version: "v3.10.0",
+ tsdb: &monitoringv1.TSDBSpec{
+ StaleSeriesCompactionThreshold: resource.NewQuantity(1, resource.DecimalSI),
+ },
+ golden: "TSDB_StaleSeriesCompactionThreshold_greater_than_or_equal_to_v3.10.0.golden",
+ },
+ {
+ name: "TSDB StaleSeriesCompactionThreshold > 1",
+ tsdb: &monitoringv1.TSDBSpec{
+ StaleSeriesCompactionThreshold: resource.NewQuantity(2, resource.DecimalSI),
+ },
+ expectErr: true,
+ },
+ {
+ name: "TSDB StaleSeriesCompactionThreshold < 0",
+ tsdb: &monitoringv1.TSDBSpec{
+ StaleSeriesCompactionThreshold: resource.NewQuantity(-1, resource.DecimalSI),
+ },
+ expectErr: true,
+ },
} {
t.Run(tc.name, func(t *testing.T) {
p := defaultPrometheus()
@@ -6055,6 +6087,77 @@ func TestTSDBConfig(t *testing.T) {
p.Spec.TSDB = tc.tsdb
}
+ err := p.Spec.TSDB.Validate()
+ if tc.expectErr {
+ require.Error(t, err)
+ return
+ }
+
+ cg := mustNewConfigGenerator(t, p)
+ cfg, err := cg.GenerateServerConfiguration(
+ p,
+ nil,
+ nil,
+ nil,
+ nil,
+ &assets.StoreBuilder{},
+ nil,
+ nil,
+ nil,
+ nil,
+ )
+ require.NoError(t, err)
+ golden.Assert(t, string(cfg), tc.golden)
+ })
+ }
+}
+
+func TestRetentionConfigFile(t *testing.T) {
+ for _, tc := range []struct {
+ name string
+ version string
+ retention monitoringv1.Duration
+ retentionSize monitoringv1.ByteSize
+ golden string
+ }{
+ {
+ name: "retention.time set with Prometheus >= v3.11.0",
+ version: "v3.11.0",
+ retention: "2d",
+ golden: "RetentionConfigFile_time_v3.11.0.golden",
+ },
+ {
+ name: "retention.size set with Prometheus >= v3.11.0",
+ version: "v3.11.0",
+ retentionSize: "512MB",
+ golden: "RetentionConfigFile_size_v3.11.0.golden",
+ },
+ {
+ name: "retention.time and retention.size set with Prometheus >= v3.11.0",
+ version: "v3.11.0",
+ retention: "2d",
+ retentionSize: "512MB",
+ golden: "RetentionConfigFile_time_size_v3.11.0.golden",
+ },
+ {
+ name: "retention defaults to 24h when neither field is set with Prometheus >= v3.11.0",
+ version: "v3.11.0",
+ golden: "RetentionConfigFile_default_v3.11.0.golden",
+ },
+ {
+ name: "retention is not in the configuration file for Prometheus < v3.11.0",
+ version: "v3.10.0",
+ retention: "2d",
+ retentionSize: "512MB",
+ golden: "RetentionConfigFile_v3.10.0.golden",
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ p := defaultPrometheus()
+ p.Spec.CommonPrometheusFields.Version = tc.version
+ p.Spec.Retention = tc.retention
+ p.Spec.RetentionSize = tc.retentionSize
+
cg := mustNewConfigGenerator(t, p)
cfg, err := cg.GenerateServerConfiguration(
p,
@@ -6076,11 +6179,12 @@ func TestTSDBConfig(t *testing.T) {
func TestTSDBConfigPrometheusAgent(t *testing.T) {
for _, tc := range []struct {
- name string
- p *monitoringv1.Prometheus
- version string
- tsdb *monitoringv1.TSDBSpec
- golden string
+ name string
+ p *monitoringv1.Prometheus
+ version string
+ tsdb *monitoringv1.TSDBSpec
+ golden string
+ expectErr bool
}{
{
name: "PrometheusAgent no TSDB config",
@@ -6103,6 +6207,36 @@ func TestTSDBConfigPrometheusAgent(t *testing.T) {
},
golden: "PrometheusAgent_TSDB_config_greater_than_or_equal_to_v2.54.0.golden",
},
+ {
+ name: "PrometheusAgent TSDB StaleSeriesCompactionThreshold < v3.10.0",
+ version: "v2.54.0",
+ tsdb: &monitoringv1.TSDBSpec{
+ StaleSeriesCompactionThreshold: resource.NewQuantity(1, resource.DecimalSI),
+ },
+ golden: "PrometheusAgent_TSDB_StaleSeriesCompactionThreshold_less_than_v3.10.0.golden",
+ },
+ {
+ name: "PrometheusAgent TSDB StaleSeriesCompactionThreshold >= v3.10.0",
+ version: "v3.10.0",
+ tsdb: &monitoringv1.TSDBSpec{
+ StaleSeriesCompactionThreshold: resource.NewQuantity(1, resource.DecimalSI),
+ },
+ golden: "PrometheusAgent_TSDB_StaleSeriesCompactionThreshold_greater_than_or_equal_to_v3.10.0.golden",
+ },
+ {
+ name: "PrometheusAgent TSDB StaleSeriesCompactionThreshold > 1",
+ tsdb: &monitoringv1.TSDBSpec{
+ StaleSeriesCompactionThreshold: resource.NewQuantity(2, resource.DecimalSI),
+ },
+ expectErr: true,
+ },
+ {
+ name: "PrometheusAgent TSDB StaleSeriesCompactionThreshold < 0",
+ tsdb: &monitoringv1.TSDBSpec{
+ StaleSeriesCompactionThreshold: resource.NewQuantity(-1, resource.DecimalSI),
+ },
+ expectErr: true,
+ },
} {
t.Run(tc.name, func(t *testing.T) {
p := defaultPrometheus()
@@ -6113,6 +6247,12 @@ func TestTSDBConfigPrometheusAgent(t *testing.T) {
p.Spec.TSDB = tc.tsdb
}
+ err := p.Spec.TSDB.Validate()
+ if tc.expectErr {
+ require.Error(t, err)
+ return
+ }
+
cg := mustNewConfigGenerator(t, p)
cfg, err := cg.GenerateAgentConfiguration(
nil,
@@ -6143,21 +6283,21 @@ func TestScrapeFailureLogFilePrometheusAgent(t *testing.T) {
{
name: "PrometheusAgent version < v2.55.0",
version: "v2.54.0",
- scrapeFailureLogFile: ptr.To("file.log"),
+ scrapeFailureLogFile: new("file.log"),
golden: "PrometheusAgent_scrapeFailureLogFile_less_than_v2.54.0.golden",
},
{
name: "PrometheusAgent version >= v2.55.0",
version: "v2.55.0",
- scrapeFailureLogFile: ptr.To("/tmp/file.log"),
+ scrapeFailureLogFile: new("/tmp/file.log"),
golden: "PrometheusAgent_scrapeFailureLogFile_greater_than_or_equal_to_v2.55.0.golden",
},
{
name: "PrometheusAgent version >= v2.55.0 and scrapeFailureLogFile with empty path",
version: "v2.55.0",
- scrapeFailureLogFile: ptr.To("file.log"),
+ scrapeFailureLogFile: new("file.log"),
golden: "PrometheusAgent_scrapeFailureLogFile_empty_path_v2.55.0.golden",
},
} {
@@ -6235,7 +6375,7 @@ func TestGenerateRelabelConfig(t *testing.T) {
{
// Test empty replacement
Action: "Replace",
- Replacement: ptr.To(""),
+ Replacement: new(""),
TargetLabel: "job",
},
},
@@ -6248,19 +6388,19 @@ func TestGenerateRelabelConfig(t *testing.T) {
{
Action: "Replace",
Regex: "(.+)(?::d+)",
- Replacement: ptr.To("$1:9537"),
+ Replacement: new("$1:9537"),
SourceLabels: []monitoringv1.LabelName{"__address__"},
TargetLabel: "__address__",
},
{
Action: "Replace",
- Replacement: ptr.To("crio"),
+ Replacement: new("crio"),
TargetLabel: "job",
},
{
// Test empty replacement
Action: "Replace",
- Replacement: ptr.To(""),
+ Replacement: new(""),
TargetLabel: "job",
},
},
@@ -6307,9 +6447,9 @@ func TestProbeSpecConfig(t *testing.T) {
URL: "example.com",
Path: "/probe",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -6340,13 +6480,13 @@ func TestProbeSpecConfig(t *testing.T) {
RelabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "foo",
- Replacement: ptr.To("bar"),
+ Replacement: new("bar"),
Action: "replace",
},
// Empty replacement case
{
TargetLabel: "foobar",
- Replacement: ptr.To(""),
+ Replacement: new(""),
Action: "replace",
},
},
@@ -6477,19 +6617,19 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
name: "explicit_job_name",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- JobName: ptr.To("explicit-test-scrape-config3"),
+ JobName: new("explicit-test-scrape-config3"),
},
golden: "ScrapeConfigSpecConfig_WithJobName.golden",
},
{
name: "explicit_job_name_with_relabel_config",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- JobName: ptr.To("explicit-test-scrape-config5"),
+ JobName: new("explicit-test-scrape-config5"),
RelabelConfigs: []monitoringv1.RelabelConfig{
{
Action: "Replace",
Regex: "(.+)(?::d+)",
- Replacement: ptr.To("$1:9537"),
+ Replacement: new("$1:9537"),
SourceLabels: []monitoringv1.LabelName{"__address__"},
TargetLabel: "__address__",
},
@@ -6500,7 +6640,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
name: "shard_config",
patchProm: func(p *monitoringv1.Prometheus) {
- p.Spec.Shards = ptr.To(int32(2))
+ p.Spec.Shards = new(int32(2))
},
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
StaticConfigs: []monitoringv1alpha1.StaticConfig{
@@ -6517,7 +6657,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
name: "already_sharded_config",
patchProm: func(p *monitoringv1.Prometheus) {
- p.Spec.Shards = ptr.To(int32(2))
+ p.Spec.Shards = new(int32(2))
},
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
StaticConfigs: []monitoringv1alpha1.StaticConfig{
@@ -6578,9 +6718,9 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
URL: "http://localhost:9100/sd.json",
RefreshInterval: &refreshInterval,
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -6600,7 +6740,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
name: "metrics_path",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- MetricsPath: ptr.To("/metrics"),
+ MetricsPath: new("/metrics"),
},
golden: "ScrapeConfigSpecConfig_MetricPath.golden",
},
@@ -6618,7 +6758,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
Action: "Replace",
Regex: "(.+)(?::d+)",
- Replacement: ptr.To("$1:9537"),
+ Replacement: new("$1:9537"),
SourceLabels: []monitoringv1.LabelName{"__address__"},
TargetLabel: "__address__",
},
@@ -6629,21 +6769,21 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
name: "honor_timestamp",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- HonorTimestamps: ptr.To(true),
+ HonorTimestamps: new(true),
},
golden: "ScrapeConfigSpecConfig_HonorTimeStamp.golden",
},
{
name: "track_timestamps_staleness",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- TrackTimestampsStaleness: ptr.To(true),
+ TrackTimestampsStaleness: new(true),
},
golden: "ScrapeConfigSpecConfig_TrackTimestampsStaleness.golden",
},
{
name: "honor_labels",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- HonorLabels: ptr.To(true),
+ HonorLabels: new(true),
},
golden: "ScrapeConfigSpecConfig_HonorLabels.golden",
},
@@ -6744,7 +6884,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
URL: "http://localhost:9100/sd.json",
TLSConfig: &monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(false),
+ InsecureSkipVerify: new(false),
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -6791,7 +6931,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
URL: "http://localhost:9100/sd.json",
TLSConfig: &monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -6816,18 +6956,18 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
name: "limits",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- SampleLimit: ptr.To(uint64(10000)),
- TargetLimit: ptr.To(uint64(1000)),
- LabelLimit: ptr.To(uint64(50)),
- LabelNameLengthLimit: ptr.To(uint64(40)),
- LabelValueLengthLimit: ptr.To(uint64(30)),
+ SampleLimit: new(uint64(10000)),
+ TargetLimit: new(uint64(1000)),
+ LabelLimit: new(uint64(50)),
+ LabelNameLengthLimit: new(uint64(40)),
+ LabelValueLengthLimit: new(uint64(30)),
},
golden: "ScrapeConfigSpecConfig_Limits.golden",
},
{
name: "params",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- MetricsPath: ptr.To("/federate"),
+ MetricsPath: new("/federate"),
Params: map[string][]string{"match[]": {"{job=\"prometheus\"}", "{__name__=~\"job:.*\"}"}},
},
golden: "ScrapeConfigSpecConfig_Params.golden",
@@ -6890,9 +7030,9 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
name: "proxy_settings",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -6911,9 +7051,9 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
name: "proxy_settings_with_muti_proxy_connect_header_values",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -6961,9 +7101,9 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
},
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -6996,7 +7136,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
Names: []string{"node.demo.do.prometheus.io"},
Type: ptr.To(monitoringv1alpha1.DNSRecordTypeA),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -7010,7 +7150,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
Names: []string{"node.demo.do.prometheus.io"},
Type: ptr.To(monitoringv1alpha1.DNSRecordTypeNS),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -7024,7 +7164,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
Names: []string{"node.demo.do.prometheus.io"},
Type: ptr.To(monitoringv1alpha1.DNSRecordTypeNS),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -7038,7 +7178,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
Names: []string{"node.demo.do.prometheus.io"},
Type: ptr.To(monitoringv1alpha1.DNSRecordTypeMX),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -7052,7 +7192,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
Names: []string{"node.demo.do.prometheus.io"},
Type: ptr.To(monitoringv1alpha1.DNSRecordTypeNS),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -7061,14 +7201,14 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
{
name: "enable_compression_is_set_to_true",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- EnableCompression: ptr.To(true),
+ EnableCompression: new(true),
},
golden: "ScrapeConfigSpecConfig_EnableCompression_True.golden",
},
{
name: "enable_compression_is_set_to_false",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- EnableCompression: ptr.To(false),
+ EnableCompression: new(false),
},
golden: "ScrapeConfigSpecConfig_EnableCompression_False.golden",
},
@@ -7076,7 +7216,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
name: "enable_http2_is_set_to_true_unsupported",
version: "v2.34.0",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
},
golden: "ScrapeConfigSpecConfig_EnableHTTP2_Unsupported.golden",
},
@@ -7084,7 +7224,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
name: "enable_http2_is_set_to_false_unsupported",
version: "v2.34.0",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
golden: "ScrapeConfigSpecConfig_EnableHTTP2_Unsupported.golden",
},
@@ -7092,7 +7232,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
name: "enable_http2_is_set_to_true",
version: "v2.35.0",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
},
golden: "ScrapeConfigSpecConfig_EnableHTTP2_True.golden",
},
@@ -7100,7 +7240,7 @@ func TestScrapeConfigSpecConfig(t *testing.T) {
name: "enable_http2_is_set_to_false",
version: "v2.35.0",
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
golden: "ScrapeConfigSpecConfig_EnableHTTP2_False.golden",
},
@@ -7346,12 +7486,12 @@ func TestScrapeConfigSpecConfigWithHTTPSD(t *testing.T) {
HTTPSDConfigs: []monitoringv1alpha1.HTTPSDConfig{
{
URL: "http://localhost:9100/sd.json",
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -7558,11 +7698,11 @@ func TestScrapeConfigSpecConfigWithKubernetesSD(t *testing.T) {
KubernetesSDConfigs: []monitoringv1alpha1.KubernetesSDConfig{
{
Role: monitoringv1alpha1.KubernetesRoleNode,
- APIServer: ptr.To("https://kubernetes.default.svc"),
+ APIServer: new("https://kubernetes.default.svc"),
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -7574,8 +7714,8 @@ func TestScrapeConfigSpecConfigWithKubernetesSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -7588,7 +7728,7 @@ func TestScrapeConfigSpecConfigWithKubernetesSD(t *testing.T) {
{
Role: monitoringv1alpha1.KubernetesRolePod,
Namespaces: &monitoringv1alpha1.NamespaceDiscovery{
- IncludeOwnNamespace: ptr.To(true),
+ IncludeOwnNamespace: new(true),
Names: []string{"ns1", "ns2"},
},
},
@@ -7617,7 +7757,7 @@ func TestScrapeConfigSpecConfigWithKubernetesSD(t *testing.T) {
{
Role: monitoringv1alpha1.KubernetesRolePod,
AttachMetadata: &monitoringv1alpha1.AttachMetadata{
- Node: ptr.To(true),
+ Node: new(true),
},
},
},
@@ -7631,7 +7771,7 @@ func TestScrapeConfigSpecConfigWithKubernetesSD(t *testing.T) {
{
Role: monitoringv1alpha1.KubernetesRoleService,
AttachMetadata: &monitoringv1alpha1.AttachMetadata{
- Node: ptr.To(true),
+ Node: new(true),
},
},
},
@@ -7647,7 +7787,7 @@ func TestScrapeConfigSpecConfigWithKubernetesSD(t *testing.T) {
Selectors: []monitoringv1alpha1.K8SSelectorConfig{
{
Role: monitoringv1alpha1.KubernetesRoleNode,
- Label: ptr.To("component=executor"),
+ Label: new("component=executor"),
},
},
},
@@ -7665,8 +7805,8 @@ func TestScrapeConfigSpecConfigWithKubernetesSD(t *testing.T) {
Selectors: []monitoringv1alpha1.K8SSelectorConfig{
{
Role: monitoringv1alpha1.KubernetesRoleNode,
- Label: ptr.To("type=infra"),
- Field: ptr.To("spec.unschedulable=false"),
+ Label: new("type=infra"),
+ Field: new("spec.unschedulable=false"),
},
},
},
@@ -7681,7 +7821,7 @@ func TestScrapeConfigSpecConfigWithKubernetesSD(t *testing.T) {
KubernetesSDConfigs: []monitoringv1alpha1.KubernetesSDConfig{
{
Role: monitoringv1alpha1.KubernetesRoleNode,
- APIServer: ptr.To("https://kubernetes.default.svc"),
+ APIServer: new("https://kubernetes.default.svc"),
BasicAuth: &monitoringv1.BasicAuth{
Username: corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -7706,7 +7846,7 @@ func TestScrapeConfigSpecConfigWithKubernetesSD(t *testing.T) {
KubernetesSDConfigs: []monitoringv1alpha1.KubernetesSDConfig{
{
Role: monitoringv1alpha1.KubernetesRoleNode,
- APIServer: ptr.To("https://kubernetes.default.svc"),
+ APIServer: new("https://kubernetes.default.svc"),
Authorization: &monitoringv1.SafeAuthorization{
Credentials: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -7725,7 +7865,7 @@ func TestScrapeConfigSpecConfigWithKubernetesSD(t *testing.T) {
KubernetesSDConfigs: []monitoringv1alpha1.KubernetesSDConfig{
{
Role: monitoringv1alpha1.KubernetesRoleNode,
- APIServer: ptr.To("https://kubernetes.default.svc"),
+ APIServer: new("https://kubernetes.default.svc"),
OAuth2: &monitoringv1.OAuth2{
ClientID: monitoringv1.SecretOrConfigMap{
ConfigMap: &corev1.ConfigMapKeySelector{
@@ -7758,7 +7898,7 @@ func TestScrapeConfigSpecConfigWithKubernetesSD(t *testing.T) {
KubernetesSDConfigs: []monitoringv1alpha1.KubernetesSDConfig{
{
Role: monitoringv1alpha1.KubernetesRoleNode,
- APIServer: ptr.To("https://kubernetes.default.svc"),
+ APIServer: new("https://kubernetes.default.svc"),
TLSConfig: &monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
@@ -7869,23 +8009,23 @@ func TestScrapeConfigSpecConfigWithConsulSD(t *testing.T) {
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "localhost",
- Datacenter: ptr.To("we1"),
- Namespace: ptr.To("observability"),
- Partition: ptr.To("1"),
+ Datacenter: new("we1"),
+ Namespace: new("observability"),
+ Partition: new("1"),
Scheme: ptr.To(monitoringv1.SchemeHTTPS),
Services: []string{"prometheus", "alertmanager"},
Tags: []string{"tag1"},
- TagSeparator: ptr.To(";"),
+ TagSeparator: new(";"),
NodeMeta: map[string]string{
"service": "service_name",
"name": "node_name",
},
- AllowStale: ptr.To(false),
+ AllowStale: new(false),
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -7897,8 +8037,8 @@ func TestScrapeConfigSpecConfigWithConsulSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHttp2: ptr.To(true),
+ FollowRedirects: new(true),
+ EnableHttp2: new(true),
TokenRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "foo",
@@ -7916,7 +8056,7 @@ func TestScrapeConfigSpecConfigWithConsulSD(t *testing.T) {
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "localhost",
- Filter: ptr.To("Meta.env == \"qa\""),
+ Filter: new("Meta.env == \"qa\""),
},
},
},
@@ -7928,7 +8068,7 @@ func TestScrapeConfigSpecConfigWithConsulSD(t *testing.T) {
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "localhost",
- HealthFilter: ptr.To("Service.Meta.env == \"prod\""),
+ HealthFilter: new("Service.Meta.env == \"prod\""),
},
},
},
@@ -8048,7 +8188,7 @@ func TestScrapeConfigSpecConfigWithConsulSD(t *testing.T) {
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "server",
- PathPrefix: ptr.To("example-path-prefix"),
+ PathPrefix: new("example-path-prefix"),
},
},
},
@@ -8061,7 +8201,7 @@ func TestScrapeConfigSpecConfigWithConsulSD(t *testing.T) {
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "server",
- PathPrefix: ptr.To("example-path-prefix"),
+ PathPrefix: new("example-path-prefix"),
},
},
},
@@ -8074,7 +8214,7 @@ func TestScrapeConfigSpecConfigWithConsulSD(t *testing.T) {
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "server",
- Namespace: ptr.To("example-namespace"),
+ Namespace: new("example-namespace"),
},
},
},
@@ -8087,7 +8227,7 @@ func TestScrapeConfigSpecConfigWithConsulSD(t *testing.T) {
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "server",
- Namespace: ptr.To("example-namespace"),
+ Namespace: new("example-namespace"),
},
},
},
@@ -8198,7 +8338,7 @@ func TestScrapeConfigSpecConfigWithEC2SD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
AccessKey: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "aws-access-api",
@@ -8212,7 +8352,7 @@ func TestScrapeConfigSpecConfigWithEC2SD(t *testing.T) {
Key: "secretKey",
},
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -8223,10 +8363,10 @@ func TestScrapeConfigSpecConfigWithEC2SD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
- RoleARN: ptr.To("arn:aws:iam::123456789:role/prometheus-role"),
+ Region: new("us-east-1"),
+ RoleARN: new("arn:aws:iam::123456789:role/prometheus-role"),
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -8237,10 +8377,10 @@ func TestScrapeConfigSpecConfigWithEC2SD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
- RoleARN: ptr.To("arn:aws:iam::123456789:role/prometheus-role"),
+ Region: new("us-east-1"),
+ RoleARN: new("arn:aws:iam::123456789:role/prometheus-role"),
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
Filters: []monitoringv1alpha1.Filter{
{
Name: "tag:environment",
@@ -8262,10 +8402,10 @@ func TestScrapeConfigSpecConfigWithEC2SD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
- RoleARN: ptr.To("arn:aws:iam::123456789:role/prometheus-role"),
+ Region: new("us-east-1"),
+ RoleARN: new("arn:aws:iam::123456789:role/prometheus-role"),
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
Filters: []monitoringv1alpha1.Filter{
{
Name: "tag:environment",
@@ -8287,7 +8427,7 @@ func TestScrapeConfigSpecConfigWithEC2SD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
AccessKey: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "wrong-secret-name",
@@ -8317,11 +8457,11 @@ func TestScrapeConfigSpecConfigWithEC2SD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -8333,9 +8473,9 @@ func TestScrapeConfigSpecConfigWithEC2SD(t *testing.T) {
},
},
},
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -8346,7 +8486,7 @@ func TestScrapeConfigSpecConfigWithEC2SD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
TLSConfig: &monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
@@ -8371,8 +8511,8 @@ func TestScrapeConfigSpecConfigWithEC2SD(t *testing.T) {
Key: "private-key",
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -8384,7 +8524,7 @@ func TestScrapeConfigSpecConfigWithEC2SD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
TLSConfig: &monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
@@ -8409,8 +8549,8 @@ func TestScrapeConfigSpecConfigWithEC2SD(t *testing.T) {
Key: "private-key",
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -8466,20 +8606,20 @@ func TestScrapeConfigSpecConfigWithAzureSD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
- Environment: ptr.To("AzurePublicCloud"),
+ Environment: new("AzurePublicCloud"),
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeOAuth),
SubscriptionID: "11AAAA11-A11A-111A-A111-1111A1111A11",
- TenantID: ptr.To("BBBB222B-B2B2-2B22-B222-2BB2222BB2B2"),
- ClientID: ptr.To("333333CC-3C33-3333-CCC3-33C3CCCCC33C"),
+ TenantID: new("BBBB222B-B2B2-2B22-B222-2BB2222BB2B2"),
+ ClientID: new("333333CC-3C33-3333-CCC3-33C3CCCCC33C"),
ClientSecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "secret",
},
Key: "clientSecret",
},
- ResourceGroup: ptr.To("my-resource-group"),
+ ResourceGroup: new("my-resource-group"),
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -8490,12 +8630,12 @@ func TestScrapeConfigSpecConfigWithAzureSD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
- Environment: ptr.To("AzurePublicCloud"),
+ Environment: new("AzurePublicCloud"),
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeSDK),
SubscriptionID: "11AAAA11-A11A-111A-A111-1111A1111A11",
- ResourceGroup: ptr.To("my-resource-group"),
+ ResourceGroup: new("my-resource-group"),
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -8506,7 +8646,7 @@ func TestScrapeConfigSpecConfigWithAzureSD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
- Environment: ptr.To("AzurePublicCloud"),
+ Environment: new("AzurePublicCloud"),
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeManagedIdentity),
SubscriptionID: "11AAAA11-A11A-111A-A111-1111A1111A11",
},
@@ -8558,9 +8698,9 @@ func TestScrapeConfigSpecConfigWithAzureSD(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -8572,8 +8712,8 @@ func TestScrapeConfigSpecConfigWithAzureSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -8675,7 +8815,7 @@ func TestScrapeConfigSpecConfigWithAzureSD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
- Environment: ptr.To("AzurePublicCloud"),
+ Environment: new("AzurePublicCloud"),
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeWorkloadIdentity),
SubscriptionID: "11AAAA11-A11A-111A-A111-1111A1111A11",
},
@@ -8777,7 +8917,7 @@ func TestScrapeConfigSpecConfigWithGCESD(t *testing.T) {
Project: "devops-dev",
Zone: "us-west-1",
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -8791,9 +8931,9 @@ func TestScrapeConfigSpecConfigWithGCESD(t *testing.T) {
Project: "devops-dev",
Zone: "us-west-1",
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- Port: ptr.To(int32(9100)),
- Filter: ptr.To("filter-expression"),
- TagSeparator: ptr.To("tag-value"),
+ Port: new(int32(9100)),
+ Filter: new("filter-expression"),
+ TagSeparator: new("tag-value"),
},
},
},
@@ -8879,16 +9019,16 @@ func TestScrapeConfigSpecConfigWithOpenStackSD(t *testing.T) {
Role: monitoringv1alpha1.OpenStackRoleInstance,
Region: "region-1",
IdentityEndpoint: ptr.To(monitoringv1alpha1.URL("http://identity.example.com:5000/v2.0")),
- Username: ptr.To("nova-user-1"),
+ Username: new("nova-user-1"),
Password: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "openstack-access-secret",
},
Key: "password",
},
- DomainName: ptr.To("devops-project-1"),
+ DomainName: new("devops-project-1"),
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -8976,9 +9116,9 @@ func TestScrapeConfigSpecConfigWithDigitalOceanSD(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -8990,9 +9130,9 @@ func TestScrapeConfigSpecConfigWithDigitalOceanSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- Port: ptr.To(int32(9100)),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ Port: new(int32(9100)),
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
},
},
@@ -9160,9 +9300,9 @@ func TestScrapeConfigSpecConfigWithDockerSDConfig(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -9174,11 +9314,11 @@ func TestScrapeConfigSpecConfigWithDockerSDConfig(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- Port: ptr.To(int32(9100)),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ Port: new(int32(9100)),
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- HostNetworkingHost: ptr.To("localhost"),
+ HostNetworkingHost: new("localhost"),
Filters: []monitoringv1alpha1.Filter{
{Name: "dummy_label_1",
Values: []string{"dummy_value_1"}},
@@ -9385,7 +9525,7 @@ func TestScrapeConfigSpecConfigWithDockerSDConfig(t *testing.T) {
Key: "password",
},
},
- MatchFirstNetwork: ptr.To(true),
+ MatchFirstNetwork: new(true),
},
},
},
@@ -9442,7 +9582,7 @@ func TestScrapeConfigSpecConfigWithDockerSDConfig(t *testing.T) {
Key: "password",
},
},
- MatchFirstNetwork: ptr.To(true),
+ MatchFirstNetwork: new(true),
},
},
},
@@ -9535,9 +9675,9 @@ func TestScrapeConfigSpecConfigWithLinodeSDConfig(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -9549,11 +9689,11 @@ func TestScrapeConfigSpecConfigWithLinodeSDConfig(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- Port: ptr.To(int32(9100)),
- TagSeparator: ptr.To(","),
+ FollowRedirects: new(true),
+ Port: new(int32(9100)),
+ TagSeparator: new(","),
RefreshInterval: ptr.To(monitoringv1.Duration("5m")),
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
TLSConfig: &monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
@@ -9610,9 +9750,9 @@ func TestScrapeConfigSpecConfigWithLinodeSDConfig(t *testing.T) {
"param2": "value2",
},
},
- TagSeparator: ptr.To(","),
+ TagSeparator: new(","),
RefreshInterval: ptr.To(monitoringv1.Duration("5m")),
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
TLSConfig: &monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
@@ -9719,9 +9859,9 @@ func TestScrapeConfigSpecConfigWithHetznerSD(t *testing.T) {
{
Role: "hcloud",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -9733,9 +9873,9 @@ func TestScrapeConfigSpecConfigWithHetznerSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- Port: ptr.To(int32(9100)),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ Port: new(int32(9100)),
RefreshInterval: ptr.To(monitoringv1.Duration("5m")),
},
},
@@ -9750,9 +9890,9 @@ func TestScrapeConfigSpecConfigWithHetznerSD(t *testing.T) {
{
Role: "hcloud",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -9764,11 +9904,11 @@ func TestScrapeConfigSpecConfigWithHetznerSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- Port: ptr.To(int32(9100)),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ Port: new(int32(9100)),
RefreshInterval: ptr.To(monitoringv1.Duration("5m")),
- LabelSelector: ptr.To("label_value"),
+ LabelSelector: new("label_value"),
},
},
},
@@ -9782,9 +9922,9 @@ func TestScrapeConfigSpecConfigWithHetznerSD(t *testing.T) {
{
Role: "hcloud",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -9796,11 +9936,11 @@ func TestScrapeConfigSpecConfigWithHetznerSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- Port: ptr.To(int32(9100)),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ Port: new(int32(9100)),
RefreshInterval: ptr.To(monitoringv1.Duration("5m")),
- LabelSelector: ptr.To("label_value"),
+ LabelSelector: new("label_value"),
},
},
},
@@ -10113,19 +10253,19 @@ func TestAppendConvertClassicHistogramsToNHCB(t *testing.T) {
{
name: "ConvertClassicHistogramsToNHCB true with Prometheus Version 3.4",
version: "v3.4.0",
- convertClassicHistogramsToNHCB: ptr.To(true),
+ convertClassicHistogramsToNHCB: new(true),
expectedCfg: "ConvertClassicHistogramsToNHCBTrueWithPrometheusV3.golden",
},
{
name: "ConvertClassicHistogramsToNHCB false with Prometheus Version 3.4",
version: "v3.4.0",
- convertClassicHistogramsToNHCB: ptr.To(false),
+ convertClassicHistogramsToNHCB: new(false),
expectedCfg: "ConvertClassicHistogramsToNHCBFalseWithPrometheusV3.golden",
},
{
name: "ConvertClassicHistogramsToNHCB true with Prometheus Version 2",
version: "v2.55.0",
- convertClassicHistogramsToNHCB: ptr.To(true),
+ convertClassicHistogramsToNHCB: new(true),
expectedCfg: "ConvertClassicHistogramsToNHCBTrueWithPrometheusLowerThanV3.golden",
},
}
@@ -10239,7 +10379,7 @@ func TestOTLPConfig(t *testing.T) {
name: "Config KeepIdentifyingResourceAttributes",
version: "v3.1.0",
otlpConfig: &monitoringv1.OTLPConfig{
- KeepIdentifyingResourceAttributes: ptr.To(true),
+ KeepIdentifyingResourceAttributes: new(true),
},
golden: "OTLPConfig_Config_keep_identifying_resource_attributes.golden",
},
@@ -10247,7 +10387,7 @@ func TestOTLPConfig(t *testing.T) {
name: "Config ConvertHistogramsToNHCB old version",
version: "v3.0.0",
otlpConfig: &monitoringv1.OTLPConfig{
- KeepIdentifyingResourceAttributes: ptr.To(false),
+ KeepIdentifyingResourceAttributes: new(false),
},
golden: "OTLPConfig_Config_keep_identifying_resource_attributes_with_old_version.golden",
},
@@ -10271,7 +10411,7 @@ func TestOTLPConfig(t *testing.T) {
name: "Config ConvertHistogramsToNHCB",
version: "v3.4.0",
otlpConfig: &monitoringv1.OTLPConfig{
- ConvertHistogramsToNHCB: ptr.To(true),
+ ConvertHistogramsToNHCB: new(true),
},
golden: "OTLPConfig_Config_convert_histograms_to_nhcb.golden",
},
@@ -10279,7 +10419,7 @@ func TestOTLPConfig(t *testing.T) {
name: "Config ConvertHistogramsToNHCB with old version",
version: "v3.3.1",
otlpConfig: &monitoringv1.OTLPConfig{
- ConvertHistogramsToNHCB: ptr.To(true),
+ ConvertHistogramsToNHCB: new(true),
},
golden: "OTLPConfig_Config_convert_histograms_to_nhcb_with_old_version.golden",
},
@@ -10288,7 +10428,7 @@ func TestOTLPConfig(t *testing.T) {
version: "v3.5.0",
otlpConfig: &monitoringv1.OTLPConfig{
IgnoreResourceAttributes: []string{"aa", "bb", "cc"},
- PromoteAllResourceAttributes: ptr.To(true),
+ PromoteAllResourceAttributes: new(true),
},
golden: "OTLPConfig_Config_ignore_resource_attributes_and_promote_all_resource_attributes.golden",
},
@@ -10312,7 +10452,7 @@ func TestOTLPConfig(t *testing.T) {
name: "Config PromoteAllResourceAttributes with correct prometheus version",
version: "v3.5.0",
otlpConfig: &monitoringv1.OTLPConfig{
- PromoteAllResourceAttributes: ptr.To(true),
+ PromoteAllResourceAttributes: new(true),
},
golden: "OTLPConfig_Config_promote_all_resource_attributes.golden",
},
@@ -10321,7 +10461,7 @@ func TestOTLPConfig(t *testing.T) {
version: "v3.5.0",
otlpConfig: &monitoringv1.OTLPConfig{
PromoteResourceAttributes: []string{"aa", "bb", "cc"},
- PromoteAllResourceAttributes: ptr.To(true),
+ PromoteAllResourceAttributes: new(true),
},
expectedErr: true,
},
@@ -10329,7 +10469,7 @@ func TestOTLPConfig(t *testing.T) {
name: "Config PromoteAllResourceAttributes with old prometheus version",
version: "v3.4.0",
otlpConfig: &monitoringv1.OTLPConfig{
- PromoteAllResourceAttributes: ptr.To(true),
+ PromoteAllResourceAttributes: new(true),
},
golden: "OTLPConfig_Config_promote_all_resource_attributes_wrong_prom.golden",
},
@@ -10337,7 +10477,7 @@ func TestOTLPConfig(t *testing.T) {
name: "Config PromoteScopeMetadata with compatible versiopn",
version: "v3.6.0",
otlpConfig: &monitoringv1.OTLPConfig{
- PromoteScopeMetadata: ptr.To(true),
+ PromoteScopeMetadata: new(true),
},
golden: "OTLPConfig_Config_promote_scope_metadata.golden",
},
@@ -10345,10 +10485,42 @@ func TestOTLPConfig(t *testing.T) {
name: "Config PromoteScopeMetadata with wrong version",
version: "v3.5.0",
otlpConfig: &monitoringv1.OTLPConfig{
- PromoteScopeMetadata: ptr.To(true),
+ PromoteScopeMetadata: new(true),
},
golden: "OTLPConfig_Config_promote_scope_metadata_wrong_version.golden",
},
+ {
+ name: "Config LabelNameUnderscoreSanitization with compatible version",
+ version: "v3.8.0",
+ otlpConfig: &monitoringv1.OTLPConfig{
+ LabelNameUnderscoreSanitization: new(true),
+ },
+ golden: "OTLPConfig_Config_label_name_underscore_sanitization.golden",
+ },
+ {
+ name: "Config LabelNameUnderscoreSanitization with old version",
+ version: "v3.7.0",
+ otlpConfig: &monitoringv1.OTLPConfig{
+ LabelNameUnderscoreSanitization: new(true),
+ },
+ golden: "OTLPConfig_Config_label_name_underscore_sanitization_wrong_version.golden",
+ },
+ {
+ name: "Config LabelNamePreserveMultipleUnderscores with compatible version",
+ version: "v3.8.0",
+ otlpConfig: &monitoringv1.OTLPConfig{
+ LabelNamePreserveMultipleUnderscores: new(false),
+ },
+ golden: "OTLPConfig_Config_label_name_preserve_multiple_underscores.golden",
+ },
+ {
+ name: "Config LabelNamePreserveMultipleUnderscores with old version",
+ version: "v3.7.0",
+ otlpConfig: &monitoringv1.OTLPConfig{
+ LabelNamePreserveMultipleUnderscores: new(false),
+ },
+ golden: "OTLPConfig_Config_label_name_preserve_multiple_underscores_wrong_version.golden",
+ },
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
@@ -10405,15 +10577,15 @@ func TestTracingConfig(t *testing.T) {
},
{
tracingConfig: &monitoringv1.TracingConfig{
- ClientType: ptr.To("grpc"),
+ ClientType: new("grpc"),
Endpoint: "https://otel-collector.default.svc.local:3333",
SamplingFraction: &samplingTwo,
Headers: map[string]string{
"custom": "header",
},
- Compression: ptr.To("gzip"),
+ Compression: new("gzip"),
Timeout: ptr.To(monitoringv1.Duration("10s")),
- Insecure: ptr.To(false),
+ Insecure: new(false),
},
name: "Expect valid config",
expectedErr: false,
@@ -10471,9 +10643,9 @@ func TestScrapeConfigSpecConfigWithKumaSD(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -10485,12 +10657,12 @@ func TestScrapeConfigSpecConfigWithKumaSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
Server: "http://127.0.0.1:5681",
- ClientID: ptr.To("client"),
- FetchTimeout: (*monitoringv1.Duration)(ptr.To("5s")),
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
+ ClientID: new("client"),
+ FetchTimeout: (*monitoringv1.Duration)(new("5s")),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
},
},
},
@@ -10758,7 +10930,7 @@ func defaultPodMonitor() *monitoringv1.PodMonitor {
},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -10781,9 +10953,9 @@ func defaultScrapeConfig() *monitoringv1alpha1.ScrapeConfig {
URL: "http://localhost:9100/sd.json",
RefreshInterval: ptr.To(monitoringv1.Duration("5m")),
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
},
},
},
@@ -10823,7 +10995,7 @@ func TestScrapeClass(t *testing.T) {
scrapeClass: []monitoringv1.ScrapeClass{
{
Name: "test-tls-scrape-class",
- Default: ptr.To(true),
+ Default: new(true),
TLSConfig: &monitoringv1.TLSConfig{
TLSFilesConfig: monitoringv1.TLSFilesConfig{
CAFile: "/etc/prometheus/secrets/default/ca.crt",
@@ -10847,10 +11019,10 @@ func TestScrapeClass(t *testing.T) {
for _, sc := range tc.scrapeClass {
p.Spec.ScrapeClasses = append(p.Spec.ScrapeClasses, sc)
if !ptr.Deref(sc.Default, false) {
- serviceMonitor.Spec.ScrapeClassName = ptr.To(sc.Name)
- podMonitor.Spec.ScrapeClassName = ptr.To(sc.Name)
- probe.Spec.ScrapeClassName = ptr.To(sc.Name)
- scrapeConfig.Spec.ScrapeClassName = ptr.To(sc.Name)
+ serviceMonitor.Spec.ScrapeClassName = new(sc.Name)
+ podMonitor.Spec.ScrapeClassName = new(sc.Name)
+ probe.Spec.ScrapeClassName = new(sc.Name)
+ scrapeConfig.Spec.ScrapeClassName = new(sc.Name)
}
}
@@ -10965,7 +11137,7 @@ func TestServiceMonitorScrapeClassWithDefaultTLS(t *testing.T) {
for _, sc := range tc.scrapeClass {
p.Spec.ScrapeClasses = append(p.Spec.ScrapeClasses, sc)
if sc.Default == nil {
- serviceMonitor.Spec.ScrapeClassName = ptr.To(sc.Name)
+ serviceMonitor.Spec.ScrapeClassName = new(sc.Name)
}
}
@@ -11077,7 +11249,7 @@ func TestPodMonitorScrapeClassWithDefaultTLS(t *testing.T) {
for _, sc := range tc.scrapeClass {
p.Spec.ScrapeClasses = append(p.Spec.ScrapeClasses, sc)
if sc.Default == nil {
- podMonitor.Spec.ScrapeClassName = ptr.To(sc.Name)
+ podMonitor.Spec.ScrapeClassName = new(sc.Name)
}
}
podMonitor.Spec.PodMetricsEndpoints[0].TLSConfig = tc.tlsConfig
@@ -11138,10 +11310,10 @@ func TestPodMonitorPortNumber(t *testing.T) {
p := defaultPrometheus()
podMonitor := defaultPodMonitor()
- podMonitor.Spec.PodMetricsEndpoints[0].Port = ptr.To(tc.port)
- podMonitor.Spec.PodMetricsEndpoints[0].PortNumber = ptr.To(tc.portNumber)
+ podMonitor.Spec.PodMetricsEndpoints[0].Port = new(tc.port)
+ podMonitor.Spec.PodMetricsEndpoints[0].PortNumber = new(tc.portNumber)
//nolint:staticcheck // Ignore SA1019 this field is marked as deprecated.
- podMonitor.Spec.PodMetricsEndpoints[0].TargetPort = ptr.To(tc.targetPort)
+ podMonitor.Spec.PodMetricsEndpoints[0].TargetPort = new(tc.targetPort)
cg := mustNewConfigGenerator(t, p)
@@ -11171,7 +11343,7 @@ func TestNewConfigGeneratorWithMultipleDefaultScrapeClass(t *testing.T) {
p.Spec.ScrapeClasses = []monitoringv1.ScrapeClass{
{
Name: "test-default-scrape-class",
- Default: ptr.To(true),
+ Default: new(true),
TLSConfig: &monitoringv1.TLSConfig{
TLSFilesConfig: monitoringv1.TLSFilesConfig{
CAFile: "/etc/prometheus/secrets/ca.crt",
@@ -11182,7 +11354,7 @@ func TestNewConfigGeneratorWithMultipleDefaultScrapeClass(t *testing.T) {
},
{
Name: "test-default-scrape-class-2",
- Default: ptr.To(true),
+ Default: new(true),
TLSConfig: &monitoringv1.TLSConfig{
TLSFilesConfig: monitoringv1.TLSFilesConfig{
CAFile: "/etc/prometheus/secrets/ca.crt",
@@ -11304,9 +11476,9 @@ func TestScrapeConfigSpecConfigWithEurekaSD(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -11318,10 +11490,10 @@ func TestScrapeConfigSpecConfigWithEurekaSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
Server: "http://localhost:8761/eureka",
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
},
},
},
@@ -11485,9 +11657,9 @@ func TestScrapeConfigSpecConfigWithNomadSD(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -11499,14 +11671,14 @@ func TestScrapeConfigSpecConfigWithNomadSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- AllowStale: ptr.To(true),
- TagSeparator: ptr.To(","),
- Namespace: ptr.To("default"),
- Region: ptr.To("default"),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ AllowStale: new(true),
+ TagSeparator: new(","),
+ Namespace: new("default"),
+ Region: new("default"),
Server: "http://127.0.0.1:4646",
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
},
},
},
@@ -11672,9 +11844,9 @@ func TestScrapeConfigSpecConfigWithDockerswarmSD(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -11686,9 +11858,9 @@ func TestScrapeConfigSpecConfigWithDockerswarmSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
Filters: []monitoringv1alpha1.Filter{
{
Name: "foo",
@@ -11723,9 +11895,9 @@ func TestScrapeConfigSpecConfigWithDockerswarmSD(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -11737,9 +11909,9 @@ func TestScrapeConfigSpecConfigWithDockerswarmSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
},
},
},
@@ -11907,9 +12079,9 @@ func TestScrapeConfigSpecConfigWithPuppetDBSD(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -11921,9 +12093,9 @@ func TestScrapeConfigSpecConfigWithPuppetDBSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
},
},
},
@@ -11952,9 +12124,9 @@ func TestScrapeConfigSpecConfigWithPuppetDBSD(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -11966,9 +12138,9 @@ func TestScrapeConfigSpecConfigWithPuppetDBSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
},
},
},
@@ -12125,8 +12297,8 @@ func TestScrapeConfigSpecConfigWithLightSailSD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Region: ptr.To("us-east-1"),
- Endpoint: ptr.To("https://lightsail.us-east-1.amazonaws.com/"),
+ Region: new("us-east-1"),
+ Endpoint: new("https://lightsail.us-east-1.amazonaws.com/"),
AccessKey: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "aws-access-api",
@@ -12140,7 +12312,7 @@ func TestScrapeConfigSpecConfigWithLightSailSD(t *testing.T) {
Key: "secretKey",
},
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -12151,11 +12323,11 @@ func TestScrapeConfigSpecConfigWithLightSailSD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Region: ptr.To("us-east-1"),
- Endpoint: ptr.To("https://lightsail.us-east-1.amazonaws.com/"),
- RoleARN: ptr.To("arn:aws:iam::123456789:role/prometheus-role"),
+ Region: new("us-east-1"),
+ Endpoint: new("https://lightsail.us-east-1.amazonaws.com/"),
+ RoleARN: new("arn:aws:iam::123456789:role/prometheus-role"),
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -12166,8 +12338,8 @@ func TestScrapeConfigSpecConfigWithLightSailSD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Region: ptr.To("us-east-1"),
- Endpoint: ptr.To("https://lightsail.us-east-1.amazonaws.com/"),
+ Region: new("us-east-1"),
+ Endpoint: new("https://lightsail.us-east-1.amazonaws.com/"),
Authorization: &monitoringv1.SafeAuthorization{
Credentials: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -12177,9 +12349,9 @@ func TestScrapeConfigSpecConfigWithLightSailSD(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -12191,9 +12363,9 @@ func TestScrapeConfigSpecConfigWithLightSailSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
},
},
},
@@ -12204,8 +12376,8 @@ func TestScrapeConfigSpecConfigWithLightSailSD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Region: ptr.To("us-east-1"),
- Endpoint: ptr.To("https://lightsail.us-east-1.amazonaws.com/"),
+ Region: new("us-east-1"),
+ Endpoint: new("https://lightsail.us-east-1.amazonaws.com/"),
BasicAuth: &monitoringv1.BasicAuth{
Username: corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -12221,9 +12393,9 @@ func TestScrapeConfigSpecConfigWithLightSailSD(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -12235,9 +12407,9 @@ func TestScrapeConfigSpecConfigWithLightSailSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
},
},
},
@@ -12248,8 +12420,8 @@ func TestScrapeConfigSpecConfigWithLightSailSD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Region: ptr.To("us-east-1"),
- Endpoint: ptr.To("https://lightsail.us-east-1.amazonaws.com/"),
+ Region: new("us-east-1"),
+ Endpoint: new("https://lightsail.us-east-1.amazonaws.com/"),
OAuth2: &monitoringv1.OAuth2{
ClientID: monitoringv1.SecretOrConfigMap{
@@ -12283,8 +12455,8 @@ func TestScrapeConfigSpecConfigWithLightSailSD(t *testing.T) {
scSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Region: ptr.To("us-east-1"),
- Endpoint: ptr.To("https://lightsail.us-east-1.amazonaws.com/"),
+ Region: new("us-east-1"),
+ Endpoint: new("https://lightsail.us-east-1.amazonaws.com/"),
Authorization: &monitoringv1.SafeAuthorization{
Credentials: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -12422,8 +12594,8 @@ func TestScrapeConfigSpecConfigWithOVHCloudSD(t *testing.T) {
Key: "ck",
},
Service: monitoringv1alpha1.OVHServiceDedicatedServer,
- Endpoint: ptr.To("127.0.0.1"),
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
+ Endpoint: new("127.0.0.1"),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
},
},
},
@@ -12494,15 +12666,15 @@ func TestScrapeConfigSpecConfigWithScalewaySD(t *testing.T) {
},
ProjectID: "00000000-0000-0000-0000-000000000001",
Role: monitoringv1alpha1.ScalewayRoleInstance,
- Zone: ptr.To("fr-par-1"),
- Port: ptr.To(int32(23456)),
+ Zone: new("fr-par-1"),
+ Port: new(int32(23456)),
ApiURL: ptr.To(monitoringv1alpha1.URL("https://api.scaleway.com")),
- NameFilter: ptr.To("name"),
+ NameFilter: new("name"),
TagsFilter: []string{"aa", "bb"},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -12514,9 +12686,9 @@ func TestScrapeConfigSpecConfigWithScalewaySD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
},
},
},
@@ -12648,9 +12820,9 @@ func TestScrapeConfigSpecConfigWithIonosSD(t *testing.T) {
},
},
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -12662,10 +12834,10 @@ func TestScrapeConfigSpecConfigWithIonosSD(t *testing.T) {
},
},
},
- FollowRedirects: ptr.To(true),
- EnableHTTP2: ptr.To(true),
- Port: ptr.To(int32(9100)),
- RefreshInterval: (*monitoringv1.Duration)(ptr.To("30s")),
+ FollowRedirects: new(true),
+ EnableHTTP2: new(true),
+ Port: new(int32(9100)),
+ RefreshInterval: (*monitoringv1.Duration)(new("30s")),
},
},
},
@@ -12817,7 +12989,7 @@ func TestServiceMonitorWithDefaultScrapeClassRelabelings(t *testing.T) {
scrapeClasses := []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
+ Default: new(true),
Relabelings: []monitoringv1.RelabelConfig{
{
Action: "replace",
@@ -12872,7 +13044,7 @@ func TestServiceMonitorWithNonDefaultScrapeClassRelabelings(t *testing.T) {
}
p.Spec.ScrapeClasses = append(p.Spec.ScrapeClasses, sc)
- serviceMonitor.Spec.ScrapeClassName = ptr.To(sc.Name)
+ serviceMonitor.Spec.ScrapeClassName = new(sc.Name)
cg := mustNewConfigGenerator(t, p)
cfg, err := cg.GenerateServerConfiguration(
@@ -12897,7 +13069,7 @@ func TestPodMonitorWithDefaultScrapeClassRelabelings(t *testing.T) {
scrapeClasses := []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
+ Default: new(true),
Relabelings: []monitoringv1.RelabelConfig{
{
Action: "replace",
@@ -12952,7 +13124,7 @@ func TestPodMonitorWithNonDefaultScrapeClassRelabelings(t *testing.T) {
}
p.Spec.ScrapeClasses = append(p.Spec.ScrapeClasses, sc)
- podMonitor.Spec.ScrapeClassName = ptr.To(sc.Name)
+ podMonitor.Spec.ScrapeClassName = new(sc.Name)
cg := mustNewConfigGenerator(t, p)
cfg, err := cg.GenerateServerConfiguration(
@@ -12973,9 +13145,9 @@ func TestPodMonitorWithNonDefaultScrapeClassRelabelings(t *testing.T) {
func TestScrapeClassMetricRelabelings(t *testing.T) {
serviceMonitorWithNonDefaultScrapeClass := defaultServiceMonitor()
- serviceMonitorWithNonDefaultScrapeClass.Spec.ScrapeClassName = ptr.To("test-extra-relabelings-scrape-class")
+ serviceMonitorWithNonDefaultScrapeClass.Spec.ScrapeClassName = new("test-extra-relabelings-scrape-class")
podMonitorWithNonDefaultScrapeClass := defaultPodMonitor()
- podMonitorWithNonDefaultScrapeClass.Spec.ScrapeClassName = ptr.To("test-extra-relabelings-scrape-class")
+ podMonitorWithNonDefaultScrapeClass.Spec.ScrapeClassName = new("test-extra-relabelings-scrape-class")
for _, tc := range []struct {
name string
scrapeClasses []monitoringv1.ScrapeClass
@@ -12990,19 +13162,19 @@ func TestScrapeClassMetricRelabelings(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
+ Default: new(true),
MetricRelabelings: []monitoringv1.RelabelConfig{
{
SourceLabels: []monitoringv1.LabelName{"namespace"},
Regex: "tenant1-.*",
TargetLabel: "tenant",
- Replacement: ptr.To("tenant1"),
+ Replacement: new("tenant1"),
},
{
SourceLabels: []monitoringv1.LabelName{"namespace"},
Regex: "tenant2-.*",
TargetLabel: "tenant",
- Replacement: ptr.To("tenant2"),
+ Replacement: new("tenant2"),
},
},
},
@@ -13011,7 +13183,7 @@ func TestScrapeClassMetricRelabelings(t *testing.T) {
MetricRelabelings: []monitoringv1.RelabelConfig{
{
TargetLabel: "tenant",
- Replacement: ptr.To("not-default"),
+ Replacement: new("not-default"),
},
},
},
@@ -13027,7 +13199,7 @@ func TestScrapeClassMetricRelabelings(t *testing.T) {
MetricRelabelings: []monitoringv1.RelabelConfig{
{
TargetLabel: "extra",
- Replacement: ptr.To("value1"),
+ Replacement: new("value1"),
},
},
},
@@ -13040,19 +13212,19 @@ func TestScrapeClassMetricRelabelings(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
+ Default: new(true),
MetricRelabelings: []monitoringv1.RelabelConfig{
{
SourceLabels: []monitoringv1.LabelName{"namespace"},
Regex: "tenant1-.*",
TargetLabel: "tenant",
- Replacement: ptr.To("tenant1"),
+ Replacement: new("tenant1"),
},
{
SourceLabels: []monitoringv1.LabelName{"namespace"},
Regex: "tenant2-.*",
TargetLabel: "tenant",
- Replacement: ptr.To("tenant2"),
+ Replacement: new("tenant2"),
},
},
},
@@ -13061,7 +13233,7 @@ func TestScrapeClassMetricRelabelings(t *testing.T) {
MetricRelabelings: []monitoringv1.RelabelConfig{
{
TargetLabel: "tenant",
- Replacement: ptr.To("not-default"),
+ Replacement: new("not-default"),
},
},
},
@@ -13077,7 +13249,7 @@ func TestScrapeClassMetricRelabelings(t *testing.T) {
MetricRelabelings: []monitoringv1.RelabelConfig{
{
TargetLabel: "extra",
- Replacement: ptr.To("value1"),
+ Replacement: new("value1"),
},
},
},
@@ -13177,7 +13349,7 @@ func TestScrapeClassAuthorization(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
+ Default: new(true),
Authorization: &monitoringv1.Authorization{
CredentialsFile: "/etc/secret/credentials",
},
@@ -13218,7 +13390,7 @@ func TestScrapeClassAuthorization(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
+ Default: new(true),
Authorization: &monitoringv1.Authorization{
CredentialsFile: "/etc/secret/credentials/default",
},
@@ -13265,7 +13437,7 @@ func TestScrapeClassAuthorization(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
+ Default: new(true),
Authorization: &monitoringv1.Authorization{
CredentialsFile: "/etc/secret/credentials/default",
},
@@ -13312,7 +13484,7 @@ func TestScrapeClassAuthorization(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
+ Default: new(true),
Authorization: &monitoringv1.Authorization{
CredentialsFile: "/etc/secret/credentials/default",
},
@@ -13387,9 +13559,9 @@ func TestScrapeClassAuthorization(t *testing.T) {
func TestScrapeClassAttachMetadata(t *testing.T) {
serviceMonitorWithNonDefaultScrapeClass := defaultServiceMonitor()
- serviceMonitorWithNonDefaultScrapeClass.Spec.ScrapeClassName = ptr.To("test-attachmetadata-scrape-class")
+ serviceMonitorWithNonDefaultScrapeClass.Spec.ScrapeClassName = new("test-attachmetadata-scrape-class")
podMonitorWithNonDefaultScrapeClass := defaultPodMonitor()
- podMonitorWithNonDefaultScrapeClass.Spec.ScrapeClassName = ptr.To("test-attachmetadata-scrape-class")
+ podMonitorWithNonDefaultScrapeClass.Spec.ScrapeClassName = new("test-attachmetadata-scrape-class")
for _, tc := range []struct {
name string
scrapeClasses []monitoringv1.ScrapeClass
@@ -13404,8 +13576,8 @@ func TestScrapeClassAttachMetadata(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
- AttachMetadata: &monitoringv1.AttachMetadata{Node: ptr.To(true)},
+ Default: new(true),
+ AttachMetadata: &monitoringv1.AttachMetadata{Node: new(true)},
},
},
serviceMonitors: map[string]*monitoringv1.ServiceMonitor{"monitor": defaultServiceMonitor()},
@@ -13416,7 +13588,7 @@ func TestScrapeClassAttachMetadata(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "test-attachmetadata-scrape-class",
- AttachMetadata: &monitoringv1.AttachMetadata{Node: ptr.To(true)},
+ AttachMetadata: &monitoringv1.AttachMetadata{Node: new(true)},
},
},
serviceMonitors: map[string]*monitoringv1.ServiceMonitor{"monitor": serviceMonitorWithNonDefaultScrapeClass},
@@ -13427,12 +13599,12 @@ func TestScrapeClassAttachMetadata(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
- AttachMetadata: &monitoringv1.AttachMetadata{Node: ptr.To(true)},
+ Default: new(true),
+ AttachMetadata: &monitoringv1.AttachMetadata{Node: new(true)},
},
{
Name: "not-default",
- AttachMetadata: &monitoringv1.AttachMetadata{Node: ptr.To(true)},
+ AttachMetadata: &monitoringv1.AttachMetadata{Node: new(true)},
},
},
podMonitors: map[string]*monitoringv1.PodMonitor{"monitor": defaultPodMonitor()},
@@ -13443,7 +13615,7 @@ func TestScrapeClassAttachMetadata(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "test-attachmetadata-scrape-class",
- AttachMetadata: &monitoringv1.AttachMetadata{Node: ptr.To(true)},
+ AttachMetadata: &monitoringv1.AttachMetadata{Node: new(true)},
},
},
podMonitors: map[string]*monitoringv1.PodMonitor{"monitor": podMonitorWithNonDefaultScrapeClass},
@@ -13478,13 +13650,13 @@ func TestScrapeClassAttachMetadata(t *testing.T) {
func TestScrapeClassFallbackScrapeProtocol(t *testing.T) {
serviceMonitorWithNonDefaultScrapeClass := defaultServiceMonitor()
- serviceMonitorWithNonDefaultScrapeClass.Spec.ScrapeClassName = ptr.To("test-fallback-scrapeprotocol-scrape-class")
+ serviceMonitorWithNonDefaultScrapeClass.Spec.ScrapeClassName = new("test-fallback-scrapeprotocol-scrape-class")
podMonitorWithNonDefaultScrapeClass := defaultPodMonitor()
- podMonitorWithNonDefaultScrapeClass.Spec.ScrapeClassName = ptr.To("test-fallback-scrapeprotocol-scrape-class")
+ podMonitorWithNonDefaultScrapeClass.Spec.ScrapeClassName = new("test-fallback-scrapeprotocol-scrape-class")
probeWithNonDefaultScrapeClass := defaultProbe()
- probeWithNonDefaultScrapeClass.Spec.ScrapeClassName = ptr.To("test-fallback-scrapeprotocol-scrape-class")
+ probeWithNonDefaultScrapeClass.Spec.ScrapeClassName = new("test-fallback-scrapeprotocol-scrape-class")
scrapeConfigWithNonDefaultScrapeClass := defaultScrapeConfig()
- scrapeConfigWithNonDefaultScrapeClass.Spec.ScrapeClassName = ptr.To("test-fallback-scrapeprotocol-scrape-class")
+ scrapeConfigWithNonDefaultScrapeClass.Spec.ScrapeClassName = new("test-fallback-scrapeprotocol-scrape-class")
for _, tc := range []struct {
name string
scrapeClasses []monitoringv1.ScrapeClass
@@ -13499,7 +13671,7 @@ func TestScrapeClassFallbackScrapeProtocol(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
+ Default: new(true),
FallbackScrapeProtocol: ptr.To(monitoringv1.OpenMetricsText1_0_0),
},
},
@@ -13522,7 +13694,7 @@ func TestScrapeClassFallbackScrapeProtocol(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
+ Default: new(true),
FallbackScrapeProtocol: ptr.To(monitoringv1.OpenMetricsText1_0_0),
},
},
@@ -13545,7 +13717,7 @@ func TestScrapeClassFallbackScrapeProtocol(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
+ Default: new(true),
FallbackScrapeProtocol: ptr.To(monitoringv1.OpenMetricsText1_0_0),
},
},
@@ -13568,7 +13740,7 @@ func TestScrapeClassFallbackScrapeProtocol(t *testing.T) {
scrapeClasses: []monitoringv1.ScrapeClass{
{
Name: "default",
- Default: ptr.To(true),
+ Default: new(true),
FallbackScrapeProtocol: ptr.To(monitoringv1.OpenMetricsText1_0_0),
},
},
@@ -13628,7 +13800,7 @@ func TestGenerateAlertmanagerConfig(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "foo",
- Namespace: ptr.To("other"),
+ Namespace: new("other"),
Port: intstr.FromString("web"),
},
},
@@ -13640,12 +13812,12 @@ func TestGenerateAlertmanagerConfig(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "foo",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -13667,7 +13839,7 @@ func TestGenerateAlertmanagerConfig(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "foo",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
TLSConfig: &monitoringv1.TLSConfig{
SafeTLSConfig: monitoringv1.SafeTLSConfig{
@@ -13705,7 +13877,7 @@ func TestGenerateAlertmanagerConfig(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "foo",
- Namespace: ptr.To("other"),
+ Namespace: new("other"),
Port: intstr.FromString("web"),
TLSConfig: &monitoringv1.TLSConfig{
SafeTLSConfig: monitoringv1.SafeTLSConfig{
@@ -13743,7 +13915,7 @@ func TestGenerateAlertmanagerConfig(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "foo",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromString("web"),
},
},
@@ -13813,7 +13985,7 @@ func TestAlertmanagerTLSConfig(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "foo",
- Namespace: ptr.To("other"),
+ Namespace: new("other"),
TLSConfig: &monitoringv1.TLSConfig{
SafeTLSConfig: monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
@@ -13854,7 +14026,7 @@ func TestAlertmanagerTLSConfig(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "foo",
- Namespace: ptr.To("other"),
+ Namespace: new("other"),
TLSConfig: &monitoringv1.TLSConfig{
SafeTLSConfig: monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
@@ -13895,7 +14067,7 @@ func TestAlertmanagerTLSConfig(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "foo",
- Namespace: ptr.To("other"),
+ Namespace: new("other"),
TLSConfig: &monitoringv1.TLSConfig{
SafeTLSConfig: monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
@@ -13936,7 +14108,7 @@ func TestAlertmanagerTLSConfig(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "foo",
- Namespace: ptr.To("other"),
+ Namespace: new("other"),
TLSConfig: &monitoringv1.TLSConfig{
SafeTLSConfig: monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
@@ -14186,7 +14358,7 @@ func TestPodMonitorSelectors(t *testing.T) {
},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -14217,7 +14389,7 @@ func TestPodMonitorSelectors(t *testing.T) {
},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -14244,7 +14416,7 @@ func TestPodMonitorSelectors(t *testing.T) {
},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -14282,7 +14454,7 @@ func TestPodMonitorSelectors(t *testing.T) {
},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -14321,19 +14493,19 @@ func TestAppendConvertScrapeClassicHistograms(t *testing.T) {
{
name: "ScrapeClassicHistograms true with Prometheus Version 3.5",
version: "v3.5.0",
- ScrapeClassicHistograms: ptr.To(true),
+ ScrapeClassicHistograms: new(true),
expectedCfg: "ScrapeClassicHistogramsTrueProperPromVersion.golden",
},
{
name: "ScrapeClassicHistograms false with Prometheus Version 3.5",
version: "v3.5.0",
- ScrapeClassicHistograms: ptr.To(false),
+ ScrapeClassicHistograms: new(false),
expectedCfg: "ScrapeClassicHistogramsFalseProperPromVersion.golden",
},
{
name: "ScrapeClassicHistograms true with Prometheus Version 2",
version: "v2.45.0",
- ScrapeClassicHistograms: ptr.To(true),
+ ScrapeClassicHistograms: new(true),
expectedCfg: "ScrapeClassicHistogramsTrueWrongPromVersion.golden",
},
}
@@ -14378,19 +14550,19 @@ func TestAppendScrapeNativeHistograms(t *testing.T) {
{
name: "ScrapeNativeHistograms true with Prometheus Version 3.8",
version: "v3.8.0",
- ScrapeNativeHistograms: ptr.To(true),
+ ScrapeNativeHistograms: new(true),
expectedCfg: "ScrapeNativeHistogramsTrueProperPromVersion.golden",
},
{
name: "ScrapeNativeHistograms false with Prometheus Version 3.8",
version: "v3.8.0",
- ScrapeNativeHistograms: ptr.To(false),
+ ScrapeNativeHistograms: new(false),
expectedCfg: "ScrapeNativeHistogramsFalseProperPromVersion.golden",
},
{
name: "ScrapeNativeHistograms true with Lower Prometheus version",
version: "v3.7.0",
- ScrapeNativeHistograms: ptr.To(true),
+ ScrapeNativeHistograms: new(true),
expectedCfg: "ScrapeNativeHistogramsTrueWrongPromVersion.golden",
},
}
@@ -14459,7 +14631,7 @@ func TestTopologyShardingRelabeling(t *testing.T) {
MatchLabels: map[string]string{"foo": "bar"},
},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
- {Port: ptr.To("web"), Interval: "30s"},
+ {Port: new("web"), Interval: "30s"},
},
},
},
@@ -14467,13 +14639,13 @@ func TestTopologyShardingRelabeling(t *testing.T) {
}
for _, tc := range []struct {
- name string
- shards int32
- zones []string
- serviceMonitor map[string]*monitoringv1.ServiceMonitor
- podMonitor map[string]*monitoringv1.PodMonitor
- attachMetadata *monitoringv1.AttachMetadata
- golden string
+ name string
+ shards int32
+ zones []string
+ serviceMonitor map[string]*monitoringv1.ServiceMonitor
+ podMonitor map[string]*monitoringv1.PodMonitor
+ podTopologyLabels bool
+ golden string
}{
{
name: "service_monitor_4shards_2zones",
@@ -14516,21 +14688,63 @@ func TestTopologyShardingRelabeling(t *testing.T) {
zones: []string{"zone-a", "zone-b"},
serviceMonitor: func() map[string]*monitoringv1.ServiceMonitor {
sm := basicServiceMonitor()
- sm["test"].Spec.AttachMetadata = &monitoringv1.AttachMetadata{Node: ptr.To(false)}
+ sm["test"].Spec.AttachMetadata = &monitoringv1.AttachMetadata{Node: new(false)}
return sm
}(),
golden: "TopologySharding_ServiceMonitor_force_attach_metadata_false.golden",
},
+ // Pod topology labels (K8s >= 1.35) — no attach_metadata.node required.
+ {
+ name: "pod_topology_labels_service_monitor_4shards_2zones",
+ shards: 4,
+ zones: []string{"zone-a", "zone-b"},
+ serviceMonitor: basicServiceMonitor(),
+ podTopologyLabels: true,
+ golden: "TopologySharding_PodTopologyLabels_ServiceMonitor_4shards_2zones.golden",
+ },
+ {
+ name: "pod_topology_labels_pod_monitor_4shards_2zones",
+ shards: 4,
+ zones: []string{"zone-a", "zone-b"},
+ podMonitor: basicPodMonitor(),
+ podTopologyLabels: true,
+ golden: "TopologySharding_PodTopologyLabels_PodMonitor_4shards_2zones.golden",
+ },
+ {
+ name: "pod_topology_labels_service_monitor_6shards_3zones",
+ shards: 6,
+ zones: []string{"zone-a", "zone-b", "zone-c"},
+ serviceMonitor: basicServiceMonitor(),
+ podTopologyLabels: true,
+ golden: "TopologySharding_PodTopologyLabels_ServiceMonitor_6shards_3zones.golden",
+ },
+ {
+ name: "pod_topology_labels_attach_metadata_false_is_respected",
+ shards: 4,
+ zones: []string{"zone-a", "zone-b"},
+ serviceMonitor: func() map[string]*monitoringv1.ServiceMonitor {
+ sm := basicServiceMonitor()
+ sm["test"].Spec.AttachMetadata = &monitoringv1.AttachMetadata{Node: new(bool)}
+ return sm
+ }(),
+ podTopologyLabels: true,
+ golden: "TopologySharding_PodTopologyLabels_ServiceMonitor_attach_metadata_false.golden",
+ },
} {
t.Run(tc.name, func(t *testing.T) {
p := defaultPrometheus()
- p.Spec.Shards = ptr.To(tc.shards)
+ p.Spec.Shards = new(tc.shards)
p.Spec.ShardingStrategy = &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: tc.zones},
}
- cg := mustNewConfigGenerator(t, p, WithPrometheusTopologySharding())
+ opts := []ConfigGeneratorOption{WithPrometheusTopologySharding()}
+ if tc.podTopologyLabels {
+ opts = append(opts, WithPodTopologyLabelsSupport())
+ }
+
+ cg := mustNewConfigGenerator(t, p, opts...)
cfg, err := cg.GenerateServerConfiguration(
p,
tc.serviceMonitor,
@@ -14577,7 +14791,7 @@ func TestShardingRelabelConfigsWithRetention(t *testing.T) {
} {
t.Run(tc.name, func(t *testing.T) {
p := defaultPrometheus()
- p.Spec.Shards = ptr.To(tc.shards)
+ p.Spec.Shards = new(tc.shards)
opts := []ConfigGeneratorOption{}
if tc.retentionEnabled {
@@ -14642,7 +14856,7 @@ func TestTopologyZoneForShard(t *testing.T) {
{
name: "address mode returns empty",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(addressMode),
+ Mode: new(addressMode),
},
prometheusTopologySharding: true,
shardIndex: 0,
@@ -14651,7 +14865,7 @@ func TestTopologyZoneForShard(t *testing.T) {
{
name: "topology mode with no values returns empty",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{}},
},
prometheusTopologySharding: true,
@@ -14661,7 +14875,7 @@ func TestTopologyZoneForShard(t *testing.T) {
{
name: "shard 0 gets first zone",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b"}},
},
prometheusTopologySharding: true,
@@ -14671,7 +14885,7 @@ func TestTopologyZoneForShard(t *testing.T) {
{
name: "shard 1 gets second zone",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b"}},
},
prometheusTopologySharding: true,
@@ -14681,7 +14895,7 @@ func TestTopologyZoneForShard(t *testing.T) {
{
name: "shard 2 wraps around to first zone",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b"}},
},
prometheusTopologySharding: true,
@@ -14727,7 +14941,7 @@ func TestInzoneShardForShard(t *testing.T) {
{
name: "2 shards 2 zones",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b"}},
},
prometheusTopologySharding: true,
@@ -14736,7 +14950,7 @@ func TestInzoneShardForShard(t *testing.T) {
{
name: "2 shards 1 zone",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a"}},
},
prometheusTopologySharding: true,
@@ -14745,7 +14959,7 @@ func TestInzoneShardForShard(t *testing.T) {
{
name: "3 shards 2 zones",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b"}},
},
prometheusTopologySharding: true,
@@ -14754,7 +14968,7 @@ func TestInzoneShardForShard(t *testing.T) {
{
name: "4 shards 2 zones",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b"}},
},
prometheusTopologySharding: true,
@@ -14763,7 +14977,7 @@ func TestInzoneShardForShard(t *testing.T) {
{
name: "6 shards 3 zones",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{Values: []string{"zone-a", "zone-b", "zone-c"}},
},
prometheusTopologySharding: true,
diff --git a/pkg/prometheus/resource_selector.go b/pkg/prometheus/resource_selector.go
index 3a3bb274256..9fb24b449a2 100644
--- a/pkg/prometheus/resource_selector.go
+++ b/pkg/prometheus/resource_selector.go
@@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"log/slog"
+ "maps"
"net"
"net/url"
"slices"
@@ -470,6 +471,9 @@ func (rs *ResourceSelector) checkProbe(ctx context.Context, probe *monitoringv1.
}
if probe.Spec.Targets.StaticConfig != nil {
+ if err := rs.validateStaticConfigLabels(probe.Spec.Targets.StaticConfig.Labels); err != nil {
+ return fmt.Errorf("targets.staticConfig.labels: %w", err)
+ }
if err := rs.ValidateRelabelConfigs(probe.Spec.Targets.StaticConfig.RelabelConfigs); err != nil {
return fmt.Errorf("targets.staticConfig.relabelConfigs: %w", err)
}
@@ -492,6 +496,17 @@ func (rs *ResourceSelector) checkProbe(ctx context.Context, probe *monitoringv1.
return nil
}
+func (rs *ResourceSelector) validateStaticConfigLabels(labels map[string]string) error {
+ keys := slices.Collect(maps.Keys(labels))
+ slices.Sort(keys)
+ for _, labelName := range keys {
+ if !isValidLabelName(labelName, rs.version) {
+ return fmt.Errorf("invalid label %q", labelName)
+ }
+ }
+ return nil
+}
+
// validateProberURL checks that the prober URL is a valid host or host:port.
// We use govalidator.IsHost() because the standard library doesn't offer a
// single function that validates a string as an IP (v4/v6) or DNS hostname.
@@ -1317,10 +1332,8 @@ func (rs *ResourceSelector) validateScalewaySDConfigs(ctx context.Context, sc *m
func (rs *ResourceSelector) validateStaticConfig(sc *monitoringv1alpha1.ScrapeConfig) error {
for i, config := range sc.Spec.StaticConfigs {
- for labelName := range config.Labels {
- if !isValidLabelName(labelName, rs.version) {
- return fmt.Errorf("[%d]: invalid label in map %s", i, labelName)
- }
+ if err := rs.validateStaticConfigLabels(config.Labels); err != nil {
+ return fmt.Errorf("[%d]: %w", i, err)
}
}
diff --git a/pkg/prometheus/resource_selector_test.go b/pkg/prometheus/resource_selector_test.go
index 0946bf99659..444077da704 100644
--- a/pkg/prometheus/resource_selector_test.go
+++ b/pkg/prometheus/resource_selector_test.go
@@ -146,9 +146,9 @@ func TestSelectProbes(t *testing.T) {
scenario: "invalid proxyconfig due to invalid proxyurl",
updateSpec: func(ps *monitoringv1.ProbeSpec) {
ps.ProberSpec.ProxyConfig = monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://xxx-${dev}.svc.cluster.local:80"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://xxx-${dev}.svc.cluster.local:80"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -167,8 +167,8 @@ func TestSelectProbes(t *testing.T) {
scenario: "invalid proxyconfig due to proxy environment set to true and proxyurl defined",
updateSpec: func(ps *monitoringv1.ProbeSpec) {
ps.ProberSpec.ProxyConfig = monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- ProxyFromEnvironment: ptr.To(true),
+ ProxyURL: new("http://no-proxy.com"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -187,8 +187,8 @@ func TestSelectProbes(t *testing.T) {
scenario: "invalid proxyconfig due to proxy environment set to true and noproxy defined",
updateSpec: func(ps *monitoringv1.ProbeSpec) {
ps.ProberSpec.ProxyConfig = monitoringv1.ProxyConfig{
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(true),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -207,8 +207,8 @@ func TestSelectProbes(t *testing.T) {
scenario: "invalid proxyconfig due to invalid secret secret key",
updateSpec: func(ps *monitoringv1.ProbeSpec) {
ps.ProberSpec.ProxyConfig = monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- ProxyFromEnvironment: ptr.To(true),
+ ProxyURL: new("http://no-proxy.com"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -227,7 +227,7 @@ func TestSelectProbes(t *testing.T) {
scenario: "invalid proxyconfig due to proxy from environment set to false and proxyurl and noproxy not defined",
updateSpec: func(ps *monitoringv1.ProbeSpec) {
ps.ProberSpec.ProxyConfig = monitoringv1.ProxyConfig{
- ProxyFromEnvironment: ptr.To(false),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -246,9 +246,9 @@ func TestSelectProbes(t *testing.T) {
scenario: "valid proxyconfig",
updateSpec: func(ps *monitoringv1.ProbeSpec) {
ps.ProberSpec.ProxyConfig = monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -317,6 +317,29 @@ func TestSelectProbes(t *testing.T) {
},
valid: true,
},
+ {
+ scenario: "valid static target labels",
+ updateSpec: func(ps *monitoringv1.ProbeSpec) {
+ ps.Targets.StaticConfig.Labels = map[string]string{"owner": "team-a"}
+ },
+ valid: true,
+ },
+ {
+ scenario: "invalid static target label with prom2",
+ updateSpec: func(ps *monitoringv1.ProbeSpec) {
+ ps.Targets.StaticConfig.Labels = map[string]string{"cluster-id": "xxx"}
+ },
+ promVersion: "2.55.0",
+ valid: false,
+ },
+ {
+ scenario: "static target label with prom3",
+ promVersion: "3.0.0",
+ updateSpec: func(ps *monitoringv1.ProbeSpec) {
+ ps.Targets.StaticConfig.Labels = map[string]string{"cluster-id": "xxx"}
+ },
+ valid: true,
+ },
{
scenario: "utf-8 static relabeling config with prom2",
updateSpec: func(ps *monitoringv1.ProbeSpec) {
@@ -395,7 +418,7 @@ func TestSelectProbes(t *testing.T) {
},
{
scenario: "inexistent scrape class",
- scrapeClass: ptr.To("inexistent"),
+ scrapeClass: new("inexistent"),
updateSpec: func(ps *monitoringv1.ProbeSpec) {
ps.Targets.StaticConfig = nil
ps.Targets.Ingress = &monitoringv1.ProbeTargetIngress{
@@ -412,7 +435,7 @@ func TestSelectProbes(t *testing.T) {
},
{
scenario: "existent scrape class",
- scrapeClass: ptr.To("existent"),
+ scrapeClass: new("existent"),
updateSpec: func(ps *monitoringv1.ProbeSpec) {
ps.Targets.StaticConfig = nil
ps.Targets.Ingress = &monitoringv1.ProbeTargetIngress{
@@ -901,9 +924,9 @@ func TestSelectServiceMonitors(t *testing.T) {
sm.Endpoints = append(sm.Endpoints, monitoringv1.Endpoint{
HTTPConfigWithProxyAndTLSFiles: monitoringv1.HTTPConfigWithProxyAndTLSFiles{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -926,9 +949,9 @@ func TestSelectServiceMonitors(t *testing.T) {
sm.Endpoints = append(sm.Endpoints, monitoringv1.Endpoint{
HTTPConfigWithProxyAndTLSFiles: monitoringv1.HTTPConfigWithProxyAndTLSFiles{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -951,9 +974,9 @@ func TestSelectServiceMonitors(t *testing.T) {
sm.Endpoints = append(sm.Endpoints, monitoringv1.Endpoint{
HTTPConfigWithProxyAndTLSFiles: monitoringv1.HTTPConfigWithProxyAndTLSFiles{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://xxx-${dev}.svc.cluster.local:80"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://xxx-${dev}.svc.cluster.local:80"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -976,8 +999,8 @@ func TestSelectServiceMonitors(t *testing.T) {
sm.Endpoints = append(sm.Endpoints, monitoringv1.Endpoint{
HTTPConfigWithProxyAndTLSFiles: monitoringv1.HTTPConfigWithProxyAndTLSFiles{
ProxyConfig: monitoringv1.ProxyConfig{
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(true),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1000,8 +1023,8 @@ func TestSelectServiceMonitors(t *testing.T) {
sm.Endpoints = append(sm.Endpoints, monitoringv1.Endpoint{
HTTPConfigWithProxyAndTLSFiles: monitoringv1.HTTPConfigWithProxyAndTLSFiles{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- ProxyFromEnvironment: ptr.To(true),
+ ProxyURL: new("http://no-proxy.com"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1042,14 +1065,14 @@ func TestSelectServiceMonitors(t *testing.T) {
},
{
scenario: "inexistent Scrape Class",
- scrapeClass: ptr.To("inexistent"),
+ scrapeClass: new("inexistent"),
updateSpec: func(_ *monitoringv1.ServiceMonitorSpec) {
},
valid: false,
},
{
scenario: "existent Scrape Class",
- scrapeClass: ptr.To("existent"),
+ scrapeClass: new("existent"),
updateSpec: func(_ *monitoringv1.ServiceMonitorSpec) {
},
valid: true,
@@ -1294,9 +1317,9 @@ func TestSelectPodMonitors(t *testing.T) {
pm.PodMetricsEndpoints = append(pm.PodMetricsEndpoints, monitoringv1.PodMetricsEndpoint{
HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1319,9 +1342,9 @@ func TestSelectPodMonitors(t *testing.T) {
pm.PodMetricsEndpoints = append(pm.PodMetricsEndpoints, monitoringv1.PodMetricsEndpoint{
HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1344,9 +1367,9 @@ func TestSelectPodMonitors(t *testing.T) {
pm.PodMetricsEndpoints = append(pm.PodMetricsEndpoints, monitoringv1.PodMetricsEndpoint{
HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://xxx-${dev}.svc.cluster.local:80"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://xxx-${dev}.svc.cluster.local:80"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1369,8 +1392,8 @@ func TestSelectPodMonitors(t *testing.T) {
pm.PodMetricsEndpoints = append(pm.PodMetricsEndpoints, monitoringv1.PodMetricsEndpoint{
HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
ProxyConfig: monitoringv1.ProxyConfig{
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(true),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1393,8 +1416,8 @@ func TestSelectPodMonitors(t *testing.T) {
pm.PodMetricsEndpoints = append(pm.PodMetricsEndpoints, monitoringv1.PodMetricsEndpoint{
HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- ProxyFromEnvironment: ptr.To(true),
+ ProxyURL: new("http://no-proxy.com"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1435,14 +1458,14 @@ func TestSelectPodMonitors(t *testing.T) {
},
{
scenario: "Inexistent Scrape Class",
- scrapeClass: ptr.To("inexistent"),
+ scrapeClass: new("inexistent"),
updateSpec: func(_ *monitoringv1.PodMonitorSpec) {
},
valid: false,
},
{
scenario: "existent Scrape Class",
- scrapeClass: ptr.To("existent"),
+ scrapeClass: new("existent"),
updateSpec: func(_ *monitoringv1.PodMonitorSpec) {
},
valid: true,
@@ -1666,9 +1689,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
scenario: "valid proxy config",
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.ProxyConfig = monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1705,8 +1728,8 @@ func TestSelectScrapeConfigs(t *testing.T) {
scenario: "invalid proxy config with proxy from environment set to true but proxyUrl defined",
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.ProxyConfig = monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- ProxyFromEnvironment: ptr.To(true),
+ ProxyURL: new("http://no-proxy.com"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1725,8 +1748,8 @@ func TestSelectScrapeConfigs(t *testing.T) {
scenario: "invalid proxy config with proxyFromEnvironment set to true but noProxy defined",
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.ProxyConfig = monitoringv1.ProxyConfig{
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(true),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1745,9 +1768,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
scenario: "invalid proxy config with invalid secret key",
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.ProxyConfig = monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1772,7 +1795,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
scenario: "invalid proxy config with noProxy defined and but no proxyUrl defined",
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.ProxyConfig = monitoringv1.ProxyConfig{
- NoProxy: ptr.To("0.0.0.0"),
+ NoProxy: new("0.0.0.0"),
}
},
valid: false,
@@ -1781,9 +1804,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
scenario: "valid proxy config with multi header values",
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.ProxyConfig = monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1814,9 +1837,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
scenario: "invalid proxy config with one invalid secret key",
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.ProxyConfig = monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1872,9 +1895,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
URL: "http://example.com",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1899,8 +1922,8 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
URL: "http://example.com",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- ProxyFromEnvironment: ptr.To(true),
+ ProxyURL: new("http://no-proxy.com"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -1964,9 +1987,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.HTTPSDConfigs = []monitoringv1alpha1.HTTPSDConfig{
{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -2105,9 +2128,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Role: monitoringv1alpha1.KubernetesRoleNode,
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -2131,8 +2154,8 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Role: monitoringv1alpha1.KubernetesRoleNode,
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- ProxyFromEnvironment: ptr.To(true),
+ ProxyURL: new("http://no-proxy.com"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -2156,7 +2179,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Selectors: []monitoringv1alpha1.K8SSelectorConfig{
{
- Label: ptr.To("app=example,env!=production,release in (v1, v2)"),
+ Label: new("app=example,env!=production,release in (v1, v2)"),
},
},
},
@@ -2171,7 +2194,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Selectors: []monitoringv1alpha1.K8SSelectorConfig{
{
- Field: ptr.To("status.phase=Running,metadata.name!=worker"),
+ Field: new("status.phase=Running,metadata.name!=worker"),
},
},
},
@@ -2293,8 +2316,8 @@ func TestSelectScrapeConfigs(t *testing.T) {
Selectors: []monitoringv1alpha1.K8SSelectorConfig{
{
Role: monitoringv1alpha1.KubernetesRoleNode,
- Label: ptr.To("app=example,env!=production,release in (v1, v2)"),
- Field: ptr.To("status.phase=Running,metadata.name!=worker"),
+ Label: new("app=example,env!=production,release in (v1, v2)"),
+ Field: new("status.phase=Running,metadata.name!=worker"),
},
},
},
@@ -2307,7 +2330,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.KubernetesSDConfigs = []monitoringv1alpha1.KubernetesSDConfig{
{
- APIServer: ptr.To("https://kube-api-server-address:6443"),
+ APIServer: new("https://kube-api-server-address:6443"),
},
}
},
@@ -2319,7 +2342,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.KubernetesSDConfigs = []monitoringv1alpha1.KubernetesSDConfig{
{
Namespaces: &monitoringv1alpha1.NamespaceDiscovery{
- IncludeOwnNamespace: ptr.To(true),
+ IncludeOwnNamespace: new(true),
},
},
}
@@ -2331,9 +2354,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.KubernetesSDConfigs = []monitoringv1alpha1.KubernetesSDConfig{
{
- APIServer: ptr.To("https://kube-api-server-address:6443"),
+ APIServer: new("https://kube-api-server-address:6443"),
Namespaces: &monitoringv1alpha1.NamespaceDiscovery{
- IncludeOwnNamespace: ptr.To(true),
+ IncludeOwnNamespace: new(true),
},
},
}
@@ -2391,7 +2414,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.ConsulSDConfigs = []monitoringv1alpha1.ConsulSDConfig{
{
Server: "example.com",
- Filter: ptr.To("Meta.env == \"qa\""),
+ Filter: new("Meta.env == \"qa\""),
},
}
},
@@ -2404,7 +2427,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.ConsulSDConfigs = []monitoringv1alpha1.ConsulSDConfig{
{
Server: "example.com",
- Filter: ptr.To("Meta.env == \"qa\""),
+ Filter: new("Meta.env == \"qa\""),
},
}
},
@@ -2417,7 +2440,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.ConsulSDConfigs = []monitoringv1alpha1.ConsulSDConfig{
{
Server: "example.com",
- HealthFilter: ptr.To("Service.Meta.env == \"prod\""),
+ HealthFilter: new("Service.Meta.env == \"prod\""),
},
}
},
@@ -2430,7 +2453,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.ConsulSDConfigs = []monitoringv1alpha1.ConsulSDConfig{
{
Server: "example.com",
- HealthFilter: ptr.To("Service.Meta.env == \"prod\""),
+ HealthFilter: new("Service.Meta.env == \"prod\""),
},
}
},
@@ -2452,9 +2475,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
},
{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -2603,7 +2626,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Names: []string{"node.demo.do.prometheus.io"},
Type: ptr.To(monitoringv1alpha1.DNSRecordTypeMX),
- Port: ptr.To(int32(9900)),
+ Port: new(int32(9900)),
},
}
},
@@ -2617,7 +2640,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Names: []string{"node.demo.do.prometheus.io"},
Type: ptr.To(monitoringv1alpha1.DNSRecordTypeA),
- Port: ptr.To(int32(9900)),
+ Port: new(int32(9900)),
},
}
},
@@ -2631,7 +2654,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Names: []string{"node.demo.do.prometheus.io"},
Type: ptr.To(monitoringv1alpha1.DNSRecordTypeA),
- Port: ptr.To(int32(9900)),
+ Port: new(int32(9900)),
},
}
},
@@ -2644,7 +2667,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Names: []string{"node.demo.do.prometheus.io"},
Type: ptr.To(monitoringv1alpha1.DNSRecordTypeNS),
- Port: ptr.To(int32(9900)),
+ Port: new(int32(9900)),
},
}
},
@@ -2658,7 +2681,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Names: []string{"node.demo.do.prometheus.io"},
Type: ptr.To(monitoringv1alpha1.DNSRecordTypeMX),
- Port: ptr.To(int32(9900)),
+ Port: new(int32(9900)),
},
}
},
@@ -2672,7 +2695,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Names: []string{"node.demo.do.prometheus.io"},
Type: ptr.To(monitoringv1alpha1.DNSRecordTypeA),
- Port: ptr.To(int32(9900)),
+ Port: new(int32(9900)),
},
}
},
@@ -2684,7 +2707,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.EC2SDConfigs = []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
AccessKey: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "secret",
@@ -2707,7 +2730,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.EC2SDConfigs = []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
},
}
},
@@ -2718,7 +2741,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.EC2SDConfigs = []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
AccessKey: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "secret",
@@ -2741,7 +2764,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.EC2SDConfigs = []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
TLSConfig: &monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
@@ -2776,7 +2799,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.EC2SDConfigs = []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
TLSConfig: &monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
@@ -2802,7 +2825,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
},
},
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
},
}
},
@@ -2814,7 +2837,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.EC2SDConfigs = []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
TLSConfig: &monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
@@ -2835,11 +2858,11 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.EC2SDConfigs = []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -2862,8 +2885,8 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.AzureSDConfigs = []monitoringv1alpha1.AzureSDConfig{
{
- TenantID: ptr.To("BBBB222B-B2B2-2B22-B222-2BB2222BB2B2"),
- ClientID: ptr.To("333333CC-3C33-3333-CCC3-33C3CCCCC33C"),
+ TenantID: new("BBBB222B-B2B2-2B22-B222-2BB2222BB2B2"),
+ ClientID: new("333333CC-3C33-3333-CCC3-33C3CCCCC33C"),
ClientSecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "secret",
@@ -2881,8 +2904,8 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.AzureSDConfigs = []monitoringv1alpha1.AzureSDConfig{
{
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeOAuth),
- TenantID: ptr.To("BBBB222B-B2B2-2B22-B222-2BB2222BB2B2"),
- ClientID: ptr.To("333333CC-3C33-3333-CCC3-33C3CCCCC33C"),
+ TenantID: new("BBBB222B-B2B2-2B22-B222-2BB2222BB2B2"),
+ ClientID: new("333333CC-3C33-3333-CCC3-33C3CCCCC33C"),
},
}
},
@@ -2894,7 +2917,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.AzureSDConfigs = []monitoringv1alpha1.AzureSDConfig{
{
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeOAuth),
- ClientID: ptr.To("333333CC-3C33-3333-CCC3-33C3CCCCC33C"),
+ ClientID: new("333333CC-3C33-3333-CCC3-33C3CCCCC33C"),
ClientSecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "secret",
@@ -2912,7 +2935,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.AzureSDConfigs = []monitoringv1alpha1.AzureSDConfig{
{
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeOAuth),
- TenantID: ptr.To("BBBB222B-B2B2-2B22-B222-2BB2222BB2B2"),
+ TenantID: new("BBBB222B-B2B2-2B22-B222-2BB2222BB2B2"),
ClientSecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "secret",
@@ -2965,7 +2988,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.AzureSDConfigs = []monitoringv1alpha1.AzureSDConfig{
{
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeManagedIdentity),
- ResourceGroup: ptr.To("my-resource-group"),
+ ResourceGroup: new("my-resource-group"),
},
}
},
@@ -2978,7 +3001,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.AzureSDConfigs = []monitoringv1alpha1.AzureSDConfig{
{
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeManagedIdentity),
- ResourceGroup: ptr.To("my-resource-group"),
+ ResourceGroup: new("my-resource-group"),
},
}
},
@@ -2991,8 +3014,8 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.AzureSDConfigs = []monitoringv1alpha1.AzureSDConfig{
{
SubscriptionID: "11111111-1111-1111-1111-111111111111",
- TenantID: ptr.To("BBBB222B-B2B2-2B22-B222-2BB2222BB2B2"),
- ClientID: ptr.To("333333CC-3C33-3333-CCC3-33C3CCCCC33C"),
+ TenantID: new("BBBB222B-B2B2-2B22-B222-2BB2222BB2B2"),
+ ClientID: new("333333CC-3C33-3333-CCC3-33C3CCCCC33C"),
ClientSecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "secret",
@@ -3315,9 +3338,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Server: "http://example.com",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -3413,9 +3436,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.EurekaSDConfigs = []monitoringv1alpha1.EurekaSDConfig{
{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -3736,9 +3759,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Role: "hcloud",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -3762,8 +3785,8 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Role: "hcloud",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- ProxyFromEnvironment: ptr.To(true),
+ ProxyURL: new("http://no-proxy.com"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -3843,9 +3866,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
Server: "http://localhost:4646",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -3898,7 +3921,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.DockerSDConfigs = []monitoringv1alpha1.DockerSDConfig{
{
Host: "unix:///var/run/docker.sock",
- MatchFirstNetwork: ptr.To(true),
+ MatchFirstNetwork: new(true),
},
}
},
@@ -3911,7 +3934,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.DockerSDConfigs = []monitoringv1alpha1.DockerSDConfig{
{
Host: "unix:///var/run/docker.sock",
- MatchFirstNetwork: ptr.To(true),
+ MatchFirstNetwork: new(true),
},
}
},
@@ -3924,7 +3947,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.HetznerSDConfigs = []monitoringv1alpha1.HetznerSDConfig{
{
Role: "hcloud",
- LabelSelector: ptr.To("env=production"),
+ LabelSelector: new("env=production"),
},
}
},
@@ -3937,7 +3960,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.HetznerSDConfigs = []monitoringv1alpha1.HetznerSDConfig{
{
Role: "hcloud",
- LabelSelector: ptr.To("env=production"),
+ LabelSelector: new("env=production"),
},
}
},
@@ -4004,9 +4027,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.DockerSwarmSDConfigs = []monitoringv1alpha1.DockerSwarmSDConfig{
{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -4104,9 +4127,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
{
URL: "https://example.com",
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -4214,9 +4237,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.LightSailSDConfigs = []monitoringv1alpha1.LightSailSDConfig{
{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -4239,8 +4262,8 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.LightSailSDConfigs = []monitoringv1alpha1.LightSailSDConfig{
{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- ProxyFromEnvironment: ptr.To(true),
+ ProxyURL: new("http://no-proxy.com"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -4281,7 +4304,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.LightSailSDConfigs = []monitoringv1alpha1.LightSailSDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
AccessKey: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "secret",
@@ -4304,7 +4327,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.LightSailSDConfigs = []monitoringv1alpha1.LightSailSDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
},
}
},
@@ -4315,7 +4338,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.LightSailSDConfigs = []monitoringv1alpha1.LightSailSDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
AccessKey: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "wrong",
@@ -4338,7 +4361,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
updateSpec: func(sc *monitoringv1alpha1.ScrapeConfigSpec) {
sc.LightSailSDConfigs = []monitoringv1alpha1.LightSailSDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
AccessKey: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "secret",
@@ -4375,7 +4398,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
Key: "key2",
},
Service: monitoringv1alpha1.OVHServiceVPS,
- Endpoint: ptr.To("127.0.0.1"),
+ Endpoint: new("127.0.0.1"),
},
}
},
@@ -4396,10 +4419,10 @@ func TestSelectScrapeConfigs(t *testing.T) {
ProjectID: "1",
Role: monitoringv1alpha1.ScalewayRoleInstance,
- Zone: ptr.To("beijing-1"),
- Port: ptr.To(int32(23456)),
+ Zone: new("beijing-1"),
+ Port: new(int32(23456)),
ApiURL: ptr.To(monitoringv1alpha1.URL("https://api.scaleway.com/")),
- NameFilter: ptr.To("name"),
+ NameFilter: new("name"),
TagsFilter: []string{"aa", "bb"},
},
}
@@ -4431,8 +4454,8 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.ScalewaySDConfigs = []monitoringv1alpha1.ScalewaySDConfig{
{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- ProxyFromEnvironment: ptr.To(true),
+ ProxyURL: new("http://no-proxy.com"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -4529,9 +4552,9 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.IonosSDConfigs = []monitoringv1alpha1.IonosSDConfig{
{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- NoProxy: ptr.To("0.0.0.0"),
- ProxyFromEnvironment: ptr.To(false),
+ ProxyURL: new("http://no-proxy.com"),
+ NoProxy: new("0.0.0.0"),
+ ProxyFromEnvironment: new(false),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -4554,8 +4577,8 @@ func TestSelectScrapeConfigs(t *testing.T) {
sc.IonosSDConfigs = []monitoringv1alpha1.IonosSDConfig{
{
ProxyConfig: monitoringv1.ProxyConfig{
- ProxyURL: ptr.To("http://no-proxy.com"),
- ProxyFromEnvironment: ptr.To(true),
+ ProxyURL: new("http://no-proxy.com"),
+ ProxyFromEnvironment: new(true),
ProxyConnectHeader: map[string][]corev1.SecretKeySelector{
"header": {
{
@@ -4601,7 +4624,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
}
},
valid: false,
- scrapeClass: ptr.To("inexistent"),
+ scrapeClass: new("inexistent"),
},
{
scenario: "inexistent Scrape Class",
@@ -4614,7 +4637,7 @@ func TestSelectScrapeConfigs(t *testing.T) {
}
},
valid: true,
- scrapeClass: ptr.To("existent"),
+ scrapeClass: new("existent"),
},
} {
t.Run(tc.scenario, func(t *testing.T) {
@@ -4804,7 +4827,7 @@ func TestSelectPodMonitorsWithInvalidAuthentication(t *testing.T) {
p := defaultPrometheus()
pme := monitoringv1.PodMetricsEndpoint{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
}
tc.updateFunc(&pme)
diff --git a/pkg/prometheus/server/operator.go b/pkg/prometheus/server/operator.go
index e2152cfd58b..f61b166f735 100644
--- a/pkg/prometheus/server/operator.go
+++ b/pkg/prometheus/server/operator.go
@@ -109,6 +109,7 @@ type Operator struct {
retentionPoliciesEnabled bool
configResourcesStatusEnabled bool
topologyShardingEnabled bool
+ podTopologyLabelsSupported bool
newEventRecorder operator.NewEventRecorderFunc
finalizerSyncer *operator.FinalizerSyncer
@@ -172,6 +173,16 @@ func WithConfigResourceStatus() ControllerOption {
}
}
+// WithPodTopologyLabels tells that the cluster runs K8s >= 1.35 where
+// PodTopologyLabelsAdmission automatically injects topology labels onto pods.
+// When set, the operator uses pod label SD meta labels for zone detection in
+// topology sharding instead of forcing attach_metadata.node=true.
+func WithPodTopologyLabels() ControllerOption {
+ return func(o *Operator) {
+ o.podTopologyLabelsSupported = true
+ }
+}
+
// New creates a new controller.
func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger *slog.Logger, r prometheus.Registerer, opts ...ControllerOption) (*Operator, error) {
logger = logger.With("component", controllerName)
@@ -208,12 +219,13 @@ func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger
accessor: operator.NewAccessor(logger),
config: prompkg.Config{
- LocalHost: c.LocalHost,
- ReloaderConfig: c.ReloaderConfig,
- PrometheusDefaultBaseImage: c.PrometheusDefaultBaseImage,
- ThanosDefaultBaseImage: c.ThanosDefaultBaseImage,
- Annotations: c.Annotations,
- Labels: c.Labels,
+ LocalHost: c.LocalHost,
+ ReloaderConfig: c.ReloaderConfig,
+ PrometheusDefaultBaseImage: c.PrometheusDefaultBaseImage,
+ ThanosDefaultBaseImage: c.ThanosDefaultBaseImage,
+ Annotations: c.Annotations,
+ Labels: c.Labels,
+ WatchObjectRefsInAllNamespaces: c.WatchObjectRefsInAllNamespaces,
},
metrics: operator.NewMetrics(r),
reconciliations: &operator.ReconciliationTracker{},
@@ -495,7 +507,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
monitoringv1.ServiceMonitorsKind,
- c.enqueueForMonitorNamespace,
+ c.enqueueForNamespaceFunc(c.nsMonInf.GetStore()),
operator.WithFilter(
operator.AnyFilter(
operator.GenerationChanged,
@@ -509,7 +521,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
monitoringv1.PodMonitorsKind,
- c.enqueueForMonitorNamespace,
+ c.enqueueForNamespaceFunc(c.nsMonInf.GetStore()),
operator.WithFilter(
operator.AnyFilter(
operator.GenerationChanged,
@@ -523,7 +535,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
monitoringv1.ProbesKind,
- c.enqueueForMonitorNamespace,
+ c.enqueueForNamespaceFunc(c.nsMonInf.GetStore()),
operator.WithFilter(
operator.AnyFilter(
operator.GenerationChanged,
@@ -538,7 +550,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
monitoringv1alpha1.ScrapeConfigsKind,
- c.enqueueForMonitorNamespace,
+ c.enqueueForNamespaceFunc(c.nsMonInf.GetStore()),
operator.WithFilter(
operator.AnyFilter(
operator.GenerationChanged,
@@ -553,7 +565,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
monitoringv1.PrometheusRuleKind,
- c.enqueueForMonitorNamespace,
+ c.enqueueForNamespaceFunc(c.nsMonInf.GetStore()),
operator.WithFilter(
operator.AnyFilter(
operator.GenerationChanged,
@@ -566,12 +578,19 @@ func (c *Operator) addHandlers() {
c.promInfs,
c.reconciliations,
)
+ var gbk operator.GetByKeyer = c.nsPromInf.GetStore()
+ if c.config.WatchObjectRefsInAllNamespaces && c.nsPromInf != c.nsMonInf {
+ gbk = operator.NewMultiGetByKeyer(
+ c.nsPromInf.GetStore(),
+ c.nsMonInf.GetStore(),
+ )
+ }
c.cmapInfs.AddEventHandler(operator.NewEventHandler(
c.logger,
c.accessor,
c.metrics,
operator.ConfigMapGVK().Kind,
- c.enqueueForPrometheusNamespace,
+ c.enqueueForNamespaceFunc(gbk),
operator.WithFilter(operator.ResourceVersionChanged),
operator.WithFilter(hasRefFunc),
))
@@ -581,7 +600,7 @@ func (c *Operator) addHandlers() {
c.accessor,
c.metrics,
operator.SecretGVK().Kind,
- c.enqueueForPrometheusNamespace,
+ c.enqueueForNamespaceFunc(gbk),
operator.WithFilter(operator.ResourceVersionChanged),
operator.WithFilter(hasRefFunc),
))
@@ -688,18 +707,16 @@ func (c *Operator) RefreshStatusFor(o metav1.Object) {
c.rr.EnqueueForStatus(o)
}
-func (c *Operator) enqueueForPrometheusNamespace(nsName string) {
- c.enqueueForNamespace(c.nsPromInf.GetStore(), nsName)
-}
-
-func (c *Operator) enqueueForMonitorNamespace(nsName string) {
- c.enqueueForNamespace(c.nsMonInf.GetStore(), nsName)
+func (c *Operator) enqueueForNamespaceFunc(gbk operator.GetByKeyer) func(string) {
+ return func(ns string) {
+ c.enqueueForNamespace(gbk, ns)
+ }
}
// enqueueForNamespace enqueues all Prometheus object keys that belong to the
// given namespace or select objects in the given namespace.
-func (c *Operator) enqueueForNamespace(store cache.Store, nsName string) {
- nsObject, found, err := store.GetByKey(nsName)
+func (c *Operator) enqueueForNamespace(gbk operator.GetByKeyer, nsName string) {
+ nsObject, found, err := gbk.GetByKey(nsName)
if err != nil {
c.logger.Error(
"get namespace to enqueue Prometheus instances failed",
@@ -958,6 +975,9 @@ func (c *Operator) sync(ctx context.Context, key string) (func(context.Context)
if c.topologyShardingEnabled {
opts = append(opts, prompkg.WithPrometheusTopologySharding())
}
+ if c.podTopologyLabelsSupported {
+ opts = append(opts, prompkg.WithPodTopologyLabelsSupport())
+ }
cg, err := prompkg.NewConfigGenerator(logger, p, opts...)
if err != nil {
return closure, err
@@ -1337,7 +1357,7 @@ func gracePeriodForPrometheusStorage(p *monitoringv1.Prometheus) (time.Duration,
retention = p.Spec.Retention
if retention == "" {
- retention = defaultRetention
+ retention = monitoringv1.Duration(prompkg.DefaultRetention)
}
}
diff --git a/pkg/prometheus/server/operator_test.go b/pkg/prometheus/server/operator_test.go
index 27158e94845..1d657edf79b 100644
--- a/pkg/prometheus/server/operator_test.go
+++ b/pkg/prometheus/server/operator_test.go
@@ -29,7 +29,6 @@ import (
k8sruntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
clienttesting "k8s.io/client-go/testing"
- "k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
"github.com/prometheus-operator/prometheus-operator/pkg/operator"
@@ -220,7 +219,7 @@ func TestCreateStatefulSetInputHash(t *testing.T) {
require.Equal(t, p1Hash, p2Hash, "expected two Prometheus CRDs to produce the same hash but got different hash")
- p2Hash, err = createSSetInputHash(tc.a, c, []string{}, &operator.ShardedSecret{}, appsv1.StatefulSetSpec{Replicas: ptr.To(int32(2))})
+ p2Hash, err = createSSetInputHash(tc.a, c, []string{}, &operator.ShardedSecret{}, appsv1.StatefulSetSpec{Replicas: new(int32(2))})
require.NoError(t, err)
require.NotEqual(t, p1Hash, p2Hash, "expected same Prometheus CRDs with different statefulset specs to produce different hashes but got equal hash")
@@ -303,7 +302,7 @@ func TestProcessShardRetention(t *testing.T) {
retentionPoliciesEnabled: true,
spec: monitoringv1.PrometheusSpec{
ShardRetentionPolicy: &monitoringv1.ShardRetentionPolicy{
- WhenScaled: ptr.To(monitoringv1.DeleteWhenScaledRetentionType),
+ WhenScaled: new(monitoringv1.DeleteWhenScaledRetentionType),
},
},
expectedDelete: true,
@@ -313,7 +312,7 @@ func TestProcessShardRetention(t *testing.T) {
retentionPoliciesEnabled: true,
spec: monitoringv1.PrometheusSpec{
ShardRetentionPolicy: &monitoringv1.ShardRetentionPolicy{
- WhenScaled: ptr.To(monitoringv1.RetainWhenScaledRetentionType),
+ WhenScaled: new(monitoringv1.RetainWhenScaledRetentionType),
},
},
expectedDelete: false,
@@ -325,7 +324,7 @@ func TestProcessShardRetention(t *testing.T) {
retentionPoliciesEnabled: true,
spec: monitoringv1.PrometheusSpec{
ShardRetentionPolicy: &monitoringv1.ShardRetentionPolicy{
- WhenScaled: ptr.To(monitoringv1.RetainWhenScaledRetentionType),
+ WhenScaled: new(monitoringv1.RetainWhenScaledRetentionType),
},
},
annotations: map[string]string{deletionDeadlineAnnotation: time.Now().UTC().Add(24 * time.Hour).Format(annotationTimeFormat)},
@@ -338,7 +337,7 @@ func TestProcessShardRetention(t *testing.T) {
spec: monitoringv1.PrometheusSpec{
RetentionSize: "10Gi",
ShardRetentionPolicy: &monitoringv1.ShardRetentionPolicy{
- WhenScaled: ptr.To(monitoringv1.RetainWhenScaledRetentionType),
+ WhenScaled: new(monitoringv1.RetainWhenScaledRetentionType),
},
},
expectedDelete: false,
@@ -350,7 +349,7 @@ func TestProcessShardRetention(t *testing.T) {
retentionPoliciesEnabled: true,
spec: monitoringv1.PrometheusSpec{
ShardRetentionPolicy: &monitoringv1.ShardRetentionPolicy{
- WhenScaled: ptr.To(monitoringv1.RetainWhenScaledRetentionType),
+ WhenScaled: new(monitoringv1.RetainWhenScaledRetentionType),
},
},
injectPatchError: true,
@@ -438,7 +437,7 @@ func TestGracePeriodForPrometheusStorage(t *testing.T) {
name: "empty retention uses default (24h)",
spec: monitoringv1.PrometheusSpec{
ShardRetentionPolicy: &monitoringv1.ShardRetentionPolicy{
- WhenScaled: ptr.To(monitoringv1.RetainWhenScaledRetentionType),
+ WhenScaled: new(monitoringv1.RetainWhenScaledRetentionType),
},
},
expectedDuration: 24 * time.Hour,
@@ -447,7 +446,7 @@ func TestGracePeriodForPrometheusStorage(t *testing.T) {
name: "explicit retain retention duration",
spec: monitoringv1.PrometheusSpec{
ShardRetentionPolicy: &monitoringv1.ShardRetentionPolicy{
- WhenScaled: ptr.To(monitoringv1.RetainWhenScaledRetentionType),
+ WhenScaled: new(monitoringv1.RetainWhenScaledRetentionType),
Retain: &monitoringv1.RetainConfig{
RetentionPeriod: monitoringv1.Duration("15d"),
},
@@ -460,7 +459,7 @@ func TestGracePeriodForPrometheusStorage(t *testing.T) {
spec: monitoringv1.PrometheusSpec{
Retention: "15d",
ShardRetentionPolicy: &monitoringv1.ShardRetentionPolicy{
- WhenScaled: ptr.To(monitoringv1.RetainWhenScaledRetentionType),
+ WhenScaled: new(monitoringv1.RetainWhenScaledRetentionType),
},
},
expectedDuration: 15 * 24 * time.Hour,
@@ -470,7 +469,7 @@ func TestGracePeriodForPrometheusStorage(t *testing.T) {
spec: monitoringv1.PrometheusSpec{
RetentionSize: "10Gi",
ShardRetentionPolicy: &monitoringv1.ShardRetentionPolicy{
- WhenScaled: ptr.To(monitoringv1.RetainWhenScaledRetentionType),
+ WhenScaled: new(monitoringv1.RetainWhenScaledRetentionType),
},
},
expectedDuration: 0,
@@ -481,7 +480,7 @@ func TestGracePeriodForPrometheusStorage(t *testing.T) {
Retention: "7d",
RetentionSize: "10Gi",
ShardRetentionPolicy: &monitoringv1.ShardRetentionPolicy{
- WhenScaled: ptr.To(monitoringv1.RetainWhenScaledRetentionType),
+ WhenScaled: new(monitoringv1.RetainWhenScaledRetentionType),
},
},
expectedDuration: 7 * 24 * time.Hour,
@@ -491,7 +490,7 @@ func TestGracePeriodForPrometheusStorage(t *testing.T) {
spec: monitoringv1.PrometheusSpec{
Retention: "invalid",
ShardRetentionPolicy: &monitoringv1.ShardRetentionPolicy{
- WhenScaled: ptr.To(monitoringv1.RetainWhenScaledRetentionType),
+ WhenScaled: new(monitoringv1.RetainWhenScaledRetentionType),
},
},
expectedErr: true,
diff --git a/pkg/prometheus/server/statefulset.go b/pkg/prometheus/server/statefulset.go
index ccd44311707..f2eb3296d86 100644
--- a/pkg/prometheus/server/statefulset.go
+++ b/pkg/prometheus/server/statefulset.go
@@ -34,7 +34,6 @@ import (
)
const (
- defaultRetention = "24h"
prometheusMode = "server"
governingServiceName = "prometheus-operated"
thanosSupportedVersionHTTPClientFlag = "0.24.0"
@@ -267,7 +266,7 @@ func makeStatefulSetSpec(
operator.Zone(topologyZone),
}
if topologyZone != "" {
- reloaderOpts = append(reloaderOpts, operator.InzoneShard(ptr.To(cg.InzoneShardForShard(shard))))
+ reloaderOpts = append(reloaderOpts, operator.InzoneShard(new(cg.InzoneShardForShard(shard))))
}
operatorInitContainers = append(operatorInitContainers,
prompkg.BuildConfigReloader(
@@ -311,8 +310,8 @@ func makeStatefulSetSpec(
Resources: cpf.Resources,
TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
SecurityContext: &corev1.SecurityContext{
- ReadOnlyRootFilesystem: ptr.To(true),
- AllowPrivilegeEscalation: ptr.To(false),
+ ReadOnlyRootFilesystem: new(true),
+ AllowPrivilegeEscalation: new(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
@@ -359,11 +358,11 @@ func makeStatefulSetSpec(
InitContainers: initContainers,
SecurityContext: cpf.SecurityContext,
ServiceAccountName: cpf.ServiceAccountName,
- AutomountServiceAccountToken: ptr.To(ptr.Deref(cpf.AutomountServiceAccountToken, true)),
+ AutomountServiceAccountToken: new(ptr.Deref(cpf.AutomountServiceAccountToken, true)),
NodeSelector: cg.NodeSelectorWithTopologyZone(shard),
SchedulerName: cpf.SchedulerName,
PriorityClassName: cpf.PriorityClassName,
- TerminationGracePeriodSeconds: ptr.To(ptr.Deref(cpf.TerminationGracePeriodSeconds, prompkg.DefaultTerminationGracePeriodSeconds)),
+ TerminationGracePeriodSeconds: new(ptr.Deref(cpf.TerminationGracePeriodSeconds, prompkg.DefaultTerminationGracePeriodSeconds)),
Volumes: volumes,
Tolerations: cpf.Tolerations,
Affinity: cpf.Affinity,
@@ -396,17 +395,18 @@ func buildServerArgs(cg *prompkg.ConfigGenerator, p *monitoringv1.Prometheus) []
if cg.WithMaximumVersion("2.7.0").IsCompatible() {
retentionTimeFlagName = "storage.tsdb.retention"
if p.Spec.Retention == "" {
- retentionTimeFlagValue = defaultRetention
+ retentionTimeFlagValue = prompkg.DefaultRetention
}
- } else if p.Spec.Retention == "" && p.Spec.RetentionSize == "" {
- retentionTimeFlagValue = defaultRetention
+ } else {
+ retentionTimeFlagValue = string(prompkg.RetentionTimeOrDefault(p.Spec.Retention, p.Spec.RetentionSize))
}
- if retentionTimeFlagValue != "" {
+ // Starting with Prometheus v3.11.0, retention settings are populated in the configuration file.
+ if retentionTimeFlagValue != "" && cg.Version().LT(semver.MustParse("3.11.0")) {
promArgs = append(promArgs, monitoringv1.Argument{Name: retentionTimeFlagName, Value: retentionTimeFlagValue})
}
- if p.Spec.RetentionSize != "" {
+ if p.Spec.RetentionSize != "" && cg.Version().LT(semver.MustParse("3.11.0")) {
retentionSizeFlag := monitoringv1.Argument{Name: "storage.tsdb.retention.size", Value: string(p.Spec.RetentionSize)}
promArgs = cg.WithMinimumVersion("2.7.0").AppendCommandlineArgument(promArgs, retentionSizeFlag)
}
@@ -480,7 +480,7 @@ func appendServerVolumes(p *monitoringv1.Prometheus, volumes []corev1.Volume, vo
LocalObjectReference: corev1.LocalObjectReference{
Name: name,
},
- Optional: ptr.To(true),
+ Optional: new(true),
},
},
})
@@ -577,8 +577,8 @@ func createThanosContainer(p *monitoringv1.Prometheus, c prompkg.Config) (*corev
ImagePullPolicy: cpf.ImagePullPolicy,
TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
SecurityContext: &corev1.SecurityContext{
- AllowPrivilegeEscalation: ptr.To(false),
- ReadOnlyRootFilesystem: ptr.To(true),
+ AllowPrivilegeEscalation: new(false),
+ ReadOnlyRootFilesystem: new(true),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
diff --git a/pkg/prometheus/server/statefulset_test.go b/pkg/prometheus/server/statefulset_test.go
index c50ebc59cd6..336a690d804 100644
--- a/pkg/prometheus/server/statefulset_test.go
+++ b/pkg/prometheus/server/statefulset_test.go
@@ -379,7 +379,7 @@ func TestStatefulSetVolumeInitial(t *testing.T) {
LocalObjectReference: corev1.LocalObjectReference{
Name: "rules-configmap-one",
},
- Optional: ptr.To(true),
+ Optional: new(true),
},
},
},
@@ -1288,47 +1288,58 @@ func TestRetentionAndRetentionSize(t *testing.T) {
{"v2.7.0", "1d", "", "--storage.tsdb.retention.time=1d", "--storage.tsdb.retention.size=", true, false},
{"v2.7.0", "", "512MB", "--storage.tsdb.retention.time=24h", "--storage.tsdb.retention.size=512MB", false, true},
{"v2.7.0", "1d", "512MB", "--storage.tsdb.retention.time=1d", "--storage.tsdb.retention.size=512MB", true, true},
+ {"v3.10.0", "1d", "512MB", "--storage.tsdb.retention.time=1d", "--storage.tsdb.retention.size=512MB", true, true},
+ {"v3.11.0", "", "", "--storage.tsdb.retention.time=24h", "--storage.tsdb.retention.size=", false, false},
+ {"v3.11.0", "1d", "", "--storage.tsdb.retention.time=1d", "--storage.tsdb.retention.size=", false, false},
+ {"v3.11.0", "", "512MB", "--storage.tsdb.retention.time=24h", "--storage.tsdb.retention.size=512MB", false, false},
+ {"v3.11.0", "1d", "512MB", "--storage.tsdb.retention.time=1d", "--storage.tsdb.retention.size=512MB", false, false},
}
for _, test := range tests {
- sset, err := makeStatefulSetFromPrometheus(monitoringv1.Prometheus{
- Spec: monitoringv1.PrometheusSpec{
- CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- Version: test.version,
+ t.Run(fmt.Sprintf("%s retention=%q retentionSize=%q", test.version, test.specRetention, test.specRetentionSize), func(t *testing.T) {
+ sset, err := makeStatefulSetFromPrometheus(monitoringv1.Prometheus{
+ Spec: monitoringv1.PrometheusSpec{
+ CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
+ Version: test.version,
+ },
+ Retention: test.specRetention,
+ RetentionSize: test.specRetentionSize,
},
- Retention: test.specRetention,
- RetentionSize: test.specRetentionSize,
- },
- })
- require.NoError(t, err)
+ })
+ require.NoError(t, err)
- promArgs := sset.Spec.Template.Spec.Containers[0].Args
- retentionFlag := strings.Split(test.expectedRetentionArg, "=")[0]
- foundRetentionFlag := false
- foundRetentionSizeFlag := false
- foundRetention := false
- foundRetentionSize := false
- for _, flag := range promArgs {
- if flag == test.expectedRetentionArg {
- foundRetention = true
- } else if flag == test.expectedRetentionSizeArg {
- foundRetentionSize = true
- }
+ promArgs := sset.Spec.Template.Spec.Containers[0].Args
+ retentionFlag := strings.Split(test.expectedRetentionArg, "=")[0]
+ foundRetentionFlag := false
+ foundRetentionSizeFlag := false
+ foundRetention := false
+ foundRetentionSize := false
+ for _, flag := range promArgs {
+ if flag == test.expectedRetentionArg {
+ foundRetention = true
+ } else if flag == test.expectedRetentionSizeArg {
+ foundRetentionSize = true
+ }
- if strings.HasPrefix(flag, retentionFlag) {
- foundRetentionFlag = true
- } else if strings.HasPrefix(flag, "--storage.tsdb.retention.size") {
- foundRetentionSizeFlag = true
+ if strings.HasPrefix(flag, retentionFlag) {
+ foundRetentionFlag = true
+ } else if strings.HasPrefix(flag, "--storage.tsdb.retention.size") {
+ foundRetentionSizeFlag = true
+ }
}
- }
- if test.shouldContainRetention {
- require.True(t, (foundRetention && foundRetentionFlag))
- }
+ if test.shouldContainRetention {
+ require.True(t, (foundRetention && foundRetentionFlag))
+ } else {
+ require.False(t, foundRetentionFlag, "retention flag must not be set for Prometheus %s", test.version)
+ }
- if test.shouldContainRetentionSize {
- require.True(t, (foundRetentionSize && foundRetentionSizeFlag))
- }
+ if test.shouldContainRetentionSize {
+ require.True(t, (foundRetentionSize && foundRetentionSizeFlag))
+ } else {
+ require.False(t, foundRetentionSizeFlag, "retention size flag must not be set for Prometheus %s", test.version)
+ }
+ })
}
}
@@ -1551,7 +1562,7 @@ func TestTSDBAllowOverlappingCompaction(t *testing.T) {
name: "Verify AllowOverlappingCompaction",
version: "v2.55.0",
outOfOrderTimeWindow: "1s",
- objectStorageConfigFile: ptr.To("/etc/thanos.cfg"),
+ objectStorageConfigFile: new("/etc/thanos.cfg"),
shouldContain: true,
},
}
@@ -1563,7 +1574,7 @@ func TestTSDBAllowOverlappingCompaction(t *testing.T) {
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
Version: test.version,
TSDB: &monitoringv1.TSDBSpec{
- OutOfOrderTimeWindow: ptr.To(test.outOfOrderTimeWindow),
+ OutOfOrderTimeWindow: new(test.outOfOrderTimeWindow),
},
},
Thanos: &monitoringv1.ThanosSpec{
@@ -1773,7 +1784,7 @@ func TestExpectStatefulSetMinReadySeconds(t *testing.T) {
sset, err = makeStatefulSetFromPrometheus(monitoringv1.Prometheus{
Spec: monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- MinReadySeconds: ptr.To(int32(5)),
+ MinReadySeconds: new(int32(5)),
},
},
})
@@ -2045,7 +2056,7 @@ func TestScrapeFailureLogFileVolumeMountPresent(t *testing.T) {
sset, err := makeStatefulSetFromPrometheus(monitoringv1.Prometheus{
Spec: monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- ScrapeFailureLogFile: ptr.To("file.log"),
+ ScrapeFailureLogFile: new("file.log"),
},
},
})
@@ -2080,7 +2091,7 @@ func TestScrapeFailureLogFileVolumeMountNotPresent(t *testing.T) {
sset, err := makeStatefulSetFromPrometheus(monitoringv1.Prometheus{
Spec: monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- ScrapeFailureLogFile: ptr.To("/tmp/file.log"),
+ ScrapeFailureLogFile: new("/tmp/file.log"),
},
},
})
@@ -2268,7 +2279,7 @@ func TestPodTemplateConfig(t *testing.T) {
ImagePullSecrets: imagePullSecrets,
SchedulerName: schedulerName,
HostNetwork: hostNetwork,
- HostUsers: ptr.To(true),
+ HostUsers: new(true),
},
},
})
@@ -2334,7 +2345,6 @@ func TestPrometheusAdditionalArgsNoError(t *testing.T) {
for _, argTest := range argTests {
t.Run(argTest.version, func(t *testing.T) {
-
labels := map[string]string{
"testlabel": "testlabelvalue",
}
@@ -2368,7 +2378,6 @@ func TestPrometheusAdditionalArgsNoError(t *testing.T) {
// web.console.templates and web.console.libraries should be present in prometheus versisons < 3
require.Equal(t, argTest.expectedArgs, ssetContainerArgs, "expected Prometheus container args to match, want %s, got %s", argTest.expectedArgs, ssetContainerArgs)
})
-
}
}
@@ -2413,13 +2422,13 @@ func TestRuntimeGOGCEnvVar(t *testing.T) {
{
scenario: "Prometheus < 2.53.0",
version: "v2.51.2",
- gogc: ptr.To(int32(50)),
+ gogc: new(int32(50)),
expectedEnvVar: true,
},
{
scenario: "Prometheus > 2.53.0",
version: "v2.54.0",
- gogc: ptr.To(int32(50)),
+ gogc: new(int32(50)),
expectedEnvVar: false,
},
} {
@@ -2589,7 +2598,7 @@ func TestGRPCServerTLSCipherSuites(t *testing.T) {
sset, err := makeStatefulSetFromPrometheus(monitoringv1.Prometheus{
Spec: monitoringv1.PrometheusSpec{
Thanos: &monitoringv1.ThanosSpec{
- Version: ptr.To(tc.version),
+ Version: new(tc.version),
GRPCServerTLSConfig: &monitoringv1.GRPCServerTLSConfig{
CipherSuites: tc.cipherSuites,
},
@@ -2637,7 +2646,7 @@ func TestGRPCServerTLSCurves(t *testing.T) {
sset, err := makeStatefulSetFromPrometheus(monitoringv1.Prometheus{
Spec: monitoringv1.PrometheusSpec{
Thanos: &monitoringv1.ThanosSpec{
- Version: ptr.To(tc.version),
+ Version: new(tc.version),
GRPCServerTLSConfig: &monitoringv1.GRPCServerTLSConfig{
Curves: tc.curves,
},
@@ -2744,9 +2753,9 @@ func TestPrometheusQuerySpec(t *testing.T) {
},
{
name: "all values provided",
- lookbackDelta: ptr.To("2m"),
- maxConcurrency: ptr.To(int32(10)),
- maxSamples: ptr.To(int32(10000)),
+ lookbackDelta: new("2m"),
+ maxConcurrency: new(int32(10)),
+ maxSamples: new(int32(10000)),
timeout: ptr.To(monitoringv1.Duration("1m")),
expected: []string{
@@ -2758,9 +2767,9 @@ func TestPrometheusQuerySpec(t *testing.T) {
},
{
name: "zero values are skipped",
- lookbackDelta: ptr.To("2m"),
- maxConcurrency: ptr.To(int32(0)),
- maxSamples: ptr.To(int32(0)),
+ lookbackDelta: new("2m"),
+ maxConcurrency: new(int32(0)),
+ maxSamples: new(int32(0)),
timeout: ptr.To(monitoringv1.Duration("1m")),
expected: []string{
@@ -2770,7 +2779,7 @@ func TestPrometheusQuerySpec(t *testing.T) {
},
{
name: "maxConcurrency set to 1",
- maxConcurrency: ptr.To(int32(1)),
+ maxConcurrency: new(int32(1)),
expected: []string{
"--query.max-concurrency=1",
@@ -2778,9 +2787,9 @@ func TestPrometheusQuerySpec(t *testing.T) {
},
{
name: "max samples skipped if version < 2.5",
- lookbackDelta: ptr.To("2m"),
- maxConcurrency: ptr.To(int32(10)),
- maxSamples: ptr.To(int32(10000)),
+ lookbackDelta: new("2m"),
+ maxConcurrency: new(int32(10)),
+ maxSamples: new(int32(10000)),
timeout: ptr.To(monitoringv1.Duration("1m")),
version: "v2.4.0",
@@ -2792,9 +2801,9 @@ func TestPrometheusQuerySpec(t *testing.T) {
},
{
name: "max samples not skipped if version > 2.5",
- lookbackDelta: ptr.To("2m"),
- maxConcurrency: ptr.To(int32(10)),
- maxSamples: ptr.To(int32(10000)),
+ lookbackDelta: new("2m"),
+ maxConcurrency: new(int32(10)),
+ maxSamples: new(int32(10000)),
timeout: ptr.To(monitoringv1.Duration("1m")),
version: "v2.5.0",
@@ -2874,7 +2883,7 @@ func TestSecurityContextCapabilities(t *testing.T) {
name: "Thanos sidecar with object storage",
spec: monitoringv1.PrometheusSpec{
Thanos: &monitoringv1.ThanosSpec{
- ObjectStorageConfigFile: ptr.To("/etc/thanos.cfg"),
+ ObjectStorageConfigFile: new("/etc/thanos.cfg"),
},
},
},
@@ -3096,7 +3105,7 @@ func TestStartupProbeTimeoutSeconds(t *testing.T) {
expectedStartupFailureThreshold: 60,
},
{
- maximumStartupDurationSeconds: ptr.To(int32(600)),
+ maximumStartupDurationSeconds: new(int32(600)),
expectedStartupPeriodSeconds: 60,
expectedStartupFailureThreshold: 10,
},
@@ -3199,12 +3208,12 @@ func TestAutomountServiceAccountToken(t *testing.T) {
},
{
name: "automountServiceAccountToken set to true",
- automountServiceAccountToken: ptr.To(true),
+ automountServiceAccountToken: new(true),
expectedValue: true,
},
{
name: "automountServiceAccountToken set to false",
- automountServiceAccountToken: ptr.To(false),
+ automountServiceAccountToken: new(false),
expectedValue: false,
},
} {
@@ -3276,7 +3285,7 @@ func TestDNSPolicyAndDNSConfig(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- monitoringDNSPolicyPtr := ptr.To(monitoringv1.DNSPolicy(test.dnsPolicy))
+ monitoringDNSPolicyPtr := new(monitoringv1.DNSPolicy(test.dnsPolicy))
var monitoringDNSConfig *monitoringv1.PodDNSConfig
if test.dnsConfig != nil {
@@ -3314,8 +3323,8 @@ func TestStatefulSetenableServiceLinks(t *testing.T) {
enableServiceLinks *bool
expectedEnableServiceLinks *bool
}{
- {enableServiceLinks: ptr.To(false), expectedEnableServiceLinks: ptr.To(false)},
- {enableServiceLinks: ptr.To(true), expectedEnableServiceLinks: ptr.To(true)},
+ {enableServiceLinks: new(false), expectedEnableServiceLinks: new(false)},
+ {enableServiceLinks: new(true), expectedEnableServiceLinks: new(true)},
{enableServiceLinks: nil, expectedEnableServiceLinks: nil},
}
@@ -3394,13 +3403,13 @@ func TestStatefulSetUpdateStrategy(t *testing.T) {
updateStrategy: &monitoringv1.StatefulSetUpdateStrategy{
Type: monitoringv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &monitoringv1.RollingUpdateStatefulSetStrategy{
- MaxUnavailable: ptr.To(intstr.FromInt(1)),
+ MaxUnavailable: new(intstr.FromInt(1)),
},
},
exp: appsv1.StatefulSetUpdateStrategy{
Type: appsv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{
- MaxUnavailable: ptr.To(intstr.FromInt(1)),
+ MaxUnavailable: new(intstr.FromInt(1)),
},
},
},
@@ -3440,7 +3449,7 @@ func TestConfigReloaderTopologyZoneEnvVar(t *testing.T) {
{
name: "shard 0 gets zone-a",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{
Values: []string{"zone-a", "zone-b"},
},
@@ -3451,7 +3460,7 @@ func TestConfigReloaderTopologyZoneEnvVar(t *testing.T) {
{
name: "shard 1 gets zone-b",
shardingStrategy: &monitoringv1.ShardingStrategy{
- Mode: ptr.To(topologyMode),
+ Mode: new(topologyMode),
Topology: &monitoringv1.TopologyShardingStrategy{
Values: []string{"zone-a", "zone-b"},
},
diff --git a/pkg/prometheus/testdata/AdditionalAlertRelabelConfigs_Expected.golden b/pkg/prometheus/testdata/AdditionalAlertRelabelConfigs_Expected.golden
index e879d118a30..dfea43023cf 100644
--- a/pkg/prometheus/testdata/AdditionalAlertRelabelConfigs_Expected.golden
+++ b/pkg/prometheus/testdata/AdditionalAlertRelabelConfigs_Expected.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
alerting:
alert_relabel_configs:
- action: labeldrop
diff --git a/pkg/prometheus/testdata/AdditionalScrapeConfigs_one_prometheus_shard.golden b/pkg/prometheus/testdata/AdditionalScrapeConfigs_one_prometheus_shard.golden
index be7c749029f..583f6c30ec1 100644
--- a/pkg/prometheus/testdata/AdditionalScrapeConfigs_one_prometheus_shard.golden
+++ b/pkg/prometheus/testdata/AdditionalScrapeConfigs_one_prometheus_shard.golden
@@ -40,3 +40,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/AdditionalScrapeConfigs_sharded prometheus.golden b/pkg/prometheus/testdata/AdditionalScrapeConfigs_sharded prometheus.golden
index f74e6d8a921..88493746959 100644
--- a/pkg/prometheus/testdata/AdditionalScrapeConfigs_sharded prometheus.golden
+++ b/pkg/prometheus/testdata/AdditionalScrapeConfigs_sharded prometheus.golden
@@ -75,3 +75,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/AdditionalScrapeConfigs_unsharded_prometheus.golden b/pkg/prometheus/testdata/AdditionalScrapeConfigs_unsharded_prometheus.golden
index be7c749029f..583f6c30ec1 100644
--- a/pkg/prometheus/testdata/AdditionalScrapeConfigs_unsharded_prometheus.golden
+++ b/pkg/prometheus/testdata/AdditionalScrapeConfigs_unsharded_prometheus.golden
@@ -40,3 +40,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/AlertmanagerBearerToken.golden b/pkg/prometheus/testdata/AlertmanagerBearerToken.golden
index 10652852d8d..1a4675d646d 100644
--- a/pkg/prometheus/testdata/AlertmanagerBearerToken.golden
+++ b/pkg/prometheus/testdata/AlertmanagerBearerToken.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
alerting:
alert_relabel_configs:
- action: labeldrop
diff --git a/pkg/prometheus/testdata/AlertmanagerConfigEmpty.golden b/pkg/prometheus/testdata/AlertmanagerConfigEmpty.golden
index 609303fe82c..ecbee05becb 100644
--- a/pkg/prometheus/testdata/AlertmanagerConfigEmpty.golden
+++ b/pkg/prometheus/testdata/AlertmanagerConfigEmpty.golden
@@ -5,3 +5,7 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/AlertmanagerConfigEndpointSlice.golden b/pkg/prometheus/testdata/AlertmanagerConfigEndpointSlice.golden
index fc2b4b67413..f83c4c8ef63 100644
--- a/pkg/prometheus/testdata/AlertmanagerConfigEndpointSlice.golden
+++ b/pkg/prometheus/testdata/AlertmanagerConfigEndpointSlice.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
alerting:
alert_relabel_configs:
- action: labeldrop
diff --git a/pkg/prometheus/testdata/AlertmanagerConfigOtherNamespace.golden b/pkg/prometheus/testdata/AlertmanagerConfigOtherNamespace.golden
index 7f27f66e129..2dd0c66d018 100644
--- a/pkg/prometheus/testdata/AlertmanagerConfigOtherNamespace.golden
+++ b/pkg/prometheus/testdata/AlertmanagerConfigOtherNamespace.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
alerting:
alert_relabel_configs:
- action: labeldrop
diff --git a/pkg/prometheus/testdata/AlertmanagerConfigProxyconfig.golden b/pkg/prometheus/testdata/AlertmanagerConfigProxyconfig.golden
index 20e2ed4ac8c..3bb407169a2 100644
--- a/pkg/prometheus/testdata/AlertmanagerConfigProxyconfig.golden
+++ b/pkg/prometheus/testdata/AlertmanagerConfigProxyconfig.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
alerting:
alert_relabel_configs:
- action: labeldrop
diff --git a/pkg/prometheus/testdata/AlertmanagerConfigTLSconfig.golden b/pkg/prometheus/testdata/AlertmanagerConfigTLSconfig.golden
index 25c2a286b5d..92cb10238ea 100644
--- a/pkg/prometheus/testdata/AlertmanagerConfigTLSconfig.golden
+++ b/pkg/prometheus/testdata/AlertmanagerConfigTLSconfig.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
alerting:
alert_relabel_configs:
- action: labeldrop
diff --git a/pkg/prometheus/testdata/AlertmanagerConfigTLSconfigOtherNamespace.golden b/pkg/prometheus/testdata/AlertmanagerConfigTLSconfigOtherNamespace.golden
index 6350a6f9f56..2cabf1553d1 100644
--- a/pkg/prometheus/testdata/AlertmanagerConfigTLSconfigOtherNamespace.golden
+++ b/pkg/prometheus/testdata/AlertmanagerConfigTLSconfigOtherNamespace.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
alerting:
alert_relabel_configs:
- action: labeldrop
diff --git a/pkg/prometheus/testdata/AlertmanagerTimeoutConfig.golden b/pkg/prometheus/testdata/AlertmanagerTimeoutConfig.golden
index 19d8bba5ad9..a9e7e402227 100644
--- a/pkg/prometheus/testdata/AlertmanagerTimeoutConfig.golden
+++ b/pkg/prometheus/testdata/AlertmanagerTimeoutConfig.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
alerting:
alert_relabel_configs:
- action: labeldrop
diff --git a/pkg/prometheus/testdata/Alertmanager_with_RelabelConfigs.golden b/pkg/prometheus/testdata/Alertmanager_with_RelabelConfigs.golden
index f560f290b25..b1a3bfc4a21 100644
--- a/pkg/prometheus/testdata/Alertmanager_with_RelabelConfigs.golden
+++ b/pkg/prometheus/testdata/Alertmanager_with_RelabelConfigs.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
alerting:
alert_relabel_configs:
- action: labeldrop
diff --git a/pkg/prometheus/testdata/ConsulScrapeConfig.golden b/pkg/prometheus/testdata/ConsulScrapeConfig.golden
index 799f97f72df..e8761a0f0f1 100644
--- a/pkg/prometheus/testdata/ConsulScrapeConfig.golden
+++ b/pkg/prometheus/testdata/ConsulScrapeConfig.golden
@@ -36,3 +36,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ConsulScrapeConfigAuthorization.golden b/pkg/prometheus/testdata/ConsulScrapeConfigAuthorization.golden
index 4aa6082ee36..d4c50b1e3e9 100644
--- a/pkg/prometheus/testdata/ConsulScrapeConfigAuthorization.golden
+++ b/pkg/prometheus/testdata/ConsulScrapeConfigAuthorization.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ConsulScrapeConfigBasicAuth.golden b/pkg/prometheus/testdata/ConsulScrapeConfigBasicAuth.golden
index 15f52dea43c..d5d3bd80d5e 100644
--- a/pkg/prometheus/testdata/ConsulScrapeConfigBasicAuth.golden
+++ b/pkg/prometheus/testdata/ConsulScrapeConfigBasicAuth.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ConsulScrapeConfigOAuth.golden b/pkg/prometheus/testdata/ConsulScrapeConfigOAuth.golden
index 08be2ffe278..e5ee617d97a 100644
--- a/pkg/prometheus/testdata/ConsulScrapeConfigOAuth.golden
+++ b/pkg/prometheus/testdata/ConsulScrapeConfigOAuth.golden
@@ -22,3 +22,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ConsulScrapeConfigTLSConfig.golden b/pkg/prometheus/testdata/ConsulScrapeConfigTLSConfig.golden
index f77cb3a5bc6..7dd5b4de5df 100644
--- a/pkg/prometheus/testdata/ConsulScrapeConfigTLSConfig.golden
+++ b/pkg/prometheus/testdata/ConsulScrapeConfigTLSConfig.golden
@@ -16,3 +16,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ConsulScrapeConfigWithHealthFilter.golden b/pkg/prometheus/testdata/ConsulScrapeConfigWithHealthFilter.golden
index 57a6ef48559..13f87a08d8d 100644
--- a/pkg/prometheus/testdata/ConsulScrapeConfigWithHealthFilter.golden
+++ b/pkg/prometheus/testdata/ConsulScrapeConfigWithHealthFilter.golden
@@ -13,3 +13,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/EmptyEndpointPorts.golden b/pkg/prometheus/testdata/EmptyEndpointPorts.golden
index d72c2bdcfd7..d2ca0bc6be2 100644
--- a/pkg/prometheus/testdata/EmptyEndpointPorts.golden
+++ b/pkg/prometheus/testdata/EmptyEndpointPorts.golden
@@ -72,3 +72,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/EnforcedNamespaceLabelOnExcludedPodMonitor_Expected.golden b/pkg/prometheus/testdata/EnforcedNamespaceLabelOnExcludedPodMonitor_Expected.golden
index 8cd2556540a..11c0ee3792c 100644
--- a/pkg/prometheus/testdata/EnforcedNamespaceLabelOnExcludedPodMonitor_Expected.golden
+++ b/pkg/prometheus/testdata/EnforcedNamespaceLabelOnExcludedPodMonitor_Expected.golden
@@ -77,3 +77,7 @@ scrape_configs:
target_label: my-ns
regex: my-job-pod-.+
action: drop
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/EnforcedNamespaceLabelOnExcludedServiceMonitor_Expected.golden b/pkg/prometheus/testdata/EnforcedNamespaceLabelOnExcludedServiceMonitor_Expected.golden
index 2071aa0d10a..ee22b281053 100644
--- a/pkg/prometheus/testdata/EnforcedNamespaceLabelOnExcludedServiceMonitor_Expected.golden
+++ b/pkg/prometheus/testdata/EnforcedNamespaceLabelOnExcludedServiceMonitor_Expected.golden
@@ -91,3 +91,7 @@ scrape_configs:
target_label: ns-key
regex: my-job-pod-.+
action: drop
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/EnforcedNamespaceLabelPodMonitor_Expected.golden b/pkg/prometheus/testdata/EnforcedNamespaceLabelPodMonitor_Expected.golden
index 411c04bf7ae..fc8302bf0a5 100644
--- a/pkg/prometheus/testdata/EnforcedNamespaceLabelPodMonitor_Expected.golden
+++ b/pkg/prometheus/testdata/EnforcedNamespaceLabelPodMonitor_Expected.golden
@@ -81,3 +81,7 @@ scrape_configs:
action: drop
- target_label: ns-key
replacement: pod-monitor-ns
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/EnforcedNamespaceLabelServiceMonitor_Expected.golden b/pkg/prometheus/testdata/EnforcedNamespaceLabelServiceMonitor_Expected.golden
index 64c78c24c77..da2272f64b5 100644
--- a/pkg/prometheus/testdata/EnforcedNamespaceLabelServiceMonitor_Expected.golden
+++ b/pkg/prometheus/testdata/EnforcedNamespaceLabelServiceMonitor_Expected.golden
@@ -100,3 +100,7 @@ scrape_configs:
action: drop
- target_label: ns-key
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/GenerateRelabelConfig.golden b/pkg/prometheus/testdata/GenerateRelabelConfig.golden
index 50668fd63ed..7187bf76296 100644
--- a/pkg/prometheus/testdata/GenerateRelabelConfig.golden
+++ b/pkg/prometheus/testdata/GenerateRelabelConfig.golden
@@ -103,3 +103,7 @@ scrape_configs:
- target_label: job
replacement: ""
action: replace
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/HonorLabelsOverriding.golden b/pkg/prometheus/testdata/HonorLabelsOverriding.golden
index 45412c73940..7b34835eb7c 100644
--- a/pkg/prometheus/testdata/HonorLabelsOverriding.golden
+++ b/pkg/prometheus/testdata/HonorLabelsOverriding.golden
@@ -84,3 +84,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/HonorTimestampsOverriding.golden b/pkg/prometheus/testdata/HonorTimestampsOverriding.golden
index 9fafc9c1e4f..ccf70ff9f44 100644
--- a/pkg/prometheus/testdata/HonorTimestampsOverriding.golden
+++ b/pkg/prometheus/testdata/HonorTimestampsOverriding.golden
@@ -85,3 +85,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/MatchExpressionsServiceMonitor.golden b/pkg/prometheus/testdata/MatchExpressionsServiceMonitor.golden
index c49ab9d2f30..4f440aad8bb 100644
--- a/pkg/prometheus/testdata/MatchExpressionsServiceMonitor.golden
+++ b/pkg/prometheus/testdata/MatchExpressionsServiceMonitor.golden
@@ -79,3 +79,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/NoEnforcedNamespaceLabelServiceMonitor_Expected.golden b/pkg/prometheus/testdata/NoEnforcedNamespaceLabelServiceMonitor_Expected.golden
index d8b9e365c61..fdfb3c655fb 100644
--- a/pkg/prometheus/testdata/NoEnforcedNamespaceLabelServiceMonitor_Expected.golden
+++ b/pkg/prometheus/testdata/NoEnforcedNamespaceLabelServiceMonitor_Expected.golden
@@ -93,3 +93,7 @@ scrape_configs:
- __name__
regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s)
action: drop
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/OTLPConfig_Config_label_name_preserve_multiple_underscores.golden b/pkg/prometheus/testdata/OTLPConfig_Config_label_name_preserve_multiple_underscores.golden
new file mode 100644
index 00000000000..3b069354417
--- /dev/null
+++ b/pkg/prometheus/testdata/OTLPConfig_Config_label_name_preserve_multiple_underscores.golden
@@ -0,0 +1,9 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ evaluation_interval: 30s
+scrape_configs: []
+otlp:
+ label_name_preserve_multiple_underscores: false
diff --git a/pkg/prometheus/testdata/OTLPConfig_Config_label_name_preserve_multiple_underscores_wrong_version.golden b/pkg/prometheus/testdata/OTLPConfig_Config_label_name_preserve_multiple_underscores_wrong_version.golden
new file mode 100644
index 00000000000..609303fe82c
--- /dev/null
+++ b/pkg/prometheus/testdata/OTLPConfig_Config_label_name_preserve_multiple_underscores_wrong_version.golden
@@ -0,0 +1,7 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ evaluation_interval: 30s
+scrape_configs: []
diff --git a/pkg/prometheus/testdata/OTLPConfig_Config_label_name_underscore_sanitization.golden b/pkg/prometheus/testdata/OTLPConfig_Config_label_name_underscore_sanitization.golden
new file mode 100644
index 00000000000..6b3960974f9
--- /dev/null
+++ b/pkg/prometheus/testdata/OTLPConfig_Config_label_name_underscore_sanitization.golden
@@ -0,0 +1,9 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ evaluation_interval: 30s
+scrape_configs: []
+otlp:
+ label_name_underscore_sanitization: true
diff --git a/pkg/prometheus/testdata/OTLPConfig_Config_label_name_underscore_sanitization_wrong_version.golden b/pkg/prometheus/testdata/OTLPConfig_Config_label_name_underscore_sanitization_wrong_version.golden
new file mode 100644
index 00000000000..609303fe82c
--- /dev/null
+++ b/pkg/prometheus/testdata/OTLPConfig_Config_label_name_underscore_sanitization_wrong_version.golden
@@ -0,0 +1,7 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ evaluation_interval: 30s
+scrape_configs: []
diff --git a/pkg/prometheus/testdata/PodMonitorObjectWithEndpointSliceSelectorAndMatchLabelSelector.golden b/pkg/prometheus/testdata/PodMonitorObjectWithEndpointSliceSelectorAndMatchLabelSelector.golden
index 9bc6760432f..d3022ecd276 100644
--- a/pkg/prometheus/testdata/PodMonitorObjectWithEndpointSliceSelectorAndMatchLabelSelector.golden
+++ b/pkg/prometheus/testdata/PodMonitorObjectWithEndpointSliceSelectorAndMatchLabelSelector.golden
@@ -58,3 +58,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/PodMonitorObjectWithMatchExpressionSelector.golden b/pkg/prometheus/testdata/PodMonitorObjectWithMatchExpressionSelector.golden
index 6de3adf1e84..f433970d534 100644
--- a/pkg/prometheus/testdata/PodMonitorObjectWithMatchExpressionSelector.golden
+++ b/pkg/prometheus/testdata/PodMonitorObjectWithMatchExpressionSelector.golden
@@ -58,3 +58,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/PodMonitorObjectWithMatchLabelSelector.golden b/pkg/prometheus/testdata/PodMonitorObjectWithMatchLabelSelector.golden
index 9bc6760432f..d3022ecd276 100644
--- a/pkg/prometheus/testdata/PodMonitorObjectWithMatchLabelSelector.golden
+++ b/pkg/prometheus/testdata/PodMonitorObjectWithMatchLabelSelector.golden
@@ -58,3 +58,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/PodMonitorObjectWithSelectorAndMatchExpressionSelector.golden b/pkg/prometheus/testdata/PodMonitorObjectWithSelectorAndMatchExpressionSelector.golden
index 81d0f199c73..7e9a6e30d54 100644
--- a/pkg/prometheus/testdata/PodMonitorObjectWithSelectorAndMatchExpressionSelector.golden
+++ b/pkg/prometheus/testdata/PodMonitorObjectWithSelectorAndMatchExpressionSelector.golden
@@ -58,3 +58,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/PodMonitorPhaseFilter.golden b/pkg/prometheus/testdata/PodMonitorPhaseFilter.golden
index 9fe2b779391..f73ddc61f32 100644
--- a/pkg/prometheus/testdata/PodMonitorPhaseFilter.golden
+++ b/pkg/prometheus/testdata/PodMonitorPhaseFilter.golden
@@ -50,3 +50,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/PodTargetLabels.golden b/pkg/prometheus/testdata/PodTargetLabels.golden
index 98ce68e9d67..52b60f891c4 100644
--- a/pkg/prometheus/testdata/PodTargetLabels.golden
+++ b/pkg/prometheus/testdata/PodTargetLabels.golden
@@ -84,3 +84,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/PodTargetLabelsFromPodMonitor.golden b/pkg/prometheus/testdata/PodTargetLabelsFromPodMonitor.golden
index 5599d10d628..837478b3055 100644
--- a/pkg/prometheus/testdata/PodTargetLabelsFromPodMonitor.golden
+++ b/pkg/prometheus/testdata/PodTargetLabelsFromPodMonitor.golden
@@ -65,3 +65,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/PodTargetLabelsFromPodMonitorAndGlobal.golden b/pkg/prometheus/testdata/PodTargetLabelsFromPodMonitorAndGlobal.golden
index faa39312490..c62330ee046 100644
--- a/pkg/prometheus/testdata/PodTargetLabelsFromPodMonitorAndGlobal.golden
+++ b/pkg/prometheus/testdata/PodTargetLabelsFromPodMonitorAndGlobal.golden
@@ -65,3 +65,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeIngressSDConfigGeneration.golden b/pkg/prometheus/testdata/ProbeIngressSDConfigGeneration.golden
index 0128f65e40b..23bf9f9ec17 100644
--- a/pkg/prometheus/testdata/ProbeIngressSDConfigGeneration.golden
+++ b/pkg/prometheus/testdata/ProbeIngressSDConfigGeneration.golden
@@ -70,3 +70,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeIngressSDConfigGenerationWithLabelEnforce.golden b/pkg/prometheus/testdata/ProbeIngressSDConfigGenerationWithLabelEnforce.golden
index 7947808e97c..bf3caf8f0c9 100644
--- a/pkg/prometheus/testdata/ProbeIngressSDConfigGenerationWithLabelEnforce.golden
+++ b/pkg/prometheus/testdata/ProbeIngressSDConfigGenerationWithLabelEnforce.golden
@@ -75,3 +75,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeIngressSDConfigGenerationWithShards.golden b/pkg/prometheus/testdata/ProbeIngressSDConfigGenerationWithShards.golden
index d9f60611b54..58c10313e7b 100644
--- a/pkg/prometheus/testdata/ProbeIngressSDConfigGenerationWithShards.golden
+++ b/pkg/prometheus/testdata/ProbeIngressSDConfigGenerationWithShards.golden
@@ -70,3 +70,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeSpecConfig_empty_probe.golden b/pkg/prometheus/testdata/ProbeSpecConfig_empty_probe.golden
index 5820e6cfb87..0c8851c19ac 100644
--- a/pkg/prometheus/testdata/ProbeSpecConfig_empty_probe.golden
+++ b/pkg/prometheus/testdata/ProbeSpecConfig_empty_probe.golden
@@ -29,3 +29,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeSpecConfig_module_config.golden b/pkg/prometheus/testdata/ProbeSpecConfig_module_config.golden
index 7f1a966cd30..47eae6b8232 100644
--- a/pkg/prometheus/testdata/ProbeSpecConfig_module_config.golden
+++ b/pkg/prometheus/testdata/ProbeSpecConfig_module_config.golden
@@ -32,3 +32,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeSpecConfig_module_config_with_params.golden b/pkg/prometheus/testdata/ProbeSpecConfig_module_config_with_params.golden
index a4ca8d56e57..2e0f7d347c6 100644
--- a/pkg/prometheus/testdata/ProbeSpecConfig_module_config_with_params.golden
+++ b/pkg/prometheus/testdata/ProbeSpecConfig_module_config_with_params.golden
@@ -34,3 +34,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeSpecConfig_module_config_with_params_define_module_in_param.golden b/pkg/prometheus/testdata/ProbeSpecConfig_module_config_with_params_define_module_in_param.golden
index 3ef6d51a9c7..9912658a4fe 100644
--- a/pkg/prometheus/testdata/ProbeSpecConfig_module_config_with_params_define_module_in_param.golden
+++ b/pkg/prometheus/testdata/ProbeSpecConfig_module_config_with_params_define_module_in_param.golden
@@ -34,3 +34,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeSpecConfig_module_config_with_params_skip_module.golden b/pkg/prometheus/testdata/ProbeSpecConfig_module_config_with_params_skip_module.golden
index a4ca8d56e57..2e0f7d347c6 100644
--- a/pkg/prometheus/testdata/ProbeSpecConfig_module_config_with_params_skip_module.golden
+++ b/pkg/prometheus/testdata/ProbeSpecConfig_module_config_with_params_skip_module.golden
@@ -34,3 +34,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeSpecConfig_prober_spec.golden b/pkg/prometheus/testdata/ProbeSpecConfig_prober_spec.golden
index 3d605306605..35ef7dd0bd0 100644
--- a/pkg/prometheus/testdata/ProbeSpecConfig_prober_spec.golden
+++ b/pkg/prometheus/testdata/ProbeSpecConfig_prober_spec.golden
@@ -36,3 +36,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeSpecConfig_targets_static_config.golden b/pkg/prometheus/testdata/ProbeSpecConfig_targets_static_config.golden
index f54b046760b..23b506e46e1 100644
--- a/pkg/prometheus/testdata/ProbeSpecConfig_targets_static_config.golden
+++ b/pkg/prometheus/testdata/ProbeSpecConfig_targets_static_config.golden
@@ -50,3 +50,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeStaticTargetsConfigGenerationWithJobName.golden b/pkg/prometheus/testdata/ProbeStaticTargetsConfigGenerationWithJobName.golden
index 28044942005..c604ce858fd 100644
--- a/pkg/prometheus/testdata/ProbeStaticTargetsConfigGenerationWithJobName.golden
+++ b/pkg/prometheus/testdata/ProbeStaticTargetsConfigGenerationWithJobName.golden
@@ -49,3 +49,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeStaticTargetsConfigGenerationWithLabelEnforce.golden b/pkg/prometheus/testdata/ProbeStaticTargetsConfigGenerationWithLabelEnforce.golden
index c6f7b6a8306..934479ed49c 100644
--- a/pkg/prometheus/testdata/ProbeStaticTargetsConfigGenerationWithLabelEnforce.golden
+++ b/pkg/prometheus/testdata/ProbeStaticTargetsConfigGenerationWithLabelEnforce.golden
@@ -55,3 +55,7 @@ scrape_configs:
action: labeldrop
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeStaticTargetsConfigGenerationWithoutModule.golden b/pkg/prometheus/testdata/ProbeStaticTargetsConfigGenerationWithoutModule.golden
index f04fe6ddc32..ba3bf06e14c 100644
--- a/pkg/prometheus/testdata/ProbeStaticTargetsConfigGenerationWithoutModule.golden
+++ b/pkg/prometheus/testdata/ProbeStaticTargetsConfigGenerationWithoutModule.golden
@@ -46,3 +46,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeWithDefaultScrapeClassAuthz.golden b/pkg/prometheus/testdata/ProbeWithDefaultScrapeClassAuthz.golden
index 93bbc2a069b..c65edf28951 100644
--- a/pkg/prometheus/testdata/ProbeWithDefaultScrapeClassAuthz.golden
+++ b/pkg/prometheus/testdata/ProbeWithDefaultScrapeClassAuthz.golden
@@ -58,3 +58,7 @@ scrape_configs:
action: labeldrop
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeWithHttp2Disabled.golden b/pkg/prometheus/testdata/ProbeWithHttp2Disabled.golden
index 035c9f646f8..da5e77ed6df 100644
--- a/pkg/prometheus/testdata/ProbeWithHttp2Disabled.golden
+++ b/pkg/prometheus/testdata/ProbeWithHttp2Disabled.golden
@@ -56,3 +56,7 @@ scrape_configs:
action: labeldrop
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeWithNonDefaultScrapeClassAuthz.golden b/pkg/prometheus/testdata/ProbeWithNonDefaultScrapeClassAuthz.golden
index 98246e18c1f..bdd70254b09 100644
--- a/pkg/prometheus/testdata/ProbeWithNonDefaultScrapeClassAuthz.golden
+++ b/pkg/prometheus/testdata/ProbeWithNonDefaultScrapeClassAuthz.golden
@@ -58,3 +58,7 @@ scrape_configs:
action: labeldrop
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ProbeWithNonDefaultScrapeClassUserDefinedAuthz.golden b/pkg/prometheus/testdata/ProbeWithNonDefaultScrapeClassUserDefinedAuthz.golden
index 4e1e8efba8e..c0e4720a720 100644
--- a/pkg/prometheus/testdata/ProbeWithNonDefaultScrapeClassUserDefinedAuthz.golden
+++ b/pkg/prometheus/testdata/ProbeWithNonDefaultScrapeClassUserDefinedAuthz.golden
@@ -58,3 +58,7 @@ scrape_configs:
action: labeldrop
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/PrometheusAgent_TSDB_StaleSeriesCompactionThreshold_greater_than_or_equal_to_v3.10.0.golden b/pkg/prometheus/testdata/PrometheusAgent_TSDB_StaleSeriesCompactionThreshold_greater_than_or_equal_to_v3.10.0.golden
new file mode 100644
index 00000000000..4af6e5cafca
--- /dev/null
+++ b/pkg/prometheus/testdata/PrometheusAgent_TSDB_StaleSeriesCompactionThreshold_greater_than_or_equal_to_v3.10.0.golden
@@ -0,0 +1,9 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+scrape_configs: []
+storage:
+ tsdb:
+ stale_series_compaction_threshold: 1
diff --git a/pkg/prometheus/testdata/PrometheusAgent_TSDB_StaleSeriesCompactionThreshold_less_than_v3.10.0.golden b/pkg/prometheus/testdata/PrometheusAgent_TSDB_StaleSeriesCompactionThreshold_less_than_v3.10.0.golden
new file mode 100644
index 00000000000..8d09a4dc239
--- /dev/null
+++ b/pkg/prometheus/testdata/PrometheusAgent_TSDB_StaleSeriesCompactionThreshold_less_than_v3.10.0.golden
@@ -0,0 +1,6 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+scrape_configs: []
diff --git a/pkg/prometheus/testdata/RemoteWriteConfigWithEmptyMetadataConfig.golden b/pkg/prometheus/testdata/RemoteWriteConfigWithEmptyMetadataConfig.golden
index 7a52dfff65b..2ef178f68b9 100644
--- a/pkg/prometheus/testdata/RemoteWriteConfigWithEmptyMetadataConfig.golden
+++ b/pkg/prometheus/testdata/RemoteWriteConfigWithEmptyMetadataConfig.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
remote_write:
- url: http://example.com
metadata_config:
diff --git a/pkg/prometheus/testdata/RemoteWriteConfig_3.11.0.golden b/pkg/prometheus/testdata/RemoteWriteConfig_3.11.0.golden
index 51e81776f84..e87dd0360f6 100644
--- a/pkg/prometheus/testdata/RemoteWriteConfig_3.11.0.golden
+++ b/pkg/prometheus/testdata/RemoteWriteConfig_3.11.0.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
remote_write:
- url: http://example.com
sigv4:
diff --git a/pkg/prometheus/testdata/RetentionConfigFile_default_v3.11.0.golden b/pkg/prometheus/testdata/RetentionConfigFile_default_v3.11.0.golden
new file mode 100644
index 00000000000..ecbee05becb
--- /dev/null
+++ b/pkg/prometheus/testdata/RetentionConfigFile_default_v3.11.0.golden
@@ -0,0 +1,11 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ evaluation_interval: 30s
+scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/RetentionConfigFile_size_v3.11.0.golden b/pkg/prometheus/testdata/RetentionConfigFile_size_v3.11.0.golden
new file mode 100644
index 00000000000..2f94c8d30f9
--- /dev/null
+++ b/pkg/prometheus/testdata/RetentionConfigFile_size_v3.11.0.golden
@@ -0,0 +1,11 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ evaluation_interval: 30s
+scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ size: 512MB
diff --git a/pkg/prometheus/testdata/RetentionConfigFile_time_size_v3.11.0.golden b/pkg/prometheus/testdata/RetentionConfigFile_time_size_v3.11.0.golden
new file mode 100644
index 00000000000..174d84eff53
--- /dev/null
+++ b/pkg/prometheus/testdata/RetentionConfigFile_time_size_v3.11.0.golden
@@ -0,0 +1,12 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ evaluation_interval: 30s
+scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 2d
+ size: 512MB
diff --git a/pkg/prometheus/testdata/RetentionConfigFile_time_v3.11.0.golden b/pkg/prometheus/testdata/RetentionConfigFile_time_v3.11.0.golden
new file mode 100644
index 00000000000..0e874517803
--- /dev/null
+++ b/pkg/prometheus/testdata/RetentionConfigFile_time_v3.11.0.golden
@@ -0,0 +1,11 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ evaluation_interval: 30s
+scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 2d
diff --git a/pkg/prometheus/testdata/RetentionConfigFile_v3.10.0.golden b/pkg/prometheus/testdata/RetentionConfigFile_v3.10.0.golden
new file mode 100644
index 00000000000..609303fe82c
--- /dev/null
+++ b/pkg/prometheus/testdata/RetentionConfigFile_v3.10.0.golden
@@ -0,0 +1,7 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ evaluation_interval: 30s
+scrape_configs: []
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Already_Sharded.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Already_Sharded.golden
index 5e2ceb4e9f9..26e09445d60 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Already_Sharded.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Already_Sharded.golden
@@ -25,3 +25,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Authorization.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Authorization.golden
index 1f03f84f628..c0a9df8f97b 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Authorization.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Authorization.golden
@@ -18,3 +18,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigEmpty.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigEmpty.golden
index 26f7d0393d5..2f125e0578d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigEmpty.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigEmpty.golden
@@ -10,3 +10,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid.golden
index 5d1a39f1881..95b4fb2cc59 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid.golden
@@ -20,3 +20,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValidWithSubscriptionID.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValidWithSubscriptionID.golden
index 640c45ce422..df193d8e04d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValidWithSubscriptionID.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValidWithSubscriptionID.golden
@@ -13,3 +13,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_ManagedIdentityAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_ManagedIdentityAuth.golden
index 4518a3f498d..079ba5c6ff5 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_ManagedIdentityAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_ManagedIdentityAuth.golden
@@ -14,3 +14,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_SDKAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_SDKAuth.golden
index 06bf2148fae..9172ca35b63 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_SDKAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_SDKAuth.golden
@@ -17,3 +17,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_WorkloadIdentityAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_WorkloadIdentityAuth.golden
index c47078a44d9..873949db029 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_WorkloadIdentityAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_WorkloadIdentityAuth.golden
@@ -14,3 +14,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_basic_auth_and_TLS.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_basic_auth_and_TLS.golden
index a6ffdb8b8a9..2fbf7643d4f 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_basic_auth_and_TLS.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_basic_auth_and_TLS.golden
@@ -16,3 +16,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_http_config.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_http_config.golden
index ce3d6475933..9752b42b4cb 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_http_config.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_http_config.golden
@@ -22,3 +22,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_with_oauth2.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_with_oauth2.golden
index 0cfb25cf58b..b706ef3d6be 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_with_oauth2.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_AzureSDConfigValid_with_oauth2.golden
@@ -23,3 +23,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_BasicAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_BasicAuth.golden
index b5b8b461174..9e6dd563d6b 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_BasicAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_BasicAuth.golden
@@ -18,3 +18,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DNSSD_ARecord.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DNSSD_ARecord.golden
index ab81b616701..46eb43c0303 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DNSSD_ARecord.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DNSSD_ARecord.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DNSSD_SRVRecord.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DNSSD_SRVRecord.golden
index ce4cd35260f..0cb1bdecdf7 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DNSSD_SRVRecord.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DNSSD_SRVRecord.golden
@@ -13,3 +13,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerSDConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerSDConfig.golden
index 644b1eac252..4e50779b12e 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerSDConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerSDConfig.golden
@@ -42,3 +42,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerSD_with_BasicAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerSD_with_BasicAuth.golden
index 8a5afc63a81..10ef7770b29 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerSD_with_BasicAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerSD_with_BasicAuth.golden
@@ -27,3 +27,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerSD_with_OAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerSD_with_OAuth.golden
index b649c3d6117..655d2a14557 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerSD_with_OAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerSD_with_OAuth.golden
@@ -34,3 +34,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD.golden
index 4432ed511bf..8a077334d9f 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD.golden
@@ -29,3 +29,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD_withBasicAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD_withBasicAuth.golden
index 5658b54ae60..d276626aec4 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD_withBasicAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD_withBasicAuth.golden
@@ -25,3 +25,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD_with_OAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD_with_OAuth.golden
index 2a47da398e3..fd701ae6067 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD_with_OAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD_with_OAuth.golden
@@ -23,3 +23,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD_with_TLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD_with_TLSConfig.golden
index de7060bf0f7..47c7b914662 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD_with_TLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_DockerswarmSD_with_TLSConfig.golden
@@ -20,3 +20,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SDConfigEmpty.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SDConfigEmpty.golden
index 26f7d0393d5..2f125e0578d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SDConfigEmpty.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SDConfigEmpty.golden
@@ -10,3 +10,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SDConfigValidAPIKeys.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SDConfigValidAPIKeys.golden
index 10a93e77ead..1f33ebf2633 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SDConfigValidAPIKeys.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SDConfigValidAPIKeys.golden
@@ -16,3 +16,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SDConfigValidRoleARN.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SDConfigValidRoleARN.golden
index d99c8181c49..bd61c8ed982 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SDConfigValidRoleARN.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SDConfigValidRoleARN.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SD_withProxyConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SD_withProxyConfig.golden
index 0cad0368088..1f1bf2924e1 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SD_withProxyConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EC2SD_withProxyConfig.golden
@@ -21,3 +21,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Empty.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Empty.golden
index 26f7d0393d5..2f125e0578d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Empty.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Empty.golden
@@ -10,3 +10,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EmptyRelabelConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EmptyRelabelConfig.golden
index 26f7d0393d5..2f125e0578d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EmptyRelabelConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EmptyRelabelConfig.golden
@@ -10,3 +10,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EnableCompression_False.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EnableCompression_False.golden
index f0832062bf0..376676488b7 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EnableCompression_False.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EnableCompression_False.golden
@@ -11,3 +11,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EnableCompression_True.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EnableCompression_True.golden
index 9a6e4ca2216..180480c5c21 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EnableCompression_True.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EnableCompression_True.golden
@@ -11,3 +11,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EurekaSD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EurekaSD.golden
index fa135104910..05f8e951137 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EurekaSD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EurekaSD.golden
@@ -24,3 +24,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EurekaSD_with_OAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EurekaSD_with_OAuth.golden
index 01ac16c3a98..040fe083651 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EurekaSD_with_OAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EurekaSD_with_OAuth.golden
@@ -22,3 +22,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EurekaSD_with_TLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EurekaSD_with_TLSConfig.golden
index 5d020652298..23990956457 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EurekaSD_with_TLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_EurekaSD_with_TLSConfig.golden
@@ -19,3 +19,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_FileSD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_FileSD.golden
index 17904aaac4c..cd81be12b80 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_FileSD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_FileSD.golden
@@ -14,3 +14,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigEmpty.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigEmpty.golden
index 26f7d0393d5..2f125e0578d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigEmpty.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigEmpty.golden
@@ -10,3 +10,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigValid.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigValid.golden
index d79b0337ab6..7a642915dba 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigValid.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigValid.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigValidRequiredFields.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigValidRequiredFields.golden
index df10775dc45..fa63627c653 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigValidRequiredFields.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigValidRequiredFields.golden
@@ -13,3 +13,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigValid_all_options.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigValid_all_options.golden
index 8ffdd32724d..8af1bfbec76 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigValid_all_options.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_GCESDConfigValid_all_options.golden
@@ -17,3 +17,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD.golden
index 6b9d5fc7b41..190c77bf33e 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD.golden
@@ -19,3 +19,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_Authorization.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_Authorization.golden
index 8de183ba163..3c8e201a852 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_Authorization.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_Authorization.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_BasicAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_BasicAuth.golden
index 7d6e89826b7..ce791bc4f04 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_BasicAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_BasicAuth.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_OAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_OAuth.golden
index e995fcfafed..321bc25aea6 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_OAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_OAuth.golden
@@ -22,3 +22,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_ProxyConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_ProxyConfig.golden
index 47b68e3757c..f7306c773c9 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_ProxyConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_ProxyConfig.golden
@@ -20,3 +20,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_TLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_TLSConfig.golden
index d3a9ce0de49..2f2a851e708 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_TLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HTTPSD_with_TLSConfig.golden
@@ -16,3 +16,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD.golden
index 77e3a32c559..36ddf75ad92 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD.golden
@@ -22,3 +22,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_Authorization.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_Authorization.golden
index e676eef99cf..e86b3496ade 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_Authorization.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_Authorization.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_BasicAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_BasicAuth.golden
index cba312ce96e..d0c0c9059cd 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_BasicAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_BasicAuth.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_OAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_OAuth.golden
index 1e3ece018f6..2c48f6189a4 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_OAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_OAuth.golden
@@ -22,3 +22,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_TLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_TLSConfig.golden
index e6e7b5cd506..3287b472d5c 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_TLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HetznerSD_with_TLSConfig.golden
@@ -16,3 +16,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HonorLabels.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HonorLabels.golden
index 33a168b8b4a..93c7c0773da 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HonorLabels.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HonorLabels.golden
@@ -11,3 +11,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HonorTimeStamp.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HonorTimeStamp.golden
index 7ecef16e064..1cf534f5133 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HonorTimeStamp.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_HonorTimeStamp.golden
@@ -11,3 +11,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Inline_TLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Inline_TLSConfig.golden
index bba3f094af6..e5698c169d4 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Inline_TLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Inline_TLSConfig.golden
@@ -19,3 +19,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_IonosSD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_IonosSD.golden
index 2be8df4ad0f..80ca4ae0d17 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_IonosSD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_IonosSD.golden
@@ -25,3 +25,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_IonosSD_withOAuth2.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_IonosSD_withOAuth2.golden
index 56fde14b399..445723e0b63 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_IonosSD_withOAuth2.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_IonosSD_withOAuth2.golden
@@ -22,3 +22,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_IonosSD_withTLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_IonosSD_withTLSConfig.golden
index 192e78c03af..199b4277a05 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_IonosSD_withTLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_IonosSD_withTLSConfig.golden
@@ -19,3 +19,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD.golden
index 77a4c1ee60f..6e3a40d35be 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD.golden
@@ -21,3 +21,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_AttachMetadata.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_AttachMetadata.golden
index 1e15788aade..cc24d08bb92 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_AttachMetadata.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_AttachMetadata.golden
@@ -14,3 +14,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_Authorization.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_Authorization.golden
index 8a016db2d42..849fea5166d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_Authorization.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_Authorization.golden
@@ -16,3 +16,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_BasicAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_BasicAuth.golden
index d42fbdb4cf7..7ecffc2dd08 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_BasicAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_BasicAuth.golden
@@ -16,3 +16,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_NamespaceDiscovery.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_NamespaceDiscovery.golden
index 4331a09f127..d5cf0353693 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_NamespaceDiscovery.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_NamespaceDiscovery.golden
@@ -16,3 +16,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_NamespaceDiscovery_and_OwnNamespace.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_NamespaceDiscovery_and_OwnNamespace.golden
index 5e639b218eb..ece452c1df1 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_NamespaceDiscovery_and_OwnNamespace.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_NamespaceDiscovery_and_OwnNamespace.golden
@@ -17,3 +17,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_OAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_OAuth.golden
index f7b6e0ce107..4ba671cb8d2 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_OAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_OAuth.golden
@@ -23,3 +23,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_TLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_TLSConfig.golden
index baaaf6702a4..ba0a57d64c6 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_TLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_TLSConfig.golden
@@ -17,3 +17,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_Unsupported_Role_AttachMetadata.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_Unsupported_Role_AttachMetadata.golden
index deea1dd88db..a18f54328c1 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_Unsupported_Role_AttachMetadata.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_K8SSD_with_Unsupported_Role_AttachMetadata.golden
@@ -12,3 +12,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD.golden
index 215866e34a4..9639d967694 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD.golden
@@ -26,3 +26,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD_with_OAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD_with_OAuth.golden
index 523b61fa691..f48a5756f7d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD_with_OAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD_with_OAuth.golden
@@ -22,3 +22,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD_with_TLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD_with_TLSConfig.golden
index 288dc80baeb..3e2e21e51d3 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD_with_TLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD_with_TLSConfig.golden
@@ -19,3 +19,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD_with_TLSConfig_TLSVersion.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD_with_TLSConfig_TLSVersion.golden
index 5c2b7b1496d..83eac8b83c1 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD_with_TLSConfig_TLSVersion.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_KumaSD_with_TLSConfig_TLSVersion.golden
@@ -21,3 +21,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD.golden
index b870fc4fc81..9c5c512462d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD.golden
@@ -25,3 +25,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSDConfigValidAPIKeys.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSDConfigValidAPIKeys.golden
index bd4e9d608ce..454845a55e2 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSDConfigValidAPIKeys.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSDConfigValidAPIKeys.golden
@@ -17,3 +17,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSDConfigValidRoleARN.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSDConfigValidRoleARN.golden
index 75e800181bf..cac600fb394 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSDConfigValidRoleARN.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSDConfigValidRoleARN.golden
@@ -16,3 +16,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD_withBasicAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD_withBasicAuth.golden
index 12c64abcba1..292a8c214f4 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD_withBasicAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD_withBasicAuth.golden
@@ -25,3 +25,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD_with_OAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD_with_OAuth.golden
index 26910363eac..a116fd3dc74 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD_with_OAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD_with_OAuth.golden
@@ -23,3 +23,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD_with_TLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD_with_TLSConfig.golden
index 5f503aa9d1f..0566716f01b 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD_with_TLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LightSailSD_with_TLSConfig.golden
@@ -20,3 +20,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Limits.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Limits.golden
index ab76d5804b4..97a6afc36e6 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Limits.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Limits.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LinodeSDConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LinodeSDConfig.golden
index 776b577ec35..83883f00535 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LinodeSDConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LinodeSDConfig.golden
@@ -29,3 +29,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LinodeSD_with_OAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LinodeSD_with_OAuth.golden
index d880f80f200..dadd4812f0b 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LinodeSD_with_OAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_LinodeSD_with_OAuth.golden
@@ -28,3 +28,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_MetricPath.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_MetricPath.golden
index 5f9f83f4e24..2b4c8412c91 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_MetricPath.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_MetricPath.golden
@@ -11,3 +11,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NomadSD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NomadSD.golden
index 03b44f1e185..850465574d6 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NomadSD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NomadSD.golden
@@ -28,3 +28,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NomadSD_with_OAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NomadSD_with_OAuth.golden
index 68633e5b573..e89abd70bf6 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NomadSD_with_OAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NomadSD_with_OAuth.golden
@@ -22,3 +22,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NomadSD_with_TLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NomadSD_with_TLSConfig.golden
index 8251c1cacb4..b3549dcc13d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NomadSD_with_TLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NomadSD_with_TLSConfig.golden
@@ -19,3 +19,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NonEmptyMetricRelabelConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NonEmptyMetricRelabelConfig.golden
index 789619d38a5..11c13643a62 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NonEmptyMetricRelabelConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NonEmptyMetricRelabelConfig.golden
@@ -13,3 +13,7 @@ scrape_configs:
metric_relabel_configs:
- regex: noisy_labels.*
action: labeldrop
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NonEmptyRelabelConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NonEmptyRelabelConfig.golden
index 5e31cff0893..15d93f4eefd 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NonEmptyRelabelConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_NonEmptyRelabelConfig.golden
@@ -16,3 +16,7 @@ scrape_configs:
regex: (.+)(?::d+)
replacement: $1:9537
action: replace
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_OVHCloudSD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_OVHCloudSD.golden
index f166854c0cc..ea51cc38750 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_OVHCloudSD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_OVHCloudSD.golden
@@ -17,3 +17,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_OpenStackSDConfigEmpty.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_OpenStackSDConfigEmpty.golden
index 26f7d0393d5..2f125e0578d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_OpenStackSDConfigEmpty.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_OpenStackSDConfigEmpty.golden
@@ -10,3 +10,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_OpenStackSDConfigValid.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_OpenStackSDConfigValid.golden
index 2ec8f276bc7..990f3c6e117 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_OpenStackSDConfigValid.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_OpenStackSDConfigValid.golden
@@ -19,3 +19,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Params.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Params.golden
index a6de2070ae5..46f2ec31115 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Params.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Params.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ProxySettings.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ProxySettings.golden
index 19bde9d5b97..17abf2138c6 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ProxySettings.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ProxySettings.golden
@@ -16,3 +16,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ProxySettingsWithMutiProxyConnectHeaderValues.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ProxySettingsWithMutiProxyConnectHeaderValues.golden
index 2f037d97168..79f3d3cb692 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ProxySettingsWithMutiProxyConnectHeaderValues.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ProxySettingsWithMutiProxyConnectHeaderValues.golden
@@ -21,3 +21,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD.golden
index fe9160d6b7d..e0426ce3e82 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD.golden
@@ -25,3 +25,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD_withBasicAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD_withBasicAuth.golden
index 437fe6ce43b..5725095f736 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD_withBasicAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD_withBasicAuth.golden
@@ -25,3 +25,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD_with_OAuth.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD_with_OAuth.golden
index 6d8fe1d3c15..99ffeddc9a5 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD_with_OAuth.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD_with_OAuth.golden
@@ -23,3 +23,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD_with_TLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD_with_TLSConfig.golden
index 1bf5394b8d3..862c01689ce 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD_with_TLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_PuppetDBSD_with_TLSConfig.golden
@@ -20,3 +20,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScaleWaySD.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScaleWaySD.golden
index 693a8802a12..3ea9c6b9576 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScaleWaySD.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScaleWaySD.golden
@@ -31,3 +31,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScaleWaySD_with_TLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScaleWaySD_with_TLSConfig.golden
index 7ac66295beb..413a41442b4 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScaleWaySD_with_TLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScaleWaySD_with_TLSConfig.golden
@@ -19,3 +19,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Scheme.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Scheme.golden
index 3c6673658b3..0f61f9d3636 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Scheme.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Scheme.golden
@@ -11,3 +11,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScrapeInterval.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScrapeInterval.golden
index 0fa8cdc0961..0eefa240cd3 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScrapeInterval.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScrapeInterval.golden
@@ -11,3 +11,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScrapeProtocols.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScrapeProtocols.golden
index 7c6caa2d6fe..8b9b19ebe81 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScrapeProtocols.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScrapeProtocols.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScrapeTimeout.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScrapeTimeout.golden
index 4bcb1181311..4c9a202173d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScrapeTimeout.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_ScrapeTimeout.golden
@@ -11,3 +11,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Sharded.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Sharded.golden
index 226bdd466a9..fda91e5b800 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Sharded.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Sharded.golden
@@ -32,3 +32,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Static.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Static.golden
index 1183663a5ff..c07dd614212 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Static.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_Static.golden
@@ -15,3 +15,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_TLSConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_TLSConfig.golden
index 3e0e989960c..277eac1cb0d 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_TLSConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_TLSConfig.golden
@@ -19,3 +19,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_TrackTimestampsStaleness.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_TrackTimestampsStaleness.golden
index f4a4f50fb93..5ad20809839 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_TrackTimestampsStaleness.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_TrackTimestampsStaleness.golden
@@ -11,3 +11,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_WithJobName.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_WithJobName.golden
index d85f2227f59..e409f142569 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_WithJobName.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_WithJobName.golden
@@ -13,3 +13,7 @@ scrape_configs:
- target_label: job
action: replace
replacement: explicit-test-scrape-config3
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_WithJobNameAndRelabelConfig.golden b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_WithJobNameAndRelabelConfig.golden
index 181b8551ff2..ffebb4f7401 100644
--- a/pkg/prometheus/testdata/ScrapeConfigSpecConfig_WithJobNameAndRelabelConfig.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigSpecConfig_WithJobNameAndRelabelConfig.golden
@@ -19,3 +19,7 @@ scrape_configs:
regex: (.+)(?::d+)
replacement: $1:9537
action: replace
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigWithDefaultScrapeClassAuthz.golden b/pkg/prometheus/testdata/ScrapeConfigWithDefaultScrapeClassAuthz.golden
index 23cec0a7f83..c2d166e1c71 100644
--- a/pkg/prometheus/testdata/ScrapeConfigWithDefaultScrapeClassAuthz.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigWithDefaultScrapeClassAuthz.golden
@@ -22,3 +22,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigWithNonDefaultScrapeClassAuthz.golden b/pkg/prometheus/testdata/ScrapeConfigWithNonDefaultScrapeClassAuthz.golden
index f34e221a092..666547f1532 100644
--- a/pkg/prometheus/testdata/ScrapeConfigWithNonDefaultScrapeClassAuthz.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigWithNonDefaultScrapeClassAuthz.golden
@@ -22,3 +22,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ScrapeConfigWithNonDefaultScrapeClassUserDefinedAuthz.golden b/pkg/prometheus/testdata/ScrapeConfigWithNonDefaultScrapeClassUserDefinedAuthz.golden
index d0b22d45389..24e13701ebc 100644
--- a/pkg/prometheus/testdata/ScrapeConfigWithNonDefaultScrapeClassUserDefinedAuthz.golden
+++ b/pkg/prometheus/testdata/ScrapeConfigWithNonDefaultScrapeClassUserDefinedAuthz.golden
@@ -22,3 +22,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ServiceMonitorObjectWithEndpointSliceSelectorAndMatchLabelSelector.golden b/pkg/prometheus/testdata/ServiceMonitorObjectWithEndpointSliceSelectorAndMatchLabelSelector.golden
index 40c89b1011b..9738ad92075 100644
--- a/pkg/prometheus/testdata/ServiceMonitorObjectWithEndpointSliceSelectorAndMatchLabelSelector.golden
+++ b/pkg/prometheus/testdata/ServiceMonitorObjectWithEndpointSliceSelectorAndMatchLabelSelector.golden
@@ -79,3 +79,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ServiceMonitorObjectWithMatchExpressionSelector.golden b/pkg/prometheus/testdata/ServiceMonitorObjectWithMatchExpressionSelector.golden
index 3a5dff05b17..6e78fef2455 100644
--- a/pkg/prometheus/testdata/ServiceMonitorObjectWithMatchExpressionSelector.golden
+++ b/pkg/prometheus/testdata/ServiceMonitorObjectWithMatchExpressionSelector.golden
@@ -79,3 +79,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ServiceMonitorObjectWithMatchLabelSelector.golden b/pkg/prometheus/testdata/ServiceMonitorObjectWithMatchLabelSelector.golden
index 76d4d4ea0c5..493ce7353a7 100644
--- a/pkg/prometheus/testdata/ServiceMonitorObjectWithMatchLabelSelector.golden
+++ b/pkg/prometheus/testdata/ServiceMonitorObjectWithMatchLabelSelector.golden
@@ -79,3 +79,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ServiceMonitorObjectWithSelectorAndMatchExpressionSelector.golden b/pkg/prometheus/testdata/ServiceMonitorObjectWithSelectorAndMatchExpressionSelector.golden
index d4e5a571a2d..d0b33b76010 100644
--- a/pkg/prometheus/testdata/ServiceMonitorObjectWithSelectorAndMatchExpressionSelector.golden
+++ b/pkg/prometheus/testdata/ServiceMonitorObjectWithSelectorAndMatchExpressionSelector.golden
@@ -79,3 +79,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/SettingHonorLabels.golden b/pkg/prometheus/testdata/SettingHonorLabels.golden
index 67a4bc656eb..6fd3d23323b 100644
--- a/pkg/prometheus/testdata/SettingHonorLabels.golden
+++ b/pkg/prometheus/testdata/SettingHonorLabels.golden
@@ -84,3 +84,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/SettingHonorTimestampsInPodMonitor.golden b/pkg/prometheus/testdata/SettingHonorTimestampsInPodMonitor.golden
index a32ff109ea7..b307fd57a1e 100644
--- a/pkg/prometheus/testdata/SettingHonorTimestampsInPodMonitor.golden
+++ b/pkg/prometheus/testdata/SettingHonorTimestampsInPodMonitor.golden
@@ -66,3 +66,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/SettingHonorTimestampsInServiceMonitor.golden b/pkg/prometheus/testdata/SettingHonorTimestampsInServiceMonitor.golden
index 9fafc9c1e4f..ccf70ff9f44 100644
--- a/pkg/prometheus/testdata/SettingHonorTimestampsInServiceMonitor.golden
+++ b/pkg/prometheus/testdata/SettingHonorTimestampsInServiceMonitor.golden
@@ -85,3 +85,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/SettingTrackTimestampsStalenessInPodMonitor.golden b/pkg/prometheus/testdata/SettingTrackTimestampsStalenessInPodMonitor.golden
index bfa701e76f3..0da87b5626a 100644
--- a/pkg/prometheus/testdata/SettingTrackTimestampsStalenessInPodMonitor.golden
+++ b/pkg/prometheus/testdata/SettingTrackTimestampsStalenessInPodMonitor.golden
@@ -66,3 +66,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/SettingTrackTimestampsStalenessInServiceMonitor.golden b/pkg/prometheus/testdata/SettingTrackTimestampsStalenessInServiceMonitor.golden
index f63fd0c31e5..7d41c48d808 100644
--- a/pkg/prometheus/testdata/SettingTrackTimestampsStalenessInServiceMonitor.golden
+++ b/pkg/prometheus/testdata/SettingTrackTimestampsStalenessInServiceMonitor.golden
@@ -85,3 +85,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ShardingRelabelConfigs_with_retention_2_shards.golden b/pkg/prometheus/testdata/ShardingRelabelConfigs_with_retention_2_shards.golden
index ebb4cd0d02d..22913863b41 100644
--- a/pkg/prometheus/testdata/ShardingRelabelConfigs_with_retention_2_shards.golden
+++ b/pkg/prometheus/testdata/ShardingRelabelConfigs_with_retention_2_shards.golden
@@ -86,3 +86,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ShardingRelabelConfigs_with_retention_3_shards.golden b/pkg/prometheus/testdata/ShardingRelabelConfigs_with_retention_3_shards.golden
index a5b7831c477..cacae11b049 100644
--- a/pkg/prometheus/testdata/ShardingRelabelConfigs_with_retention_3_shards.golden
+++ b/pkg/prometheus/testdata/ShardingRelabelConfigs_with_retention_3_shards.golden
@@ -86,3 +86,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/ShardingRelabelConfigs_without_retention.golden b/pkg/prometheus/testdata/ShardingRelabelConfigs_without_retention.golden
index 508e7b457e6..f84cf66c7dc 100644
--- a/pkg/prometheus/testdata/ShardingRelabelConfigs_without_retention.golden
+++ b/pkg/prometheus/testdata/ShardingRelabelConfigs_without_retention.golden
@@ -79,3 +79,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/StorageSettingMaxExemplars_MaxSize5000000.golden b/pkg/prometheus/testdata/StorageSettingMaxExemplars_MaxSize5000000.golden
index e878a48a400..dfdf1044898 100644
--- a/pkg/prometheus/testdata/StorageSettingMaxExemplars_MaxSize5000000.golden
+++ b/pkg/prometheus/testdata/StorageSettingMaxExemplars_MaxSize5000000.golden
@@ -8,3 +8,6 @@ scrape_configs: []
storage:
exemplars:
max_exemplars: 5000000
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/StorageSettingMaxExemplars_MaxSizeNotSetAtAll.golden b/pkg/prometheus/testdata/StorageSettingMaxExemplars_MaxSizeNotSetAtAll.golden
index 609303fe82c..ecbee05becb 100644
--- a/pkg/prometheus/testdata/StorageSettingMaxExemplars_MaxSizeNotSetAtAll.golden
+++ b/pkg/prometheus/testdata/StorageSettingMaxExemplars_MaxSizeNotSetAtAll.golden
@@ -5,3 +5,7 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TSDB_StaleSeriesCompactionThreshold_greater_than_or_equal_to_v3.10.0.golden b/pkg/prometheus/testdata/TSDB_StaleSeriesCompactionThreshold_greater_than_or_equal_to_v3.10.0.golden
new file mode 100644
index 00000000000..70a901212a4
--- /dev/null
+++ b/pkg/prometheus/testdata/TSDB_StaleSeriesCompactionThreshold_greater_than_or_equal_to_v3.10.0.golden
@@ -0,0 +1,10 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ evaluation_interval: 30s
+scrape_configs: []
+storage:
+ tsdb:
+ stale_series_compaction_threshold: 1
diff --git a/pkg/prometheus/testdata/TSDB_StaleSeriesCompactionThreshold_less_than_v3.10.0.golden b/pkg/prometheus/testdata/TSDB_StaleSeriesCompactionThreshold_less_than_v3.10.0.golden
new file mode 100644
index 00000000000..609303fe82c
--- /dev/null
+++ b/pkg/prometheus/testdata/TSDB_StaleSeriesCompactionThreshold_less_than_v3.10.0.golden
@@ -0,0 +1,7 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ evaluation_interval: 30s
+scrape_configs: []
diff --git a/pkg/prometheus/testdata/TSDB_config_greater_than_or_equal_to_v2.39.0.golden b/pkg/prometheus/testdata/TSDB_config_greater_than_or_equal_to_v2.39.0.golden
index 3012c6447e3..6b3e78c6184 100644
--- a/pkg/prometheus/testdata/TSDB_config_greater_than_or_equal_to_v2.39.0.golden
+++ b/pkg/prometheus/testdata/TSDB_config_greater_than_or_equal_to_v2.39.0.golden
@@ -8,3 +8,5 @@ scrape_configs: []
storage:
tsdb:
out_of_order_time_window: 10m
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TargetLabels.golden b/pkg/prometheus/testdata/TargetLabels.golden
index 45412c73940..7b34835eb7c 100644
--- a/pkg/prometheus/testdata/TargetLabels.golden
+++ b/pkg/prometheus/testdata/TargetLabels.golden
@@ -84,3 +84,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TestAdditionalAlertmanagers_Expected.golden b/pkg/prometheus/testdata/TestAdditionalAlertmanagers_Expected.golden
index 85b4341279e..9a11ed6de69 100644
--- a/pkg/prometheus/testdata/TestAdditionalAlertmanagers_Expected.golden
+++ b/pkg/prometheus/testdata/TestAdditionalAlertmanagers_Expected.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
alerting:
alert_relabel_configs:
- action: labeldrop
diff --git a/pkg/prometheus/testdata/TestServiceMonitorWithDefaultServiceDiscoveryRole.golden b/pkg/prometheus/testdata/TestServiceMonitorWithDefaultServiceDiscoveryRole.golden
index 7c9c7822bdb..06c868d7ba8 100644
--- a/pkg/prometheus/testdata/TestServiceMonitorWithDefaultServiceDiscoveryRole.golden
+++ b/pkg/prometheus/testdata/TestServiceMonitorWithDefaultServiceDiscoveryRole.golden
@@ -84,3 +84,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TestServiceMonitorWithEndpointSliceAndPrometheusEndpoints.golden b/pkg/prometheus/testdata/TestServiceMonitorWithEndpointSliceAndPrometheusEndpoints.golden
index 345f1fda9dc..8dc50ec0191 100644
--- a/pkg/prometheus/testdata/TestServiceMonitorWithEndpointSliceAndPrometheusEndpoints.golden
+++ b/pkg/prometheus/testdata/TestServiceMonitorWithEndpointSliceAndPrometheusEndpoints.golden
@@ -84,3 +84,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TestServiceMonitorWithEndpointSliceEnable_Expected.golden b/pkg/prometheus/testdata/TestServiceMonitorWithEndpointSliceEnable_Expected.golden
index 345f1fda9dc..8dc50ec0191 100644
--- a/pkg/prometheus/testdata/TestServiceMonitorWithEndpointSliceEnable_Expected.golden
+++ b/pkg/prometheus/testdata/TestServiceMonitorWithEndpointSliceEnable_Expected.golden
@@ -84,3 +84,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TestServiceMonitorWithEndpointsAndPrometheusEndpointSlice.golden b/pkg/prometheus/testdata/TestServiceMonitorWithEndpointsAndPrometheusEndpointSlice.golden
index 7c9c7822bdb..06c868d7ba8 100644
--- a/pkg/prometheus/testdata/TestServiceMonitorWithEndpointsAndPrometheusEndpointSlice.golden
+++ b/pkg/prometheus/testdata/TestServiceMonitorWithEndpointsAndPrometheusEndpointSlice.golden
@@ -84,3 +84,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TopologySharding_PodMonitor_4shards_2zones.golden b/pkg/prometheus/testdata/TopologySharding_PodMonitor_4shards_2zones.golden
index 9405ce2d18b..627f8489196 100644
--- a/pkg/prometheus/testdata/TopologySharding_PodMonitor_4shards_2zones.golden
+++ b/pkg/prometheus/testdata/TopologySharding_PodMonitor_4shards_2zones.golden
@@ -83,3 +83,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(INZONE_SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TopologySharding_PodTopologyLabels_PodMonitor_4shards_2zones.golden b/pkg/prometheus/testdata/TopologySharding_PodTopologyLabels_PodMonitor_4shards_2zones.golden
new file mode 100644
index 00000000000..20aea46d325
--- /dev/null
+++ b/pkg/prometheus/testdata/TopologySharding_PodTopologyLabels_PodMonitor_4shards_2zones.golden
@@ -0,0 +1,87 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ zone: $(TOPOLOGY_ZONE)
+ evaluation_interval: 30s
+scrape_configs:
+- job_name: podMonitor/default/test/0
+ honor_labels: false
+ kubernetes_sd_configs:
+ - role: pod
+ namespaces:
+ names:
+ - default
+ scrape_interval: 30s
+ relabel_configs:
+ - source_labels:
+ - job
+ target_label: __tmp_prometheus_job_name
+ - action: drop
+ source_labels:
+ - __meta_kubernetes_pod_phase
+ regex: (Failed|Succeeded)
+ - action: keep
+ source_labels:
+ - __meta_kubernetes_pod_label_foo
+ - __meta_kubernetes_pod_labelpresent_foo
+ regex: (bar);true
+ - action: keep
+ source_labels:
+ - __meta_kubernetes_pod_container_port_name
+ regex: web
+ - source_labels:
+ - __meta_kubernetes_namespace
+ target_label: namespace
+ - source_labels:
+ - __meta_kubernetes_pod_container_name
+ target_label: container
+ - source_labels:
+ - __meta_kubernetes_pod_name
+ target_label: pod
+ - target_label: job
+ replacement: default/test
+ - target_label: endpoint
+ replacement: web
+ - source_labels:
+ - __meta_kubernetes_endpointslice_endpoint_zone
+ - __tmp_topology
+ target_label: __tmp_topology
+ regex: (.+);
+ replacement: $1
+ action: replace
+ - source_labels:
+ - __meta_kubernetes_pod_label_topology_kubernetes_io_zone
+ - __meta_kubernetes_pod_labelpresent_topology_kubernetes_io_zone
+ - __tmp_topology
+ target_label: __tmp_topology
+ regex: (.+);true;
+ replacement: $1
+ action: replace
+ - source_labels:
+ - __tmp_topology
+ - __tmp_disable_sharding
+ regex: $(TOPOLOGY_ZONE);|.+;.+
+ action: keep
+ - source_labels:
+ - __address__
+ - __tmp_hash
+ target_label: __tmp_hash
+ regex: (.+);
+ replacement: $1
+ action: replace
+ - source_labels:
+ - __tmp_hash
+ target_label: __tmp_hash
+ modulus: 2
+ action: hashmod
+ - source_labels:
+ - __tmp_hash
+ - __tmp_disable_sharding
+ regex: $(INZONE_SHARD);|.+;.+
+ action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TopologySharding_PodTopologyLabels_ServiceMonitor_4shards_2zones.golden b/pkg/prometheus/testdata/TopologySharding_PodTopologyLabels_ServiceMonitor_4shards_2zones.golden
new file mode 100644
index 00000000000..cc81bdf7bc6
--- /dev/null
+++ b/pkg/prometheus/testdata/TopologySharding_PodTopologyLabels_ServiceMonitor_4shards_2zones.golden
@@ -0,0 +1,106 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ zone: $(TOPOLOGY_ZONE)
+ evaluation_interval: 30s
+scrape_configs:
+- job_name: serviceMonitor/default/test/0
+ honor_labels: false
+ kubernetes_sd_configs:
+ - role: endpoints
+ namespaces:
+ names:
+ - default
+ scrape_interval: 30s
+ relabel_configs:
+ - source_labels:
+ - job
+ target_label: __tmp_prometheus_job_name
+ - action: keep
+ source_labels:
+ - __meta_kubernetes_service_label_foo
+ - __meta_kubernetes_service_labelpresent_foo
+ regex: (bar);true
+ - action: keep
+ source_labels:
+ - __meta_kubernetes_endpoint_port_name
+ regex: web
+ - source_labels:
+ - __meta_kubernetes_endpoint_address_target_kind
+ - __meta_kubernetes_endpoint_address_target_name
+ separator: ;
+ regex: Node;(.*)
+ replacement: ${1}
+ target_label: node
+ - source_labels:
+ - __meta_kubernetes_endpoint_address_target_kind
+ - __meta_kubernetes_endpoint_address_target_name
+ separator: ;
+ regex: Pod;(.*)
+ replacement: ${1}
+ target_label: pod
+ - source_labels:
+ - __meta_kubernetes_namespace
+ target_label: namespace
+ - source_labels:
+ - __meta_kubernetes_service_name
+ target_label: service
+ - source_labels:
+ - __meta_kubernetes_pod_name
+ target_label: pod
+ - source_labels:
+ - __meta_kubernetes_pod_container_name
+ target_label: container
+ - action: drop
+ source_labels:
+ - __meta_kubernetes_pod_phase
+ regex: (Failed|Succeeded)
+ - source_labels:
+ - __meta_kubernetes_service_name
+ target_label: job
+ replacement: ${1}
+ - target_label: endpoint
+ replacement: web
+ - source_labels:
+ - __meta_kubernetes_endpointslice_endpoint_zone
+ - __tmp_topology
+ target_label: __tmp_topology
+ regex: (.+);
+ replacement: $1
+ action: replace
+ - source_labels:
+ - __meta_kubernetes_pod_label_topology_kubernetes_io_zone
+ - __meta_kubernetes_pod_labelpresent_topology_kubernetes_io_zone
+ - __tmp_topology
+ target_label: __tmp_topology
+ regex: (.+);true;
+ replacement: $1
+ action: replace
+ - source_labels:
+ - __tmp_topology
+ - __tmp_disable_sharding
+ regex: $(TOPOLOGY_ZONE);|.+;.+
+ action: keep
+ - source_labels:
+ - __address__
+ - __tmp_hash
+ target_label: __tmp_hash
+ regex: (.+);
+ replacement: $1
+ action: replace
+ - source_labels:
+ - __tmp_hash
+ target_label: __tmp_hash
+ modulus: 2
+ action: hashmod
+ - source_labels:
+ - __tmp_hash
+ - __tmp_disable_sharding
+ regex: $(INZONE_SHARD);|.+;.+
+ action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TopologySharding_PodTopologyLabels_ServiceMonitor_6shards_3zones.golden b/pkg/prometheus/testdata/TopologySharding_PodTopologyLabels_ServiceMonitor_6shards_3zones.golden
new file mode 100644
index 00000000000..cc81bdf7bc6
--- /dev/null
+++ b/pkg/prometheus/testdata/TopologySharding_PodTopologyLabels_ServiceMonitor_6shards_3zones.golden
@@ -0,0 +1,106 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ zone: $(TOPOLOGY_ZONE)
+ evaluation_interval: 30s
+scrape_configs:
+- job_name: serviceMonitor/default/test/0
+ honor_labels: false
+ kubernetes_sd_configs:
+ - role: endpoints
+ namespaces:
+ names:
+ - default
+ scrape_interval: 30s
+ relabel_configs:
+ - source_labels:
+ - job
+ target_label: __tmp_prometheus_job_name
+ - action: keep
+ source_labels:
+ - __meta_kubernetes_service_label_foo
+ - __meta_kubernetes_service_labelpresent_foo
+ regex: (bar);true
+ - action: keep
+ source_labels:
+ - __meta_kubernetes_endpoint_port_name
+ regex: web
+ - source_labels:
+ - __meta_kubernetes_endpoint_address_target_kind
+ - __meta_kubernetes_endpoint_address_target_name
+ separator: ;
+ regex: Node;(.*)
+ replacement: ${1}
+ target_label: node
+ - source_labels:
+ - __meta_kubernetes_endpoint_address_target_kind
+ - __meta_kubernetes_endpoint_address_target_name
+ separator: ;
+ regex: Pod;(.*)
+ replacement: ${1}
+ target_label: pod
+ - source_labels:
+ - __meta_kubernetes_namespace
+ target_label: namespace
+ - source_labels:
+ - __meta_kubernetes_service_name
+ target_label: service
+ - source_labels:
+ - __meta_kubernetes_pod_name
+ target_label: pod
+ - source_labels:
+ - __meta_kubernetes_pod_container_name
+ target_label: container
+ - action: drop
+ source_labels:
+ - __meta_kubernetes_pod_phase
+ regex: (Failed|Succeeded)
+ - source_labels:
+ - __meta_kubernetes_service_name
+ target_label: job
+ replacement: ${1}
+ - target_label: endpoint
+ replacement: web
+ - source_labels:
+ - __meta_kubernetes_endpointslice_endpoint_zone
+ - __tmp_topology
+ target_label: __tmp_topology
+ regex: (.+);
+ replacement: $1
+ action: replace
+ - source_labels:
+ - __meta_kubernetes_pod_label_topology_kubernetes_io_zone
+ - __meta_kubernetes_pod_labelpresent_topology_kubernetes_io_zone
+ - __tmp_topology
+ target_label: __tmp_topology
+ regex: (.+);true;
+ replacement: $1
+ action: replace
+ - source_labels:
+ - __tmp_topology
+ - __tmp_disable_sharding
+ regex: $(TOPOLOGY_ZONE);|.+;.+
+ action: keep
+ - source_labels:
+ - __address__
+ - __tmp_hash
+ target_label: __tmp_hash
+ regex: (.+);
+ replacement: $1
+ action: replace
+ - source_labels:
+ - __tmp_hash
+ target_label: __tmp_hash
+ modulus: 2
+ action: hashmod
+ - source_labels:
+ - __tmp_hash
+ - __tmp_disable_sharding
+ regex: $(INZONE_SHARD);|.+;.+
+ action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TopologySharding_PodTopologyLabels_ServiceMonitor_attach_metadata_false.golden b/pkg/prometheus/testdata/TopologySharding_PodTopologyLabels_ServiceMonitor_attach_metadata_false.golden
new file mode 100644
index 00000000000..d025d58c254
--- /dev/null
+++ b/pkg/prometheus/testdata/TopologySharding_PodTopologyLabels_ServiceMonitor_attach_metadata_false.golden
@@ -0,0 +1,108 @@
+global:
+ scrape_interval: 30s
+ external_labels:
+ prometheus: default/test
+ prometheus_replica: $(POD_NAME)
+ zone: $(TOPOLOGY_ZONE)
+ evaluation_interval: 30s
+scrape_configs:
+- job_name: serviceMonitor/default/test/0
+ honor_labels: false
+ kubernetes_sd_configs:
+ - role: endpoints
+ namespaces:
+ names:
+ - default
+ attach_metadata:
+ node: false
+ scrape_interval: 30s
+ relabel_configs:
+ - source_labels:
+ - job
+ target_label: __tmp_prometheus_job_name
+ - action: keep
+ source_labels:
+ - __meta_kubernetes_service_label_foo
+ - __meta_kubernetes_service_labelpresent_foo
+ regex: (bar);true
+ - action: keep
+ source_labels:
+ - __meta_kubernetes_endpoint_port_name
+ regex: web
+ - source_labels:
+ - __meta_kubernetes_endpoint_address_target_kind
+ - __meta_kubernetes_endpoint_address_target_name
+ separator: ;
+ regex: Node;(.*)
+ replacement: ${1}
+ target_label: node
+ - source_labels:
+ - __meta_kubernetes_endpoint_address_target_kind
+ - __meta_kubernetes_endpoint_address_target_name
+ separator: ;
+ regex: Pod;(.*)
+ replacement: ${1}
+ target_label: pod
+ - source_labels:
+ - __meta_kubernetes_namespace
+ target_label: namespace
+ - source_labels:
+ - __meta_kubernetes_service_name
+ target_label: service
+ - source_labels:
+ - __meta_kubernetes_pod_name
+ target_label: pod
+ - source_labels:
+ - __meta_kubernetes_pod_container_name
+ target_label: container
+ - action: drop
+ source_labels:
+ - __meta_kubernetes_pod_phase
+ regex: (Failed|Succeeded)
+ - source_labels:
+ - __meta_kubernetes_service_name
+ target_label: job
+ replacement: ${1}
+ - target_label: endpoint
+ replacement: web
+ - source_labels:
+ - __meta_kubernetes_endpointslice_endpoint_zone
+ - __tmp_topology
+ target_label: __tmp_topology
+ regex: (.+);
+ replacement: $1
+ action: replace
+ - source_labels:
+ - __meta_kubernetes_pod_label_topology_kubernetes_io_zone
+ - __meta_kubernetes_pod_labelpresent_topology_kubernetes_io_zone
+ - __tmp_topology
+ target_label: __tmp_topology
+ regex: (.+);true;
+ replacement: $1
+ action: replace
+ - source_labels:
+ - __tmp_topology
+ - __tmp_disable_sharding
+ regex: $(TOPOLOGY_ZONE);|.+;.+
+ action: keep
+ - source_labels:
+ - __address__
+ - __tmp_hash
+ target_label: __tmp_hash
+ regex: (.+);
+ replacement: $1
+ action: replace
+ - source_labels:
+ - __tmp_hash
+ target_label: __tmp_hash
+ modulus: 2
+ action: hashmod
+ - source_labels:
+ - __tmp_hash
+ - __tmp_disable_sharding
+ regex: $(INZONE_SHARD);|.+;.+
+ action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_4shards_2zones.golden b/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_4shards_2zones.golden
index dae56206d42..5dd62aaba2d 100644
--- a/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_4shards_2zones.golden
+++ b/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_4shards_2zones.golden
@@ -102,3 +102,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(INZONE_SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_6shards_3zones.golden b/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_6shards_3zones.golden
index dae56206d42..5dd62aaba2d 100644
--- a/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_6shards_3zones.golden
+++ b/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_6shards_3zones.golden
@@ -102,3 +102,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(INZONE_SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_force_attach_metadata_false.golden b/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_force_attach_metadata_false.golden
index dae56206d42..5dd62aaba2d 100644
--- a/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_force_attach_metadata_false.golden
+++ b/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_force_attach_metadata_false.golden
@@ -102,3 +102,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(INZONE_SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_force_attach_metadata_nil.golden b/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_force_attach_metadata_nil.golden
index dae56206d42..5dd62aaba2d 100644
--- a/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_force_attach_metadata_nil.golden
+++ b/pkg/prometheus/testdata/TopologySharding_ServiceMonitor_force_attach_metadata_nil.golden
@@ -102,3 +102,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(INZONE_SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/TracingConfig_Config_only_with_endpoint.golden b/pkg/prometheus/testdata/TracingConfig_Config_only_with_endpoint.golden
index 0dda9c1696d..4358202d867 100644
--- a/pkg/prometheus/testdata/TracingConfig_Config_only_with_endpoint.golden
+++ b/pkg/prometheus/testdata/TracingConfig_Config_only_with_endpoint.golden
@@ -5,5 +5,9 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
tracing:
endpoint: https://otel-collector.default.svc.local:3333
diff --git a/pkg/prometheus/testdata/TracingConfig_Expect_valid_config.golden b/pkg/prometheus/testdata/TracingConfig_Expect_valid_config.golden
index 12d51108a98..7b126d0c093 100644
--- a/pkg/prometheus/testdata/TracingConfig_Expect_valid_config.golden
+++ b/pkg/prometheus/testdata/TracingConfig_Expect_valid_config.golden
@@ -5,6 +5,10 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
tracing:
endpoint: https://otel-collector.default.svc.local:3333
client_type: grpc
diff --git a/pkg/prometheus/testdata/monitorObjectWithDefaultScrapeClassAndTLSConfig.golden b/pkg/prometheus/testdata/monitorObjectWithDefaultScrapeClassAndTLSConfig.golden
index 949df7f9d56..3bd8e7b991d 100644
--- a/pkg/prometheus/testdata/monitorObjectWithDefaultScrapeClassAndTLSConfig.golden
+++ b/pkg/prometheus/testdata/monitorObjectWithDefaultScrapeClassAndTLSConfig.golden
@@ -207,3 +207,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/monitorObjectWithNonDefaultScrapeClassAndTLSConfig.golden b/pkg/prometheus/testdata/monitorObjectWithNonDefaultScrapeClassAndTLSConfig.golden
index 9c05781fb4b..479e3d19c62 100644
--- a/pkg/prometheus/testdata/monitorObjectWithNonDefaultScrapeClassAndTLSConfig.golden
+++ b/pkg/prometheus/testdata/monitorObjectWithNonDefaultScrapeClassAndTLSConfig.golden
@@ -207,3 +207,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/monitorObjectWithoutScrapeClass.golden b/pkg/prometheus/testdata/monitorObjectWithoutScrapeClass.golden
index 0e72210293a..4fd36b5e27c 100644
--- a/pkg/prometheus/testdata/monitorObjectWithoutScrapeClass.golden
+++ b/pkg/prometheus/testdata/monitorObjectWithoutScrapeClass.golden
@@ -191,3 +191,7 @@ scrape_configs:
- source_labels:
- job
target_label: __tmp_prometheus_job_name
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/no_TSDB_config.golden b/pkg/prometheus/testdata/no_TSDB_config.golden
index 609303fe82c..ecbee05becb 100644
--- a/pkg/prometheus/testdata/no_TSDB_config.golden
+++ b/pkg/prometheus/testdata/no_TSDB_config.golden
@@ -5,3 +5,7 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassAuthz.golden b/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassAuthz.golden
index b0b95e62d78..d7a12071d4d 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassAuthz.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassAuthz.golden
@@ -68,3 +68,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithAttachMetadata.golden b/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithAttachMetadata.golden
index 21dc1b399bb..f0580e4eae2 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithAttachMetadata.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithAttachMetadata.golden
@@ -67,3 +67,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden b/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden
index f984477e4cb..faf63b68954 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden
@@ -66,3 +66,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithMetricRelabelings.golden b/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithMetricRelabelings.golden
index 0878d67d403..ebf59f69b2b 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithMetricRelabelings.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithMetricRelabelings.golden
@@ -75,3 +75,7 @@ scrape_configs:
replacement: tenant2
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithRelabelings.golden b/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithRelabelings.golden
index 3c3d3ccca47..7d98a9d93bb 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithRelabelings.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithDefaultScrapeClassWithRelabelings.golden
@@ -64,3 +64,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfig.golden b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfig.golden
index 0017829f882..47636148f0d 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfig.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfig.golden
@@ -64,3 +64,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfigMissingCA.golden b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfigMissingCA.golden
index 9e20706f38f..b73fc5479c0 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfigMissingCA.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfigMissingCA.golden
@@ -64,3 +64,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassAuthz.golden b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassAuthz.golden
index f7c001f5f93..3a75b9bbcbc 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassAuthz.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassAuthz.golden
@@ -68,3 +68,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassUserDefinedAuthz.golden b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassUserDefinedAuthz.golden
index bdf5acd75fa..fdd45444e6f 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassUserDefinedAuthz.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassUserDefinedAuthz.golden
@@ -68,3 +68,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithAttachMetadata.golden b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithAttachMetadata.golden
index 21dc1b399bb..f0580e4eae2 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithAttachMetadata.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithAttachMetadata.golden
@@ -67,3 +67,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden
index bdb4189c50c..5974c157bf6 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden
@@ -66,3 +66,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithMetricRelabelings.golden b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithMetricRelabelings.golden
index f78c06bdf0b..4a65e4973cd 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithMetricRelabelings.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithMetricRelabelings.golden
@@ -67,3 +67,7 @@ scrape_configs:
replacement: value1
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithRelabelings.golden b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithRelabelings.golden
index 0b9cde3ce36..1b7f2e3996b 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithRelabelings.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithNonDefaultScrapeClassWithRelabelings.golden
@@ -64,3 +64,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithPodName.golden b/pkg/prometheus/testdata/podMonitorObjectWithPodName.golden
index 4976feffb0c..c3be5af7956 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithPodName.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithPodName.golden
@@ -60,3 +60,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithPortNumber.golden b/pkg/prometheus/testdata/podMonitorObjectWithPortNumber.golden
index c8d25dbfd79..c159b2248f6 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithPortNumber.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithPortNumber.golden
@@ -60,3 +60,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithTargetPortInt.golden b/pkg/prometheus/testdata/podMonitorObjectWithTargetPortInt.golden
index 83f221cc42f..dc2b8bb0e0a 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithTargetPortInt.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithTargetPortInt.golden
@@ -60,3 +60,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/podMonitorObjectWithTargetPortString.golden b/pkg/prometheus/testdata/podMonitorObjectWithTargetPortString.golden
index 0ee1a030b11..ee0100e9624 100644
--- a/pkg/prometheus/testdata/podMonitorObjectWithTargetPortString.golden
+++ b/pkg/prometheus/testdata/podMonitorObjectWithTargetPortString.golden
@@ -60,3 +60,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/pod_monitor_with_oauth2.golden b/pkg/prometheus/testdata/pod_monitor_with_oauth2.golden
index 972390d18d2..de5c41e1b4d 100644
--- a/pkg/prometheus/testdata/pod_monitor_with_oauth2.golden
+++ b/pkg/prometheus/testdata/pod_monitor_with_oauth2.golden
@@ -73,3 +73,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/probeObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden b/pkg/prometheus/testdata/probeObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden
index 40fb45bdf1a..9afced6e486 100644
--- a/pkg/prometheus/testdata/probeObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden
+++ b/pkg/prometheus/testdata/probeObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden
@@ -56,3 +56,7 @@ scrape_configs:
action: labeldrop
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/probeObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden b/pkg/prometheus/testdata/probeObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden
index f97c08c1117..ad1998d56e2 100644
--- a/pkg/prometheus/testdata/probeObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden
+++ b/pkg/prometheus/testdata/probeObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden
@@ -56,3 +56,7 @@ scrape_configs:
action: labeldrop
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/probe_monitor_with_oauth2.golden b/pkg/prometheus/testdata/probe_monitor_with_oauth2.golden
index 6554bf6145a..e83c511ac74 100644
--- a/pkg/prometheus/testdata/probe_monitor_with_oauth2.golden
+++ b/pkg/prometheus/testdata/probe_monitor_with_oauth2.golden
@@ -61,3 +61,7 @@ scrape_configs:
tls_config:
insecure_skip_verify: true
ca_file: /etc/prometheus/certs/0_default_tls_ca2
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/scrapeConfigObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden b/pkg/prometheus/testdata/scrapeConfigObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden
index aee59dda297..32045bd9a42 100644
--- a/pkg/prometheus/testdata/scrapeConfigObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden
+++ b/pkg/prometheus/testdata/scrapeConfigObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden
@@ -20,3 +20,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/scrapeConfigObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden b/pkg/prometheus/testdata/scrapeConfigObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden
index 91eded626ef..b84e5da30ff 100644
--- a/pkg/prometheus/testdata/scrapeConfigObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden
+++ b/pkg/prometheus/testdata/scrapeConfigObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden
@@ -20,3 +20,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassAuthz.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassAuthz.golden
index 0aca5e900ba..129541eeb29 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassAuthz.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassAuthz.golden
@@ -87,3 +87,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithAttachMetadata.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithAttachMetadata.golden
index 1cae8fd6fc5..5a652e697b1 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithAttachMetadata.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithAttachMetadata.golden
@@ -86,3 +86,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden
index 924aeb0ab3c..d1bf25c05bb 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithFallbackScrapeProtocol.golden
@@ -85,3 +85,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithMetricRelabelings.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithMetricRelabelings.golden
index d24f6b2067a..ae0c4944953 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithMetricRelabelings.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithMetricRelabelings.golden
@@ -94,3 +94,7 @@ scrape_configs:
replacement: tenant2
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithRelabelings.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithRelabelings.golden
index f0f988365c3..1ed4bf6fdf9 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithRelabelings.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithDefaultScrapeClassWithRelabelings.golden
@@ -83,3 +83,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfig.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfig.golden
index fe5b5632a9f..b50a01fed3f 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfig.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfig.golden
@@ -83,3 +83,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfigMissingCA.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfigMissingCA.golden
index dcb2c94894a..69ed8d59e84 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfigMissingCA.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassAndExistingTLSConfigMissingCA.golden
@@ -83,3 +83,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassAuthz.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassAuthz.golden
index 0aca5e900ba..129541eeb29 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassAuthz.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassAuthz.golden
@@ -87,3 +87,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassUserDefinedAuthz.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassUserDefinedAuthz.golden
index 70ea8ffc788..3266630d842 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassUserDefinedAuthz.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassUserDefinedAuthz.golden
@@ -87,3 +87,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithAttachMetadata.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithAttachMetadata.golden
index 1cae8fd6fc5..5a652e697b1 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithAttachMetadata.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithAttachMetadata.golden
@@ -86,3 +86,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden
index e6dce8c9ffd..88be0582706 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithFallbackScrapeProtocol.golden
@@ -85,3 +85,7 @@ scrape_configs:
metric_relabel_configs:
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithMetricRelabelings.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithMetricRelabelings.golden
index 105df5184b5..25e725a6880 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithMetricRelabelings.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithMetricRelabelings.golden
@@ -86,3 +86,7 @@ scrape_configs:
replacement: value1
- target_label: namespace
replacement: default
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithRelabelings.golden b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithRelabelings.golden
index d0c748dd1ec..efdfa0c0848 100644
--- a/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithRelabelings.golden
+++ b/pkg/prometheus/testdata/serviceMonitorObjectWithNonDefaultScrapeClassWithRelabelings.golden
@@ -83,3 +83,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/service_monitor_with_oauth2.golden b/pkg/prometheus/testdata/service_monitor_with_oauth2.golden
index 33a4f1b7f19..1a6574b1047 100644
--- a/pkg/prometheus/testdata/service_monitor_with_oauth2.golden
+++ b/pkg/prometheus/testdata/service_monitor_with_oauth2.golden
@@ -92,3 +92,7 @@ scrape_configs:
- __tmp_disable_sharding
regex: $(SHARD);|.+;.+
action: keep
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/topology_zone_external_label_address_mode.golden b/pkg/prometheus/testdata/topology_zone_external_label_address_mode.golden
index 14f3838700f..eed9a2997e7 100644
--- a/pkg/prometheus/testdata/topology_zone_external_label_address_mode.golden
+++ b/pkg/prometheus/testdata/topology_zone_external_label_address_mode.golden
@@ -5,3 +5,7 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/topology_zone_external_label_custom_name.golden b/pkg/prometheus/testdata/topology_zone_external_label_custom_name.golden
index 7c164b02bde..9d9ad2ef174 100644
--- a/pkg/prometheus/testdata/topology_zone_external_label_custom_name.golden
+++ b/pkg/prometheus/testdata/topology_zone_external_label_custom_name.golden
@@ -6,3 +6,7 @@ global:
topology_zone: $(TOPOLOGY_ZONE)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/topology_zone_external_label_default_name.golden b/pkg/prometheus/testdata/topology_zone_external_label_default_name.golden
index 1114b0d01d4..020a131afb4 100644
--- a/pkg/prometheus/testdata/topology_zone_external_label_default_name.golden
+++ b/pkg/prometheus/testdata/topology_zone_external_label_default_name.golden
@@ -6,3 +6,7 @@ global:
zone: $(TOPOLOGY_ZONE)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/topology_zone_external_label_disabled.golden b/pkg/prometheus/testdata/topology_zone_external_label_disabled.golden
index 14f3838700f..eed9a2997e7 100644
--- a/pkg/prometheus/testdata/topology_zone_external_label_disabled.golden
+++ b/pkg/prometheus/testdata/topology_zone_external_label_disabled.golden
@@ -5,3 +5,7 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/testdata/topology_zone_external_label_no_feature_gate.golden b/pkg/prometheus/testdata/topology_zone_external_label_no_feature_gate.golden
index 14f3838700f..eed9a2997e7 100644
--- a/pkg/prometheus/testdata/topology_zone_external_label_no_feature_gate.golden
+++ b/pkg/prometheus/testdata/topology_zone_external_label_no_feature_gate.golden
@@ -5,3 +5,7 @@ global:
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
+storage:
+ tsdb:
+ retention:
+ time: 24h
diff --git a/pkg/prometheus/validation/validator_test.go b/pkg/prometheus/validation/validator_test.go
index baae6581d11..725fd39e508 100644
--- a/pkg/prometheus/validation/validator_test.go
+++ b/pkg/prometheus/validation/validator_test.go
@@ -19,7 +19,6 @@ import (
"github.com/prometheus/prometheus/model/relabel"
"github.com/stretchr/testify/require"
- "k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
@@ -117,7 +116,7 @@ func TestValidateRelabelConfig(t *testing.T) {
scenario: "replacement set for uppercase action",
relabelConfig: monitoringv1.RelabelConfig{
Action: "uppercase",
- Replacement: ptr.To("some-replace-value"),
+ Replacement: new("some-replace-value"),
},
prometheus: defaultPrometheusSpec,
expectedErr: true,
@@ -140,7 +139,7 @@ func TestValidateRelabelConfig(t *testing.T) {
relabelConfig: monitoringv1.RelabelConfig{
Action: "labelmap",
Regex: "__meta_kubernetes_service_label_(.+)",
- Replacement: ptr.To("some-name-value"),
+ Replacement: new("some-name-value"),
},
prometheus: defaultPrometheusSpec,
expectedErr: true,
@@ -160,7 +159,7 @@ func TestValidateRelabelConfig(t *testing.T) {
relabelConfig: monitoringv1.RelabelConfig{
Action: "labelmap",
Regex: "__meta_kubernetes_service_label_(.+)",
- Replacement: ptr.To("abc"),
+ Replacement: new("abc"),
},
prometheus: defaultPrometheusSpec,
},
@@ -197,7 +196,7 @@ func TestValidateRelabelConfig(t *testing.T) {
scenario: "valid replace config with empty replacement",
relabelConfig: monitoringv1.RelabelConfig{
Action: "replace",
- Replacement: ptr.To(""),
+ Replacement: new(""),
TargetLabel: "abc",
},
prometheus: defaultPrometheusSpec,
@@ -351,9 +350,9 @@ func TestValidateRelabelConfig(t *testing.T) {
relabelConfig: monitoringv1.RelabelConfig{
SourceLabels: []monitoringv1.LabelName{"__tmp_port"},
TargetLabel: "__port1",
- Separator: ptr.To("^"),
+ Separator: new("^"),
Regex: "validregex",
- Replacement: ptr.To("replacevalue"),
+ Replacement: new("replacevalue"),
Action: "keepequal",
},
prometheus: monitoringv1.Prometheus{
@@ -371,7 +370,7 @@ func TestValidateRelabelConfig(t *testing.T) {
relabelConfig: monitoringv1.RelabelConfig{
SourceLabels: []monitoringv1.LabelName{"__tmp_port"},
TargetLabel: "__port1",
- Separator: ptr.To(relabel.DefaultRelabelConfig.Separator),
+ Separator: new(relabel.DefaultRelabelConfig.Separator),
Regex: relabel.DefaultRelabelConfig.Regex.String(),
Modulus: relabel.DefaultRelabelConfig.Modulus,
Replacement: &relabel.DefaultRelabelConfig.Replacement,
@@ -390,7 +389,7 @@ func TestValidateRelabelConfig(t *testing.T) {
relabelConfig: monitoringv1.RelabelConfig{
Action: "labelmap",
Regex: "^(cluster)$",
- Replacement: ptr.To("exported_${1}"),
+ Replacement: new("exported_${1}"),
},
prometheus: defaultPrometheusSpec,
},
@@ -399,7 +398,7 @@ func TestValidateRelabelConfig(t *testing.T) {
relabelConfig: monitoringv1.RelabelConfig{
Action: "labelmap",
Regex: "__meta_kubernetes_(.*)",
- Replacement: ptr.To("k8s_${1}"),
+ Replacement: new("k8s_${1}"),
},
prometheus: defaultPrometheusSpec,
},
diff --git a/pkg/thanos/operator_test.go b/pkg/thanos/operator_test.go
index 8010758c89f..44e277552a1 100644
--- a/pkg/thanos/operator_test.go
+++ b/pkg/thanos/operator_test.go
@@ -51,8 +51,8 @@ func TestCreateOrUpdateRulerConfigSecret(t *testing.T) {
{
URL: "http://example.com",
MessageVersion: ptr.To(monitoringv1.RemoteWriteMessageVersion2_0),
- SendNativeHistograms: ptr.To(true),
- RoundRobinDNS: ptr.To(true),
+ SendNativeHistograms: new(true),
+ RoundRobinDNS: new(true),
},
},
golden: "default_remote_write_config.golden",
@@ -74,8 +74,8 @@ func TestCreateOrUpdateRulerConfigSecret(t *testing.T) {
{
URL: "http://example.com",
MessageVersion: ptr.To(monitoringv1.RemoteWriteMessageVersion2_0),
- SendNativeHistograms: ptr.To(true),
- RoundRobinDNS: ptr.To(true),
+ SendNativeHistograms: new(true),
+ RoundRobinDNS: new(true),
Sigv4: &monitoringv1.Sigv4{
Profile: "profilename",
RoleArn: "arn:aws:iam::123456789012:instance-profile/prometheus",
@@ -108,7 +108,7 @@ func TestCreateOrUpdateRulerConfigSecret(t *testing.T) {
Namespace: "default",
},
Spec: monitoringv1.ThanosRulerSpec{
- Version: ptr.To(tc.version),
+ Version: new(tc.version),
RemoteWrite: tc.remoteWrite,
},
}
diff --git a/pkg/thanos/statefulset.go b/pkg/thanos/statefulset.go
index 59e053d5364..66a651245f5 100644
--- a/pkg/thanos/statefulset.go
+++ b/pkg/thanos/statefulset.go
@@ -453,7 +453,7 @@ func makeStatefulSetSpec(tr *monitoringv1.ThanosRuler, config Config, ruleConfig
LocalObjectReference: corev1.LocalObjectReference{
Name: name,
},
- Optional: ptr.To(true),
+ Optional: new(true),
},
},
})
@@ -478,8 +478,8 @@ func makeStatefulSetSpec(tr *monitoringv1.ThanosRuler, config Config, ruleConfig
Ports: ports,
TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
SecurityContext: &corev1.SecurityContext{
- AllowPrivilegeEscalation: ptr.To(false),
- ReadOnlyRootFilesystem: ptr.To(true),
+ AllowPrivilegeEscalation: new(false),
+ ReadOnlyRootFilesystem: new(true),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
@@ -517,7 +517,7 @@ func makeStatefulSetSpec(tr *monitoringv1.ThanosRuler, config Config, ruleConfig
SchedulerName: tr.Spec.SchedulerName,
PriorityClassName: tr.Spec.PriorityClassName,
ServiceAccountName: tr.Spec.ServiceAccountName,
- TerminationGracePeriodSeconds: ptr.To(ptr.Deref(tr.Spec.TerminationGracePeriodSeconds, defaultTerminationGracePeriodSeconds)),
+ TerminationGracePeriodSeconds: new(ptr.Deref(tr.Spec.TerminationGracePeriodSeconds, defaultTerminationGracePeriodSeconds)),
Containers: containers,
InitContainers: tr.Spec.InitContainers,
Volumes: trVolumes,
diff --git a/pkg/thanos/statefulset_test.go b/pkg/thanos/statefulset_test.go
index 3c5de001b9c..a849cf78067 100644
--- a/pkg/thanos/statefulset_test.go
+++ b/pkg/thanos/statefulset_test.go
@@ -231,7 +231,7 @@ func TestStatefulSetVolumes(t *testing.T) {
LocalObjectReference: corev1.LocalObjectReference{
Name: "rules-configmap-one",
},
- Optional: ptr.To(true),
+ Optional: new(true),
},
},
},
@@ -722,7 +722,7 @@ func TestRetention(t *testing.T) {
func TestThanosGrpcArguments(t *testing.T) {
sset, err := makeStatefulSet(&monitoringv1.ThanosRuler{
Spec: monitoringv1.ThanosRulerSpec{
- Version: ptr.To("0.37.0"),
+ Version: new("0.37.0"),
QueryEndpoints: emptyQueryEndpoints,
GRPCServerTLSConfig: &monitoringv1.GRPCServerTLSConfig{
TLSConfig: monitoringv1.TLSConfig{
@@ -779,7 +779,7 @@ func TestGRPCServerTLSCipherSuites(t *testing.T) {
t.Run(tc.scenario, func(t *testing.T) {
sset, err := makeStatefulSet(&monitoringv1.ThanosRuler{
Spec: monitoringv1.ThanosRulerSpec{
- Version: ptr.To(tc.version),
+ Version: new(tc.version),
QueryEndpoints: emptyQueryEndpoints,
GRPCServerTLSConfig: &monitoringv1.GRPCServerTLSConfig{
CipherSuites: tc.cipherSuites,
@@ -827,7 +827,7 @@ func TestGRPCServerTLSCurves(t *testing.T) {
t.Run(tc.scenario, func(t *testing.T) {
sset, err := makeStatefulSet(&monitoringv1.ThanosRuler{
Spec: monitoringv1.ThanosRulerSpec{
- Version: ptr.To(tc.version),
+ Version: new(tc.version),
QueryEndpoints: emptyQueryEndpoints,
GRPCServerTLSConfig: &monitoringv1.GRPCServerTLSConfig{
Curves: tc.curves,
@@ -909,7 +909,7 @@ func TestPodTemplateConfig(t *testing.T) {
ImagePullPolicy: imagePullPolicy,
AdditionalArgs: additionalArgs,
SchedulerName: schedulerName,
- HostUsers: ptr.To(true),
+ HostUsers: new(true),
},
}, defaultTestConfig, nil, "", &operator.ShardedSecret{})
require.NoError(t, err)
@@ -983,7 +983,7 @@ func TestStatefulSetMinReadySeconds(t *testing.T) {
require.Equal(t, int32(0), statefulSet.MinReadySeconds)
// assert set correctly if not nil
- tr.Spec.MinReadySeconds = ptr.To(int32(5))
+ tr.Spec.MinReadySeconds = new(int32(5))
statefulSet, err = makeStatefulSetSpec(&tr, defaultTestConfig, nil, &operator.ShardedSecret{})
require.NoError(t, err)
require.Equal(t, int32(5), statefulSet.MinReadySeconds)
@@ -1127,7 +1127,7 @@ func TestThanosVersion(t *testing.T) {
sset, err := makeStatefulSet(&monitoringv1.ThanosRuler{
Spec: monitoringv1.ThanosRulerSpec{
QueryEndpoints: emptyQueryEndpoints,
- Version: ptr.To(tc.version),
+ Version: new(tc.version),
},
}, defaultTestConfig, nil, "", &operator.ShardedSecret{})
@@ -1155,7 +1155,7 @@ func TestStatefulSetDNSPolicyAndDNSConfig(t *testing.T) {
Options: []monitoringv1.PodDNSConfigOption{
{
Name: "ndots",
- Value: ptr.To("5"),
+ Value: new("5"),
},
},
},
@@ -1170,7 +1170,7 @@ func TestStatefulSetDNSPolicyAndDNSConfig(t *testing.T) {
Options: []corev1.PodDNSConfigOption{
{
Name: "ndots",
- Value: ptr.To("5"),
+ Value: new("5"),
},
},
}, sset.Spec.Template.Spec.DNSConfig, "expected DNS configuration to match")
@@ -1181,8 +1181,8 @@ func TestStatefulSetenableServiceLinks(t *testing.T) {
enableServiceLinks *bool
expectedEnableServiceLinks *bool
}{
- {enableServiceLinks: ptr.To(false), expectedEnableServiceLinks: ptr.To(false)},
- {enableServiceLinks: ptr.To(true), expectedEnableServiceLinks: ptr.To(true)},
+ {enableServiceLinks: new(false), expectedEnableServiceLinks: new(false)},
+ {enableServiceLinks: new(true), expectedEnableServiceLinks: new(true)},
{enableServiceLinks: nil, expectedEnableServiceLinks: nil},
}
@@ -1585,13 +1585,13 @@ func TestStatefulSetUpdateStrategy(t *testing.T) {
updateStrategy: &monitoringv1.StatefulSetUpdateStrategy{
Type: monitoringv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &monitoringv1.RollingUpdateStatefulSetStrategy{
- MaxUnavailable: ptr.To(intstr.FromInt(1)),
+ MaxUnavailable: new(intstr.FromInt(1)),
},
},
exp: appsv1.StatefulSetUpdateStrategy{
Type: appsv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{
- MaxUnavailable: ptr.To(intstr.FromInt(1)),
+ MaxUnavailable: new(intstr.FromInt(1)),
},
},
},
diff --git a/pkg/webconfig/config_test.go b/pkg/webconfig/config_test.go
index 89ba5e7dc61..45f824d2448 100644
--- a/pkg/webconfig/config_test.go
+++ b/pkg/webconfig/config_test.go
@@ -23,7 +23,6 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
- "k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
"github.com/prometheus-operator/prometheus-operator/pkg/webconfig"
@@ -140,11 +139,11 @@ func TestCreateOrUpdateWebConfigSecret(t *testing.T) {
},
Key: "tls.keySecret",
},
- ClientAuthType: ptr.To("RequireAnyClientCert"),
- MinVersion: ptr.To("TLS11"),
- MaxVersion: ptr.To("TLS13"),
+ ClientAuthType: new("RequireAnyClientCert"),
+ MinVersion: new("TLS11"),
+ MaxVersion: new("TLS13"),
CipherSuites: []string{"cipher-1", "cipher-2"},
- PreferServerCipherSuites: ptr.To(false),
+ PreferServerCipherSuites: new(false),
CurvePreferences: []string{"curve-1", "curve-2"},
},
},
@@ -154,9 +153,9 @@ func TestCreateOrUpdateWebConfigSecret(t *testing.T) {
name: "TLS config with client CA, cert and key files",
webConfigFileFields: monitoringv1.WebConfigFileFields{
TLSConfig: &monitoringv1.WebTLSConfig{
- ClientCAFile: ptr.To("/etc/ssl/certs/tls.client_ca"),
- CertFile: ptr.To("/etc/ssl/certs/tls.crt"),
- KeyFile: ptr.To("/etc/ssl/secrets/tls.key"),
+ ClientCAFile: new("/etc/ssl/certs/tls.client_ca"),
+ CertFile: new("/etc/ssl/certs/tls.crt"),
+ KeyFile: new("/etc/ssl/secrets/tls.key"),
},
},
golden: "TLS_config_with_client_CA_cert_and_key_files.golden",
@@ -165,7 +164,7 @@ func TestCreateOrUpdateWebConfigSecret(t *testing.T) {
name: "HTTP config with all parameters",
webConfigFileFields: monitoringv1.WebConfigFileFields{
HTTPConfig: &monitoringv1.WebHTTPConfig{
- HTTP2: ptr.To(false),
+ HTTP2: new(false),
Headers: &monitoringv1.WebHTTPHeaders{
ContentSecurityPolicy: "test",
StrictTransportSecurity: "test",
diff --git a/scripts/go.mod b/scripts/go.mod
index be66b1205af..b97751d40f0 100644
--- a/scripts/go.mod
+++ b/scripts/go.mod
@@ -1,23 +1,24 @@
module github.com/prometheus-operator/prometheus-operator/tooling
-go 1.25.0
+go 1.26.0
require (
github.com/ahmetb/gen-crd-api-reference-docs v0.3.1-0.20241111191808-71fefeed8910
github.com/brancz/gojsontoyaml v0.1.0
github.com/bwplotka/mdox v0.9.1-0.20260318034157-e88e0a8655a0
- github.com/golangci/golangci-lint/v2 v2.11.4
+ github.com/golangci/golangci-lint/v2 v2.12.1
github.com/google/go-jsonnet v0.22.0
github.com/jsonnet-bundler/jsonnet-bundler v0.6.0
github.com/prometheus/prometheus v0.311.2
github.com/yeya24/promlinter v0.3.0
- k8s.io/code-generator v0.35.2
- sigs.k8s.io/controller-tools v0.20.1
+ k8s.io/code-generator v0.36.0
+ sigs.k8s.io/controller-tools v0.21.0
)
require (
4d63.com/gocheckcompilerdirectives v1.3.0 // indirect
4d63.com/gochecknoglobals v0.2.2 // indirect
+ charm.land/lipgloss/v2 v2.0.3 // indirect
cloud.google.com/go/auth v0.18.2 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
@@ -40,16 +41,17 @@ require (
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
+ github.com/ClickHouse/clickhouse-go-linter v1.2.0 // indirect
github.com/Code-Hex/go-generics-cache v1.5.1 // indirect
github.com/Djarvur/go-err113 v0.1.1 // indirect
github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect
- github.com/Masterminds/semver/v3 v3.4.0 // indirect
+ github.com/Masterminds/semver/v3 v3.5.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/MirrexOne/unqueryvet v1.5.4 // indirect
github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect
github.com/PuerkitoBio/goquery v1.5.1 // indirect
github.com/alecthomas/chroma v0.10.0 // indirect
- github.com/alecthomas/chroma/v2 v2.23.1 // indirect
+ github.com/alecthomas/chroma/v2 v2.24.1 // indirect
github.com/alecthomas/go-check-sumtype v0.3.1 // indirect
github.com/alecthomas/kingpin/v2 v2.4.0 // indirect
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
@@ -64,8 +66,8 @@ require (
github.com/antchfx/xmlquery v1.3.4 // indirect
github.com/antchfx/xpath v1.1.10 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
- github.com/ashanbrown/forbidigo/v2 v2.3.0 // indirect
- github.com/ashanbrown/makezero/v2 v2.1.0 // indirect
+ github.com/ashanbrown/forbidigo/v2 v2.3.1 // indirect
+ github.com/ashanbrown/makezero/v2 v2.2.1 // indirect
github.com/aws/aws-sdk-go-v2 v1.41.5 // indirect
github.com/aws/aws-sdk-go-v2/config v1.32.13 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.19.13 // indirect
@@ -96,24 +98,27 @@ require (
github.com/bkielbasa/cyclop v1.2.3 // indirect
github.com/blizzy78/varnamelen v0.8.0 // indirect
github.com/bombsimon/wsl/v4 v4.7.0 // indirect
- github.com/bombsimon/wsl/v5 v5.6.0 // indirect
+ github.com/bombsimon/wsl/v5 v5.8.0 // indirect
github.com/breml/bidichk v0.3.3 // indirect
github.com/breml/errchkjson v0.4.1 // indirect
- github.com/butuzov/ireturn v0.4.0 // indirect
+ github.com/butuzov/ireturn v0.4.1 // indirect
github.com/butuzov/mirror v1.3.0 // indirect
github.com/catenacyber/perfsprint v0.10.1 // indirect
github.com/ccojocar/zxcvbn-go v1.0.4 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charithe/durationcheck v0.0.11 // indirect
- github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
+ github.com/charmbracelet/colorprofile v0.4.3 // indirect
github.com/charmbracelet/glamour v0.6.0 // indirect
- github.com/charmbracelet/lipgloss v1.1.0 // indirect
- github.com/charmbracelet/x/ansi v0.10.1 // indirect
- github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
- github.com/charmbracelet/x/term v0.2.1 // indirect
+ github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318 // indirect
+ github.com/charmbracelet/x/ansi v0.11.7 // indirect
+ github.com/charmbracelet/x/term v0.2.2 // indirect
+ github.com/charmbracelet/x/termios v0.1.1 // indirect
+ github.com/charmbracelet/x/windows v0.2.2 // indirect
github.com/ckaznocha/intrange v0.3.1 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/cli/safeexec v1.0.1 // indirect
+ github.com/clipperhouse/displaywidth v0.11.0 // indirect
+ github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
@@ -126,7 +131,7 @@ require (
github.com/dennwc/varint v1.0.0 // indirect
github.com/digitalocean/godo v1.178.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
- github.com/dlclark/regexp2 v1.11.5 // indirect
+ github.com/dlclark/regexp2 v1.12.0 // indirect
github.com/docker/docker v28.5.2+incompatible // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
@@ -144,8 +149,8 @@ require (
github.com/felixge/fgprof v0.9.5 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/firefart/nonamedreturns v1.0.6 // indirect
- github.com/fsnotify/fsnotify v1.9.0 // indirect
- github.com/fxamacker/cbor/v2 v2.9.0 // indirect
+ github.com/fsnotify/fsnotify v1.10.0 // indirect
+ github.com/fxamacker/cbor/v2 v2.9.1 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/ghostiam/protogetter v0.3.20 // indirect
@@ -156,23 +161,23 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.25.0 // indirect
github.com/go-openapi/errors v0.22.7 // indirect
- github.com/go-openapi/jsonpointer v0.22.5 // indirect
+ github.com/go-openapi/jsonpointer v0.23.1 // indirect
github.com/go-openapi/jsonreference v0.21.5 // indirect
github.com/go-openapi/loads v0.23.3 // indirect
github.com/go-openapi/spec v0.22.4 // indirect
github.com/go-openapi/strfmt v0.26.1 // indirect
- github.com/go-openapi/swag v0.25.5 // indirect
- github.com/go-openapi/swag/cmdutils v0.25.5 // indirect
- github.com/go-openapi/swag/conv v0.25.5 // indirect
- github.com/go-openapi/swag/fileutils v0.25.5 // indirect
- github.com/go-openapi/swag/jsonname v0.25.5 // indirect
- github.com/go-openapi/swag/jsonutils v0.25.5 // indirect
- github.com/go-openapi/swag/loading v0.25.5 // indirect
- github.com/go-openapi/swag/mangling v0.25.5 // indirect
- github.com/go-openapi/swag/netutils v0.25.5 // indirect
- github.com/go-openapi/swag/stringutils v0.25.5 // indirect
- github.com/go-openapi/swag/typeutils v0.25.5 // indirect
- github.com/go-openapi/swag/yamlutils v0.25.5 // indirect
+ github.com/go-openapi/swag v0.26.0 // indirect
+ github.com/go-openapi/swag/cmdutils v0.26.0 // indirect
+ github.com/go-openapi/swag/conv v0.26.0 // indirect
+ github.com/go-openapi/swag/fileutils v0.26.0 // indirect
+ github.com/go-openapi/swag/jsonname v0.26.0 // indirect
+ github.com/go-openapi/swag/jsonutils v0.26.0 // indirect
+ github.com/go-openapi/swag/loading v0.26.0 // indirect
+ github.com/go-openapi/swag/mangling v0.26.0 // indirect
+ github.com/go-openapi/swag/netutils v0.26.0 // indirect
+ github.com/go-openapi/swag/stringutils v0.26.0 // indirect
+ github.com/go-openapi/swag/typeutils v0.26.0 // indirect
+ github.com/go-openapi/swag/yamlutils v0.26.0 // indirect
github.com/go-openapi/validate v0.25.2 // indirect
github.com/go-resty/resty/v2 v2.17.2 // indirect
github.com/go-toolsmith/astcast v1.1.0 // indirect
@@ -197,13 +202,14 @@ require (
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/golangci/asciicheck v0.5.0 // indirect
- github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect
+ github.com/golangci/dupl v0.0.0-20260401084720-c99c5cf5c202 // indirect
github.com/golangci/go-printf-func-name v0.1.1 // indirect
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect
github.com/golangci/golines v0.15.0 // indirect
github.com/golangci/misspell v0.8.0 // indirect
github.com/golangci/plugin-module-register v0.1.2 // indirect
github.com/golangci/revgrep v0.8.0 // indirect
+ github.com/golangci/rowserrcheck v0.0.0-20260419091836-c5f79b8a11ba // indirect
github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e // indirect
github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e // indirect
github.com/google/gnostic-models v0.7.1 // indirect
@@ -233,7 +239,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
- github.com/hashicorp/go-version v1.8.0 // indirect
+ github.com/hashicorp/go-version v1.9.0 // indirect
github.com/hashicorp/golang-lru v0.6.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
@@ -243,8 +249,7 @@ require (
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/ionos-cloud/sdk-go/v6 v6.3.6 // indirect
- github.com/jgautheron/goconst v1.8.2 // indirect
- github.com/jingyugao/rowserrcheck v1.1.1 // indirect
+ github.com/jgautheron/goconst v1.10.0 // indirect
github.com/jjti/go-spancheck v0.6.5 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
@@ -267,17 +272,17 @@ require (
github.com/ldez/usetesting v0.5.0 // indirect
github.com/leonklingele/grouper v1.1.2 // indirect
github.com/linode/linodego v1.66.0 // indirect
- github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
+ github.com/lucasb-eyer/go-colorful v1.4.0 // indirect
github.com/macabu/inamedparam v0.2.0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/manuelarte/embeddedstructfieldcheck v0.4.0 // indirect
- github.com/manuelarte/funcorder v0.5.0 // indirect
+ github.com/manuelarte/funcorder v0.6.0 // indirect
github.com/maratori/testableexamples v1.0.1 // indirect
github.com/maratori/testpackage v1.1.2 // indirect
github.com/matoous/godox v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/mattn/go-runewidth v0.0.16 // indirect
+ github.com/mattn/go-runewidth v0.0.23 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/mdlayher/socket v0.5.1 // indirect
@@ -292,6 +297,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/moricho/tparallel v0.3.2 // indirect
+ github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@@ -309,7 +315,7 @@ require (
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/ovh/go-ovh v1.9.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
- github.com/pelletier/go-toml/v2 v2.2.4 // indirect
+ github.com/pelletier/go-toml/v2 v2.3.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
@@ -333,6 +339,7 @@ require (
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/ryancurrah/gomodguard v1.4.1 // indirect
+ github.com/ryancurrah/gomodguard/v2 v2.1.0 // indirect
github.com/ryanrolds/sqlclosecheck v0.6.0 // indirect
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect
github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect
@@ -340,12 +347,12 @@ require (
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
github.com/sashamelentyev/usestdlibvars v1.29.0 // indirect
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36 // indirect
- github.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08 // indirect
+ github.com/securego/gosec/v2 v2.26.1 // indirect
github.com/sergi/go-diff v1.3.1 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/sivchari/containedctx v1.0.3 // indirect
github.com/sonatard/noctx v0.5.1 // indirect
- github.com/sourcegraph/go-diff v0.7.0 // indirect
+ github.com/sourcegraph/go-diff v0.8.0 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/cobra v1.10.2 // indirect
@@ -360,9 +367,9 @@ require (
github.com/subosito/gotenv v1.4.1 // indirect
github.com/tdewolff/parse/v2 v2.7.3 // indirect
github.com/temoto/robotstxt v1.1.1 // indirect
- github.com/tetafro/godot v1.5.4 // indirect
+ github.com/tetafro/godot v1.5.6 // indirect
github.com/theckman/yacspin v0.13.12 // indirect
- github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 // indirect
+ github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 // indirect
github.com/timonwong/loggercheck v0.11.0 // indirect
github.com/tomarrell/wrapcheck/v2 v2.12.0 // indirect
github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
@@ -381,7 +388,7 @@ require (
github.com/yuin/goldmark-emoji v1.0.2 // indirect
gitlab.com/bosi/decorder v0.4.2 // indirect
go-simpler.org/musttag v0.14.0 // indirect
- go-simpler.org/sloglint v0.11.1 // indirect
+ go-simpler.org/sloglint v0.12.0 // indirect
go.augendre.info/arangolint v0.4.0 // indirect
go.augendre.info/fatcontext v0.9.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
@@ -396,24 +403,24 @@ require (
go.uber.org/zap v1.27.1 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
- golang.org/x/crypto v0.49.0 // indirect
+ golang.org/x/crypto v0.50.0 // indirect
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect
golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 // indirect
- golang.org/x/mod v0.34.0 // indirect
- golang.org/x/net v0.52.0 // indirect
+ golang.org/x/mod v0.35.0 // indirect
+ golang.org/x/net v0.53.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/sync v0.20.0 // indirect
- golang.org/x/sys v0.42.0 // indirect
- golang.org/x/term v0.41.0 // indirect
- golang.org/x/text v0.35.0 // indirect
+ golang.org/x/sys v0.43.0 // indirect
+ golang.org/x/term v0.42.0 // indirect
+ golang.org/x/text v0.36.0 // indirect
golang.org/x/time v0.15.0 // indirect
- golang.org/x/tools v0.43.0 // indirect
+ golang.org/x/tools v0.44.0 // indirect
google.golang.org/api v0.272.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect
google.golang.org/grpc v1.80.0 // indirect
- google.golang.org/protobuf v1.36.11 // indirect
+ google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
@@ -422,19 +429,19 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.2 // indirect
honnef.co/go/tools v0.7.0 // indirect
- k8s.io/api v0.35.3 // indirect
- k8s.io/apiextensions-apiserver v0.35.2 // indirect
- k8s.io/apimachinery v0.35.3 // indirect
- k8s.io/client-go v0.35.3 // indirect
+ k8s.io/api v0.36.0 // indirect
+ k8s.io/apiextensions-apiserver v0.36.0 // indirect
+ k8s.io/apimachinery v0.36.0 // indirect
+ k8s.io/client-go v0.36.0 // indirect
k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b // indirect
k8s.io/klog/v2 v2.140.0 // indirect
- k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect
- k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect
+ k8s.io/kube-openapi v0.0.0-20260427204847-8949caaa1199 // indirect
+ k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 // indirect
mvdan.cc/gofumpt v0.9.2 // indirect
mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
- sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect
+ sigs.k8s.io/structured-merge-diff/v6 v6.4.0 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
)
diff --git a/scripts/go.sum b/scripts/go.sum
index 1132939e25d..a48f9cb7a02 100644
--- a/scripts/go.sum
+++ b/scripts/go.sum
@@ -12,6 +12,8 @@ cel.dev/expr v0.19.2/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
+charm.land/lipgloss/v2 v2.0.3 h1:yM2zJ4Cf5Y51b7RHIwioil4ApI/aypFXXVHSwlM6RzU=
+charm.land/lipgloss/v2 v2.0.3/go.mod h1:7myLU9iG/3xluAWzpY/fSxYYHCgoKTie7laxk6ATwXA=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@@ -399,6 +401,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/ClickHouse/clickhouse-go-linter v1.2.0 h1:zbm174up3hTKjp0wKZVnTzRiG7tSF5XZF0FJG/MuCBI=
+github.com/ClickHouse/clickhouse-go-linter v1.2.0/go.mod h1:pLorS7ffPTfuUV9M0SJgfHA/h/WQPQUk2FWG9x74cQ4=
github.com/Code-Hex/go-generics-cache v1.5.1 h1:6vhZGc5M7Y/YD8cIUcY8kcuQLB4cHR7U+0KMqAA0KcU=
github.com/Code-Hex/go-generics-cache v1.5.1/go.mod h1:qxcC9kRVrct9rHeiYpFWSoW1vxyillCVzX13KZG8dl4=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
@@ -426,8 +430,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapp
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
github.com/Kunde21/markdownfmt/v3 v3.1.0 h1:KiZu9LKs+wFFBQKhrZJrFZwtLnCCWJahL+S+E/3VnM0=
github.com/Kunde21/markdownfmt/v3 v3.1.0/go.mod h1:tPXN1RTyOzJwhfHoon9wUr4HGYmWgVxSQN6VBJDkrVc=
-github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
-github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
+github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE=
+github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/MirrexOne/unqueryvet v1.5.4 h1:38QOxShO7JmMWT+eCdDMbcUgGCOeJphVkzzRgyLJgsQ=
@@ -449,8 +453,8 @@ github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8v
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
-github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=
-github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
+github.com/alecthomas/chroma/v2 v2.24.1 h1:m5ffpfZbIb++k8AqFEKy9uVgY12xIQtBsQlc6DfZJQM=
+github.com/alecthomas/chroma/v2 v2.24.1/go.mod h1:l+ohZ9xRXIbGe7cIW+YZgOGbvuVLjMps/FYN/CwuabI=
github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU=
github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E=
github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=
@@ -501,10 +505,10 @@ github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJ
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/ashanbrown/forbidigo/v2 v2.3.0 h1:OZZDOchCgsX5gvToVtEBoV2UWbFfI6RKQTir2UZzSxo=
-github.com/ashanbrown/forbidigo/v2 v2.3.0/go.mod h1:5p6VmsG5/1xx3E785W9fouMxIOkvY2rRV9nMdWadd6c=
-github.com/ashanbrown/makezero/v2 v2.1.0 h1:snuKYMbqosNokUKm+R6/+vOPs8yVAi46La7Ck6QYSaE=
-github.com/ashanbrown/makezero/v2 v2.1.0/go.mod h1:aEGT/9q3S8DHeE57C88z2a6xydvgx8J5hgXIGWgo0MY=
+github.com/ashanbrown/forbidigo/v2 v2.3.1 h1:KAZijvQ7zeIBKbhikT4jCm0TLYXC4u78bTiLh/8JROI=
+github.com/ashanbrown/forbidigo/v2 v2.3.1/go.mod h1:2QDkLTzU6TV937eFROamXrW92M3paehdae4HCDCOZCM=
+github.com/ashanbrown/makezero/v2 v2.2.1 h1:A7uU8dgB1PA9aelTxHMfHIQ8Qev8AB3JLxJUBUsejqM=
+github.com/ashanbrown/makezero/v2 v2.2.1/go.mod h1:aEGT/9q3S8DHeE57C88z2a6xydvgx8J5hgXIGWgo0MY=
github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY=
github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
github.com/aws/aws-sdk-go-v2/config v1.32.13 h1:5KgbxMaS2coSWRrx9TX/QtWbqzgQkOdEa3sZPhBhCSg=
@@ -572,8 +576,8 @@ github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ
github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k=
github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ=
github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg=
-github.com/bombsimon/wsl/v5 v5.6.0 h1:4z+/sBqC5vUmSp1O0mS+czxwH9+LKXtCWtHH9rZGQL8=
-github.com/bombsimon/wsl/v5 v5.6.0/go.mod h1:Uqt2EfrMj2NV8UGoN1f1Y3m0NpUVCsUdrNCdet+8LvU=
+github.com/bombsimon/wsl/v5 v5.8.0 h1:JTkyfs4yl8SPejrCF2GdABXE+mO1WvM7iUYzRWlsxDs=
+github.com/bombsimon/wsl/v5 v5.8.0/go.mod h1:AbOLsulgkqP4ZnitHf9gwPtCOGlrzkk0jb0uNxRSY0o=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/brancz/gojsontoyaml v0.1.0 h1:SdzR3+BCVOqaI42nFGTeaB7/2DgDM4fhuvRLqxatA8M=
@@ -582,8 +586,8 @@ github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE=
github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE=
github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg=
github.com/breml/errchkjson v0.4.1/go.mod h1:a23OvR6Qvcl7DG/Z4o0el6BRAjKnaReoPQFciAl9U3s=
-github.com/butuzov/ireturn v0.4.0 h1:+s76bF/PfeKEdbG8b54aCocxXmi0wvYdOVsWxVO7n8E=
-github.com/butuzov/ireturn v0.4.0/go.mod h1:ghI0FrCmap8pDWZwfPisFD1vEc56VKH4NpQUxDHta70=
+github.com/butuzov/ireturn v0.4.1 h1:vWb3NO4t77iku/sjCQ/2pHTQeOmxEhjIriJqRLg1Y+I=
+github.com/butuzov/ireturn v0.4.1/go.mod h1:q+DXKzTDV5guNuXLnIab9fKXizTn2miZHLhxH7V/GB4=
github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc=
github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI=
github.com/bwplotka/mdox v0.9.1-0.20260318034157-e88e0a8655a0 h1:ddpDQUwOAenI545bWVOZMAxB27q6HLuM+i6KqAOTNw4=
@@ -604,18 +608,20 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charithe/durationcheck v0.0.11 h1:g1/EX1eIiKS57NTWsYtHDZ/APfeXKhye1DidBcABctk=
github.com/charithe/durationcheck v0.0.11/go.mod h1:x5iZaixRNl8ctbM+3B2RrPG5t856TxRyVQEnbIEM2X4=
-github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
-github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
+github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q=
+github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q=
github.com/charmbracelet/glamour v0.6.0 h1:wi8fse3Y7nfcabbbDuwolqTqMQPMnVPeZhDM273bISc=
github.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8om2538k9ITBxOc=
-github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
-github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
-github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ=
-github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
-github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
-github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
-github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
-github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
+github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318 h1:OqDqxQZliC7C8adA7KjelW3OjtAxREfeHkNcd66wpeI=
+github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318/go.mod h1:Y6kE2GzHfkyQQVCSL9r2hwokSrIlHGzZG+71+wDYSZI=
+github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI=
+github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ=
+github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
+github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
+github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
+github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
+github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM=
+github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k=
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
@@ -638,6 +644,10 @@ github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5
github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00=
github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
+github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
+github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
+github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -695,8 +705,8 @@ github.com/digitalocean/godo v1.178.0/go.mod h1:xQsWpVCCbkDrWisHA72hPzPlnC+4W5w/
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
-github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
-github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8=
+github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
@@ -778,10 +788,10 @@ github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03D
github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
-github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
-github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
-github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
-github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
+github.com/fsnotify/fsnotify v1.10.0 h1:Xx/5Ydg9CeBDX/wi4VJqStNtohYjitZhhlHt4h3St1M=
+github.com/fsnotify/fsnotify v1.10.0/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
+github.com/fxamacker/cbor/v2 v2.9.1 h1:2rWm8B193Ll4VdjsJY28jxs70IdDsHRWgQYAI80+rMQ=
+github.com/fxamacker/cbor/v2 v2.9.1/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
@@ -821,8 +831,8 @@ github.com/go-openapi/analysis v0.25.0 h1:EnjAq1yO8wEO9HbPmY8vLPEIkdZuuFhCAKBPvC
github.com/go-openapi/analysis v0.25.0/go.mod h1:5WFTRE43WLkPG9r9OtlMfqkkvUTYLVVCIxLlEpyF8kE=
github.com/go-openapi/errors v0.22.7 h1:JLFBGC0Apwdzw3484MmBqspjPbwa2SHvpDm0u5aGhUA=
github.com/go-openapi/errors v0.22.7/go.mod h1://QW6SD9OsWtH6gHllUCddOXDL0tk0ZGNYHwsw4sW3w=
-github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA=
-github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0=
+github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4=
+github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY=
github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE=
github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=
github.com/go-openapi/loads v0.23.3 h1:g5Xap1JfwKkUnZdn+S0L3SzBDpcTIYzZ5Qaag0YDkKQ=
@@ -831,36 +841,36 @@ github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfD
github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ=
github.com/go-openapi/strfmt v0.26.1 h1:7zGCHji7zSYDC2tCXIusoxYQz/48jAf2q+sF6wXTG+c=
github.com/go-openapi/strfmt v0.26.1/go.mod h1:Zslk5VZPOISLwmWTMBIS7oiVFem1o1EI6zULY8Uer7Y=
-github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU=
-github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA=
-github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c=
-github.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
-github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g=
-github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k=
-github.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk=
-github.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc=
-github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo=
-github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU=
-github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo=
-github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo=
-github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU=
-github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g=
-github.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw=
-github.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY=
-github.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU=
-github.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14=
-github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M=
-github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII=
-github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E=
-github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc=
-github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ=
-github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ=
-github.com/go-openapi/testify/enable/yaml/v2 v2.4.1 h1:NZOrZmIb6PTv5LTFxr5/mKV/FjbUzGE7E6gLz7vFoOQ=
-github.com/go-openapi/testify/enable/yaml/v2 v2.4.1/go.mod h1:r7dwsujEHawapMsxA69i+XMGZrQ5tRauhLAjV/sxg3Q=
-github.com/go-openapi/testify/v2 v2.4.1 h1:zB34HDKj4tHwyUQHrUkpV0Q0iXQ6dUCOQtIqn8hE6Iw=
-github.com/go-openapi/testify/v2 v2.4.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
+github.com/go-openapi/swag v0.26.0 h1:GVDXCmfvhfu1BxiHo8/FA+BbKmhecHnG3varjON5/RI=
+github.com/go-openapi/swag v0.26.0/go.mod h1:82g3193sZJRbocs7bNCqGfIgq8pkuwVwCfhKIRlEQF0=
+github.com/go-openapi/swag/cmdutils v0.26.0 h1:iowihOcvq7y4egO8cOq0dmfohz6wfeQ63U1EnuhO2TU=
+github.com/go-openapi/swag/cmdutils v0.26.0/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM=
+github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I=
+github.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE=
+github.com/go-openapi/swag/fileutils v0.26.0 h1:WJoPRvsA7QRiiWluowkLJa9jaYR7FCuxmDvnCgaRRxU=
+github.com/go-openapi/swag/fileutils v0.26.0/go.mod h1:0WDJ7lp67eNjPMO50wAWYlKvhOb6CQ37rzR7wrgI8Tc=
+github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w=
+github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M=
+github.com/go-openapi/swag/jsonutils v0.26.0 h1:FawFML2iAXsPqmERscuMPIHmFsoP1tOqWkxBaKNMsnA=
+github.com/go-openapi/swag/jsonutils v0.26.0/go.mod h1:2VmA0CJlyFqgawOaPI9psnjFDqzyivIqLYN34t9p91E=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0 h1:apqeINu/ICHouqiRZbyFvuDge5jCmmLTqGQ9V95EaOM=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0/go.mod h1:AyM6QT8uz5IdKxk5akv0y6u4QvcL9GWERt0Jx/F/R8Y=
+github.com/go-openapi/swag/loading v0.26.0 h1:Apg6zaKhCJurpJer0DCxq99qwmhFddBhaMX7kilDcko=
+github.com/go-openapi/swag/loading v0.26.0/go.mod h1:dBxQ/6V2uBaAQdevN18VELE6xSpJWZxLX4txe12JwDg=
+github.com/go-openapi/swag/mangling v0.26.0 h1:Du2YC4YLA/Y5m/YKQd7AnY5qq0wRKSFZTTt8ktFaXcQ=
+github.com/go-openapi/swag/mangling v0.26.0/go.mod h1:jifS7W9vbg+pw63bT+GI53otluMQL3CeemuyCHKwVx0=
+github.com/go-openapi/swag/netutils v0.26.0 h1:CmZp+ZT7HrmFwrC3GdGsXBq2+42T1bjKBapcqVpIs3c=
+github.com/go-openapi/swag/netutils v0.26.0/go.mod h1:5iK+Ok3ZohWWex1C50BFTPexi03UaPwjW4Oj8kgrpwo=
+github.com/go-openapi/swag/stringutils v0.26.0 h1:qZQngLxs5s7SLijc3N2ZO+fUq2o8LjuWAASSrJuh+xg=
+github.com/go-openapi/swag/stringutils v0.26.0/go.mod h1:sWn5uY+QIIspwPhvgnqJsH8xqFT2ZbYcvbcFanRyhFE=
+github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFuuyQIKYybfq4=
+github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE=
+github.com/go-openapi/swag/yamlutils v0.26.0 h1:H7O8l/8NJJQ/oiReEN+oMpnGMyt8G0hl460nRZxhLMQ=
+github.com/go-openapi/swag/yamlutils v0.26.0/go.mod h1:1evKEGAtP37Pkwcc7EWMF0hedX0/x3Rkvei2wtG/TbU=
+github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0=
+github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE=
+github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4=
+github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
github.com/go-openapi/validate v0.25.2 h1:12NsfLAwGegqbGWr2CnvT65X/Q2USJipmJ9b7xDJZz0=
github.com/go-openapi/validate v0.25.2/go.mod h1:Pgl1LpPPGFnZ+ys4/hTlDiRYQdI1ocKypgE+8Q8BLfY=
github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
@@ -976,14 +986,14 @@ github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golangci/asciicheck v0.5.0 h1:jczN/BorERZwK8oiFBOGvlGPknhvq0bjnysTj4nUfo0=
github.com/golangci/asciicheck v0.5.0/go.mod h1:5RMNAInbNFw2krqN6ibBxN/zfRFa9S6tA1nPdM0l8qQ=
-github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 h1:WUvBfQL6EW/40l6OmeSBYQJNSif4O11+bmWEz+C7FYw=
-github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E=
+github.com/golangci/dupl v0.0.0-20260401084720-c99c5cf5c202 h1:CbTB8KpqnViI6lIXxp03Oclc4VFHi3K4BWC1TacsZ+A=
+github.com/golangci/dupl v0.0.0-20260401084720-c99c5cf5c202/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E=
github.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarogrvjO9AfiW3B4U=
github.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss=
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE=
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY=
-github.com/golangci/golangci-lint/v2 v2.11.4 h1:GK+UlZBN5y7rh2PBnHA93XLSX6RaF7uhzJQ3JwU1wuA=
-github.com/golangci/golangci-lint/v2 v2.11.4/go.mod h1:ODQDCASMA3VqfZYIbbQLpTRTzV7O/vjmIRF6u8NyFwI=
+github.com/golangci/golangci-lint/v2 v2.12.1 h1:Rr07Ps/u+kvQqSO4L026WOSVvOlMU+RZTa/lossFaJA=
+github.com/golangci/golangci-lint/v2 v2.12.1/go.mod h1:e/wBh0xvA13ag/OWByUmvjc9oYPtcKGpXycldJbc7t0=
github.com/golangci/golines v0.15.0 h1:Qnph25g8Y1c5fdo1X7GaRDGgnMHgnxh4Gk4VfPTtRx0=
github.com/golangci/golines v0.15.0/go.mod h1:AZjXd23tbHMpowhtnGlj9KCNsysj72aeZVVHnVcZx10=
github.com/golangci/misspell v0.8.0 h1:qvxQhiE2/5z+BVRo1kwYA8yGz+lOlu5Jfvtx2b04Jbg=
@@ -992,6 +1002,8 @@ github.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3H
github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw=
github.com/golangci/revgrep v0.8.0 h1:EZBctwbVd0aMeRnNUsFogoyayvKHyxlV3CdUA46FX2s=
github.com/golangci/revgrep v0.8.0/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k=
+github.com/golangci/rowserrcheck v0.0.0-20260419091836-c5f79b8a11ba h1:lqtcnSMDuuJdu/LrKWi5RJzpSNLOJXYe/nzQutTI5kg=
+github.com/golangci/rowserrcheck v0.0.0-20260419091836-c5f79b8a11ba/go.mod h1:sCBNcpRmhJCtbFGz49+IM3ETTFf7QdJ30AeYCd43NKk=
github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e h1:ai0EfmVYE2bRA5htgAG9r7s3tHsfjIhN98WshBTJ9jM=
github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e/go.mod h1:Vrn4B5oR9qRwM+f54koyeH3yzphlecwERs0el27Fr/s=
github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e h1:gD6P7NEo7Eqtt0ssnqSJNNndxe69DOQ24A5h7+i3KpM=
@@ -1191,8 +1203,8 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4=
-github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA=
+github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
@@ -1227,10 +1239,8 @@ github.com/ionos-cloud/sdk-go/v6 v6.3.6/go.mod h1:nUGHP4kZHAZngCVr4v6C8nuargFrtv
github.com/jarcoal/httpmock v1.4.1 h1:0Ju+VCFuARfFlhVXFc2HxlcQkfB+Xq12/EotHko+x2A=
github.com/jarcoal/httpmock v1.4.1/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0=
github.com/jawher/mow.cli v1.1.0/go.mod h1:aNaQlc7ozF3vw6IJ2dHjp2ZFiA4ozMIYY6PyuRJwlUg=
-github.com/jgautheron/goconst v1.8.2 h1:y0XF7X8CikZ93fSNT6WBTb/NElBu9IjaY7CCYQrCMX4=
-github.com/jgautheron/goconst v1.8.2/go.mod h1:A0oxgBCHy55NQn6sYpO7UdnA9p+h7cPtoOZUmvNIako=
-github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs=
-github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
+github.com/jgautheron/goconst v1.10.0 h1:Ptt+OoE4NaEWKhLrWrrN3IpZdGLiqaf7WLnEX/iv4Jw=
+github.com/jgautheron/goconst v1.10.0/go.mod h1:0p+wv1lFOiUr0IlNNT1nrm6+8DB8u2sU6KHGzFRXHDc=
github.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgYB8=
github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
@@ -1315,8 +1325,9 @@ github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84Yrj
github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=
github.com/linode/linodego v1.66.0 h1:rK8QJFaV53LWOEJvb/evhTg/dP5ElvtuZmx4iv4RJds=
github.com/linode/linodego v1.66.0/go.mod h1:12ykGs9qsvxE+OU3SXuW2w+DTruWF35FPlXC7gGk2tU=
-github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4=
+github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o=
@@ -1329,8 +1340,8 @@ github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/manuelarte/embeddedstructfieldcheck v0.4.0 h1:3mAIyaGRtjK6EO9E73JlXLtiy7ha80b2ZVGyacxgfww=
github.com/manuelarte/embeddedstructfieldcheck v0.4.0/go.mod h1:z8dFSyXqp+fC6NLDSljRJeNQJJDWnY7RoWFzV3PC6UM=
-github.com/manuelarte/funcorder v0.5.0 h1:llMuHXXbg7tD0i/LNw8vGnkDTHFpTnWqKPI85Rknc+8=
-github.com/manuelarte/funcorder v0.5.0/go.mod h1:Yt3CiUQthSBMBxjShjdXMexmzpP8YGvGLjrxJNkO2hA=
+github.com/manuelarte/funcorder v0.6.0 h1:0hBngc4fa1IgNiI65A7sFGkMvoMCc878RjqB5V7rWP0=
+github.com/manuelarte/funcorder v0.6.0/go.mod h1:id3NDhXdQBmeqXH7eVC6Z89xS6JxvZ8kF9xUxpArU/g=
github.com/maratori/testableexamples v1.0.1 h1:HfOQXs+XgfeRBJ+Wz0XfH+FHnoY9TVqL6Fcevpzy4q8=
github.com/maratori/testableexamples v1.0.1/go.mod h1:XE2F/nQs7B9N08JgyRmdGjYVGqxWwClLPCGSQhXQSrQ=
github.com/maratori/testpackage v1.1.2 h1:ffDSh+AgqluCLMXhM19f/cpvQAKygKAJXFl9aUjmbqs=
@@ -1361,8 +1372,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
-github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw=
+github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
@@ -1415,6 +1426,8 @@ github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKH
github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U=
github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ=
github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw=
+github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
+github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
@@ -1447,10 +1460,10 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
-github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=
-github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
-github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
-github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
+github.com/onsi/ginkgo/v2 v2.28.2 h1:DTrMfpqxiNUyQ3Y0zhn1n3cOO2euFgQPYIpkWwxVFps=
+github.com/onsi/ginkgo/v2 v2.28.2/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
+github.com/onsi/gomega v1.40.0 h1:Vtol0e1MghCD2ZVIilPDIg44XSL9l2QAn8ZNaljWcJc=
+github.com/onsi/gomega v1.40.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0 h1:CiTjQE/Hh5xK2t56ogrDK4nl0+tJPNmASCs4zEYZ/xU=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0/go.mod h1:WUFkzTiOpt7EYyL67gv1GOf3RD8qKWGtin3lY9LYzW4=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0 h1:1TLg6YrS3Au6F7xw3ws2Njbwj13IMqPplvGFi+18fWs=
@@ -1477,8 +1490,8 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
-github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
+github.com/pelletier/go-toml/v2 v2.3.0 h1:k59bC/lIZREW0/iVaQR8nDHxVq8OVlIzYCOJf421CaM=
+github.com/pelletier/go-toml/v2 v2.3.0/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
@@ -1571,6 +1584,8 @@ github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfF
github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk=
github.com/ryancurrah/gomodguard v1.4.1 h1:eWC8eUMNZ/wM/PWuZBv7JxxqT5fiIKSIyTvjb7Elr+g=
github.com/ryancurrah/gomodguard v1.4.1/go.mod h1:qnMJwV1hX9m+YJseXEBhd2s90+1Xn6x9dLz11ualI1I=
+github.com/ryancurrah/gomodguard/v2 v2.1.0 h1:iIIARHe7Fsp10LY5utfMmYA++hkVuKsMFGDzxnVcijU=
+github.com/ryancurrah/gomodguard/v2 v2.1.0/go.mod h1:ryDqr6as4otkNbUp/U0m7zAsxGpwcJ9NtL6mvy9Zzdw=
github.com/ryanrolds/sqlclosecheck v0.6.0 h1:pEyL9okISdg1F1SEpJNlrEotkTGerv5BMk7U4AG0eVg=
github.com/ryanrolds/sqlclosecheck v0.6.0/go.mod h1:xyX16hsDaCMXHrMJ3JMzGf5OpDfHTOTTQrT7HOFUmeU=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
@@ -1588,14 +1603,12 @@ github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36 h1:ObX9hZmK+VmijreZO/8x9pQ8/P
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36/go.mod h1:LEsDu4BubxK7/cWhtlQWfuxwL4rf/2UEpxXz1o1EMtM=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08 h1:AoLtJX4WUtZkhhUUMFy3GgecAALp/Mb4S1iyQOA2s0U=
-github.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08/go.mod h1:+XLCJiRE95ga77XInNELh2M6zQP+PdqiT9Zpm0D9Wpk=
+github.com/securego/gosec/v2 v2.26.1 h1:gdkttGhQFVehqRJ8grKH4DrpqM/QlPKNHBnl8QgcEC4=
+github.com/securego/gosec/v2 v2.26.1/go.mod h1:57UW4p0uoP3kxoTkhoo3axLdVAi+OWrLg/Ax/kdqtPE=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/shoenig/test v1.12.2 h1:ZVT8NeIUwGWpZcKaepPmFMoNQ3sVpxvqUh/MAqwFiJI=
github.com/shoenig/test v1.12.2/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI=
-github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
-github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
@@ -1605,8 +1618,8 @@ github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+W
github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4=
github.com/sonatard/noctx v0.5.1 h1:wklWg9c9ZYugOAk7qG4yP4PBrlQsmSLPTvW1K4PRQMs=
github.com/sonatard/noctx v0.5.1/go.mod h1:64XdbzFb18XL4LporKXp8poqZtPKbCrqQ402CV+kJas=
-github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=
-github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
+github.com/sourcegraph/go-diff v0.8.0 h1:ipIyu4cTsLbIrln4l0qtHA3r0a7gyK4ntKjtQytHhvY=
+github.com/sourcegraph/go-diff v0.8.0/go.mod h1:hWlcO7Al+UZStZAP8rBumHpCK5ZHQ5BXsMls8p4+F5E=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
@@ -1672,16 +1685,16 @@ github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA
github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag=
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
-github.com/tetafro/godot v1.5.4 h1:u1ww+gqpRLiIA16yF2PV1CV1n/X3zhyezbNXC3E14Sg=
-github.com/tetafro/godot v1.5.4/go.mod h1:eOkMrVQurDui411nBY2FA05EYH01r14LuWY/NrVDVcU=
+github.com/tetafro/godot v1.5.6 h1:IEkrFCwXaYHlOn4mGzGS3F3dkP6m9t0jpwqBFPIkKiA=
+github.com/tetafro/godot v1.5.6/go.mod h1:eOkMrVQurDui411nBY2FA05EYH01r14LuWY/NrVDVcU=
github.com/theckman/yacspin v0.13.12 h1:CdZ57+n0U6JMuh2xqjnjRq5Haj6v1ner2djtLQRzJr4=
github.com/theckman/yacspin v0.13.12/go.mod h1:Rd2+oG2LmQi5f3zC3yeZAOl245z8QOvrH4OPOJNZxLg=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
-github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 h1:9LPGD+jzxMlnk5r6+hJnar67cgpDIz/iyD+rfl5r2Vk=
-github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460=
+github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 h1:SiHe5XLTn9sFWJ5pBwJ5FN/4j34q9ZlOAD//kMoMYp0=
+github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4/go.mod h1:sDHLK7rb/59v/ZxZ7KtymgcoxuUMxjXq8gtu9VMOK8M=
github.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M=
github.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8=
github.com/tomarrell/wrapcheck/v2 v2.12.0 h1:H/qQ1aNWz/eeIhxKAFvkfIA+N7YDvq6TWVFL27Of9is=
@@ -1736,8 +1749,8 @@ go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ=
go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28=
go-simpler.org/musttag v0.14.0 h1:XGySZATqQYSEV3/YTy+iX+aofbZZllJaqwFWs+RTtSo=
go-simpler.org/musttag v0.14.0/go.mod h1:uP8EymctQjJ4Z1kUnjX0u2l60WfUdQxCwSNKzE1JEOE=
-go-simpler.org/sloglint v0.11.1 h1:xRbPepLT/MHPTCA6TS/wNfZrDzkGvCCqUv4Bdwc3H7s=
-go-simpler.org/sloglint v0.11.1/go.mod h1:2PowwiCOK8mjiF+0KGifVOT8ZsCNiFzvfyJeJOIt8MQ=
+go-simpler.org/sloglint v0.12.0 h1:UzWDlLWNE5FLqsvyq3tWYHuQMbqrervOhT8qPl4Mmw4=
+go-simpler.org/sloglint v0.12.0/go.mod h1:jBjjC2bm8rYrs88oTRlFX497kWjJsyZWYoNaXkGRI6I=
go.augendre.info/arangolint v0.4.0 h1:xSCZjRoS93nXazBSg5d0OGCi9APPLNMmmLrC995tR50=
go.augendre.info/arangolint v0.4.0/go.mod h1:l+f/b4plABuFISuKnTGD4RioXiCCgghv2xqst/xOvAA=
go.augendre.info/fatcontext v0.9.0 h1:Gt5jGD4Zcj8CDMVzjOJITlSb9cEch54hjRRlN3qDojE=
@@ -1940,8 +1953,8 @@ golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0Y
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
-golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
-golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
+golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
+golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -2018,8 +2031,8 @@ golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
-golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
-golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
+golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
+golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -2115,8 +2128,8 @@ golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
-golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
-golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
+golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
+golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -2317,8 +2330,8 @@ golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
-golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
+golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -2355,8 +2368,8 @@ golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
-golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
-golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
+golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
+golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -2389,8 +2402,8 @@ golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
-golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
-golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
+golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
+golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -2483,8 +2496,8 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
-golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
-golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
+golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
+golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
@@ -2920,8 +2933,8 @@ google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojt
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
-google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
-google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
+google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -2963,28 +2976,28 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
honnef.co/go/tools v0.7.0 h1:w6WUp1VbkqPEgLz4rkBzH/CSU6HkoqNLp6GstyTx3lU=
honnef.co/go/tools v0.7.0/go.mod h1:pm29oPxeP3P82ISxZDgIYeOaf9ta6Pi0EWvCFoLG2vc=
-k8s.io/api v0.35.3 h1:pA2fiBc6+N9PDf7SAiluKGEBuScsTzd2uYBkA5RzNWQ=
-k8s.io/api v0.35.3/go.mod h1:9Y9tkBcFwKNq2sxwZTQh1Njh9qHl81D0As56tu42GA4=
-k8s.io/apiextensions-apiserver v0.35.2 h1:iyStXHoJZsUXPh/nFAsjC29rjJWdSgUmG1XpApE29c0=
-k8s.io/apiextensions-apiserver v0.35.2/go.mod h1:OdyGvcO1FtMDWQ+rRh/Ei3b6X3g2+ZDHd0MSRGeS8rU=
-k8s.io/apimachinery v0.35.3 h1:MeaUwQCV3tjKP4bcwWGgZ/cp/vpsRnQzqO6J6tJyoF8=
-k8s.io/apimachinery v0.35.3/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
-k8s.io/apiserver v0.35.2 h1:rb52v0CZGEL0FkhjS+I6jHflAp7fZ4MIaKcEHX7wmDk=
-k8s.io/apiserver v0.35.2/go.mod h1:CROJUAu0tfjZLyYgSeBsBan2T7LUJGh0ucWwTCSSk7g=
-k8s.io/client-go v0.35.3 h1:s1lZbpN4uI6IxeTM2cpdtrwHcSOBML1ODNTCCfsP1pg=
-k8s.io/client-go v0.35.3/go.mod h1:RzoXkc0mzpWIDvBrRnD+VlfXP+lRzqQjCmKtiwZ8Q9c=
-k8s.io/code-generator v0.35.2 h1:3874swbO2c26VWTf6lKD4NWGyHIfyBeTCk7caCG3TuU=
-k8s.io/code-generator v0.35.2/go.mod h1:id4XLCm0yAQq5nlvyfAKibMOKnMjzlesAwGw6kM3Adc=
-k8s.io/component-base v0.35.2 h1:btgR+qNrpWuRSuvWSnQYsZy88yf5gVwemvz0yw79pGc=
-k8s.io/component-base v0.35.2/go.mod h1:B1iBJjooe6xIJYUucAxb26RwhAjzx0gHnqO9htWIX+0=
+k8s.io/api v0.36.0 h1:SgqDhZzHdOtMk40xVSvCXkP9ME0H05hPM3p9AB1kL80=
+k8s.io/api v0.36.0/go.mod h1:m1LVrGPNYax5NBHdO+QuAedXyuzTt4RryI/qnmNvs34=
+k8s.io/apiextensions-apiserver v0.36.0 h1:Wt7E8J+VBCbj4FjiBfDTK/neXDDjyJVJc7xfuOHImZ0=
+k8s.io/apiextensions-apiserver v0.36.0/go.mod h1:kGDjH0msuiIB3tgsYRV0kS9GqpMYMUsQ3GHv7TApyug=
+k8s.io/apimachinery v0.36.0 h1:jZyPzhd5Z+3h9vJLt0z9XdzW9VzNzWAUw+P1xZ9PXtQ=
+k8s.io/apimachinery v0.36.0/go.mod h1:FklypaRJt6n5wUIwWXIP6GJlIpUizTgfo1T/As+Tyxc=
+k8s.io/apiserver v0.36.0 h1:Jg5OFAENUACByUCg15CmhZAYrr5ZyJ+jodyA1mHl3YE=
+k8s.io/apiserver v0.36.0/go.mod h1:mHvwdHf+qKEm+1/hYm756SV+oREOKSPnsjagOpx6Vho=
+k8s.io/client-go v0.36.0 h1:pOYi7C4RHChYjMiHpZSpSbIM6ZxVbRXBy7CuiIwqA3c=
+k8s.io/client-go v0.36.0/go.mod h1:ZKKcpwF0aLYfkHFCjillCKaTK/yBkEDHTDXCFY6AS9Y=
+k8s.io/code-generator v0.36.0 h1:XWAkrhnArm0VWMmSFO7kyB+wE2LROwep7hEH0GPGkqA=
+k8s.io/code-generator v0.36.0/go.mod h1:Tr2UhfBRdlyRoadfob9aPCmmGe8PUs5XPK9MEJ2nx+w=
+k8s.io/component-base v0.36.0 h1:hFjEktssxiJhrK1zfybkH4kJOi8iZuF+mIDCqS5+jRo=
+k8s.io/component-base v0.36.0/go.mod h1:JZvIfcNHk+uck+8LhJzhSBtydWXaZNQwX2OdL+Mnwsk=
k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b h1:gMplByicHV/TJBizHd9aVEsTYoJBnnUAT5MHlTkbjhQ=
k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM=
k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
-k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg=
-k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0=
-k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=
-k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
+k8s.io/kube-openapi v0.0.0-20260427204847-8949caaa1199 h1:sWu4Td5mgJlwunsUydnhKEAfNUHM7hm1wfKEQmD7G5c=
+k8s.io/kube-openapi v0.0.0-20260427204847-8949caaa1199/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0=
+k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 h1:kBawHLSnx/mYHmRnNUf9d4CpjREbeZuxoSGOX/J+aYM=
+k8s.io/utils v0.0.0-20260319190234-28399d86e0b5/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
@@ -3024,15 +3037,15 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
-sigs.k8s.io/controller-tools v0.20.1 h1:gkfMt9YodI0K85oT8rVi80NTXO/kDmabKR5Ajn5GYxs=
-sigs.k8s.io/controller-tools v0.20.1/go.mod h1:b4qPmjGU3iZwqn34alUU5tILhNa9+VXK+J3QV0fT/uU=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
+sigs.k8s.io/controller-tools v0.21.0 h1:KXDQza3bgjlPY6xLR63tI/40gzjhyUAvkCrwzd2/6cs=
+sigs.k8s.io/controller-tools v0.21.0/go.mod h1:DLIypi3Q2+azVAP8jr/mHXJgveYYHFjhnNOUuBJ10JE=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
-sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8=
-sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
+sigs.k8s.io/structured-merge-diff/v6 v6.4.0 h1:qmp2e3ZfFi1/jJbDGpD4mt3wyp6PE1NfKHCYLqgNQJo=
+sigs.k8s.io/structured-merge-diff/v6 v6.4.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
diff --git a/test/e2e/alertmanager_test.go b/test/e2e/alertmanager_test.go
index 45fe0261bcf..622ad351cef 100644
--- a/test/e2e/alertmanager_test.go
+++ b/test/e2e/alertmanager_test.go
@@ -247,7 +247,7 @@ func testAMStorageUpdate(t *testing.T) {
},
},
Spec: corev1.PersistentVolumeClaimSpec{
- StorageClassName: ptr.To("unknown-storage-class"),
+ StorageClassName: new("unknown-storage-class"),
Resources: corev1.VolumeResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("200Mi"),
@@ -400,7 +400,7 @@ func testAMClusterGossipSilences(t *testing.T) {
},
Key: "key.pem",
},
- ClientAuthType: ptr.To("VerifyClientCertIfGiven"),
+ ClientAuthType: new("VerifyClientCertIfGiven"),
},
ClientTLS: monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
@@ -426,7 +426,7 @@ func testAMClusterGossipSilences(t *testing.T) {
Key: "key.pem",
},
// Since we cannot verify hostname in the cert.
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
},
},
},
@@ -1076,6 +1076,18 @@ func testAlertmanagerConfigCRD(t *testing.T) {
_, err = framework.KubeClient.CoreV1().Secrets(configNs).Create(context.Background(), webexAPITokenSecret, metav1.CreateOptions{})
require.NoError(t, err)
+ msteamsWebhookURL := "https://msteams.webhook.url"
+ msteamsSecret := &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "msteams",
+ },
+ Data: map[string][]byte{
+ "webhook-url": []byte(msteamsWebhookURL),
+ },
+ }
+ _, err = framework.KubeClient.CoreV1().Secrets(configNs).Create(context.Background(), msteamsSecret, metav1.CreateOptions{})
+ require.NoError(t, err)
+
// A valid AlertmanagerConfig resource with many receivers.
configCR := &monitoringv1alpha1.AlertmanagerConfig{
ObjectMeta: metav1.ObjectMeta{
@@ -1117,7 +1129,7 @@ func testAlertmanagerConfigCRD(t *testing.T) {
{
Type: "type",
Text: "text",
- Name: ptr.To("my-action"),
+ Name: new("my-action"),
ConfirmField: &monitoringv1alpha1.SlackConfirmationField{
Text: "text",
},
@@ -1131,7 +1143,7 @@ func testAlertmanagerConfigCRD(t *testing.T) {
},
}},
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{{
- URL: ptr.To("http://test.url"),
+ URL: new("http://test.url"),
}},
WeChatConfigs: []monitoringv1alpha1.WeChatConfig{{
APISecret: &corev1.SecretKeySelector{
@@ -1140,15 +1152,15 @@ func testAlertmanagerConfigCRD(t *testing.T) {
},
Key: testingSecretKey,
},
- CorpID: ptr.To("testingCorpID"),
+ CorpID: new("testingCorpID"),
}},
EmailConfigs: []monitoringv1alpha1.EmailConfig{{
SendResolved: func(b bool) *bool {
return &b
}(true),
- Smarthost: ptr.To("example.com:25"),
- From: ptr.To("admin@example.com"),
- To: ptr.To("test@example.com"),
+ Smarthost: new("example.com:25"),
+ From: new("admin@example.com"),
+ To: new("test@example.com"),
AuthPassword: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: testingSecret,
@@ -1167,7 +1179,7 @@ func testAlertmanagerConfigCRD(t *testing.T) {
},
// HTML field with an empty string must appear as-is in the generated configuration.
// See https://github.com/prometheus-operator/prometheus-operator/issues/5421
- HTML: ptr.To(""),
+ HTML: new(""),
}},
VictorOpsConfigs: []monitoringv1alpha1.VictorOpsConfig{{
APIKey: &corev1.SecretKeySelector{
@@ -1204,7 +1216,7 @@ func testAlertmanagerConfigCRD(t *testing.T) {
}},
SNSConfigs: []monitoringv1alpha1.SNSConfig{
{
- ApiURL: ptr.To("https://sns.us-east-2.amazonaws.com"),
+ ApiURL: new("https://sns.us-east-2.amazonaws.com"),
Sigv4: &monitoringv1.Sigv4{
Region: "us-east-2",
AccessKey: &corev1.SecretKeySelector{
@@ -1220,19 +1232,13 @@ func testAlertmanagerConfigCRD(t *testing.T) {
Key: testingSecretKey,
},
},
- TopicARN: ptr.To("test-topicARN"),
+ TopicARN: new("test-topicARN"),
},
},
WebexConfigs: []monitoringv1alpha1.WebexConfig{{
- APIURL: func() *monitoringv1alpha1.URL {
- res := monitoringv1alpha1.URL("https://webex.api.url")
- return &res
- }(),
- RoomID: "testingRoomID",
- Message: func() *string {
- res := "testingMessage"
- return &res
- }(),
+ APIURL: ptr.To(monitoringv1alpha1.URL("https://webex.api.url")),
+ RoomID: "testingRoomID",
+ Message: new("testingMessage"),
HTTPConfig: &monitoringv1alpha1.HTTPConfig{
Authorization: &monitoringv1.SafeAuthorization{
Type: "Bearer",
@@ -1245,6 +1251,15 @@ func testAlertmanagerConfigCRD(t *testing.T) {
},
},
}},
+ MSTeamsConfigs: []monitoringv1alpha1.MSTeamsConfig{{
+ WebhookURL: corev1.SecretKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: "msteams",
+ },
+ Key: "webhook-url",
+ },
+ Title: new("Alert"),
+ }},
}},
},
}
@@ -1303,7 +1318,7 @@ func testAlertmanagerConfigCRD(t *testing.T) {
Receivers: []monitoringv1alpha1.Receiver{{
Name: "e2e",
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{{
- URL: ptr.To("http://test.url"),
+ URL: new("http://test.url"),
}},
}},
MuteTimeIntervals: []monitoringv1alpha1.MuteTimeInterval{
@@ -1358,7 +1373,7 @@ func testAlertmanagerConfigCRD(t *testing.T) {
Receivers: []monitoringv1alpha1.Receiver{{
Name: "e2e",
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{{
- URL: ptr.To("http://test.url"),
+ URL: new("http://test.url"),
}},
}},
MuteTimeIntervals: []monitoringv1alpha1.MuteTimeInterval{
@@ -1590,6 +1605,9 @@ receivers:
api_url: https://webex.api.url
message: testingMessage
room_id: testingRoomID
+ msteams_configs:
+ - webhook_url: https://msteams.webhook.url
+ title: Alert
- name: %s/e2e-test-amconfig-sub-routes/e2e
webhook_configs:
- url: http://test.url
@@ -1804,7 +1822,7 @@ func testAlertmanagerConfigCRDValidation(t *testing.T) {
Receivers: []monitoringv1alpha1.Receiver{{
Name: "e2e",
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{{
- URL: ptr.To("http://example.com"),
+ URL: new("http://example.com"),
}},
}},
},
@@ -1917,27 +1935,27 @@ func testUserDefinedAlertmanagerConfigFromCustomResource(t *testing.T) {
Name: alertmanagerConfig.Name,
Global: &monitoringv1.AlertmanagerGlobalConfig{
SMTPConfig: &monitoringv1.GlobalSMTPConfig{
- From: ptr.To("from"),
+ From: new("from"),
SmartHost: &monitoringv1.HostPort{
Host: "smtp.example.org",
Port: "587",
},
- Hello: ptr.To("smtp.example.org"),
- AuthUsername: ptr.To("dev@smtp.example.org"),
+ Hello: new("smtp.example.org"),
+ AuthUsername: new("dev@smtp.example.org"),
AuthPassword: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "smtp-auth",
},
Key: "password",
},
- AuthIdentity: ptr.To("dev@smtp.example.org"),
+ AuthIdentity: new("dev@smtp.example.org"),
AuthSecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "smtp-auth",
},
Key: "secret",
},
- RequireTLS: ptr.To(true),
+ RequireTLS: new(true),
},
ResolveTimeout: "30s",
HTTPConfigWithProxy: &monitoringv1.HTTPConfigWithProxy{
@@ -1964,10 +1982,53 @@ func testUserDefinedAlertmanagerConfigFromCustomResource(t *testing.T) {
"some": "value",
},
},
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
+ },
+ },
+ },
+ TelegramConfig: &monitoringv1.GlobalTelegramConfig{
+ APIURL: ptr.To(monitoringv1.URL("https://telegram.api.url")),
+ },
+ WeChatConfig: &monitoringv1.GlobalWeChatConfig{
+ APIURL: ptr.To(monitoringv1.URL("https://wechat.api.url")),
+ APISecret: &corev1.SecretKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: "wechat",
+ },
+ Key: "apisecret",
+ },
+ APICorpID: new("abc123"),
+ },
+ VictorOpsConfig: &monitoringv1.GlobalVictorOpsConfig{
+ APIURL: ptr.To(monitoringv1.URL("https://victorops.api.url")),
+ APIKey: &corev1.SecretKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: "victorops",
},
+ Key: "apikey",
},
},
+ JiraConfig: &monitoringv1.GlobalJiraConfig{
+ APIURL: ptr.To(monitoringv1.URL("https://jira.api.url")),
+ },
+ RocketChatConfig: &monitoringv1.GlobalRocketChatConfig{
+ APIURL: ptr.To(monitoringv1.URL("https://rocketchat.api.url")),
+ Token: &corev1.SecretKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: "rocketchat",
+ },
+ Key: "token",
+ },
+ TokenID: &corev1.SecretKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: "rocketchat",
+ },
+ Key: "tokenid",
+ },
+ },
+ WebexConfig: &monitoringv1.GlobalWebexConfig{
+ APIURL: ptr.To(monitoringv1.URL("https://webex.api.url")),
+ },
},
Templates: []monitoringv1.SecretOrConfigMap{
{
@@ -2033,6 +2094,31 @@ func testUserDefinedAlertmanagerConfigFromCustomResource(t *testing.T) {
"template2.tmpl": "template2",
},
}
+ victorops := corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "victorops",
+ },
+ Data: map[string][]byte{
+ "apikey": []byte(`abcdef1234567890`),
+ },
+ }
+ wechat := corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "wechat",
+ },
+ Data: map[string][]byte{
+ "apisecret": []byte(`abcdef1234567890`),
+ },
+ }
+ rocketchat := corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "rocketchat",
+ },
+ Data: map[string][]byte{
+ "token": []byte(`abcdef1234567890`),
+ "tokenid": []byte(`abc123`),
+ },
+ }
ctx := context.Background()
_, err = framework.KubeClient.CoreV1().ConfigMaps(ns).Create(ctx, &cm, metav1.CreateOptions{})
@@ -2045,6 +2131,12 @@ func testUserDefinedAlertmanagerConfigFromCustomResource(t *testing.T) {
require.NoError(t, err)
_, err = framework.KubeClient.CoreV1().ConfigMaps(ns).Create(ctx, &tpl2, metav1.CreateOptions{})
require.NoError(t, err)
+ _, err = framework.KubeClient.CoreV1().Secrets(ns).Create(ctx, &victorops, metav1.CreateOptions{})
+ require.NoError(t, err)
+ _, err = framework.KubeClient.CoreV1().Secrets(ns).Create(ctx, &wechat, metav1.CreateOptions{})
+ require.NoError(t, err)
+ _, err = framework.KubeClient.CoreV1().Secrets(ns).Create(ctx, &rocketchat, metav1.CreateOptions{})
+ require.NoError(t, err)
_, err = framework.CreateAlertmanagerAndWaitUntilReady(ctx, alertmanager)
require.NoError(t, err)
@@ -2069,6 +2161,17 @@ func testUserDefinedAlertmanagerConfigFromCustomResource(t *testing.T) {
smtp_auth_secret: secret
smtp_auth_identity: dev@smtp.example.org
smtp_require_tls: true
+ wechat_api_url: https://wechat.api.url
+ wechat_api_secret: abcdef1234567890
+ wechat_api_corp_id: abc123
+ victorops_api_url: https://victorops.api.url
+ victorops_api_key: abcdef1234567890
+ telegram_api_url: https://telegram.api.url
+ webex_api_url: https://webex.api.url
+ jira_api_url: https://jira.api.url
+ rocketchat_api_url: https://rocketchat.api.url
+ rocketchat_token: abcdef1234567890
+ rocketchat_token_id: abc123
route:
receiver: %[1]s
routes:
@@ -2229,7 +2332,7 @@ func testAMRollbackManualChanges(t *testing.T) {
sset, err := ssetClient.Get(context.Background(), "alertmanager-"+name, metav1.GetOptions{})
require.NoError(t, err)
- sset.Spec.Replicas = ptr.To(int32(0))
+ sset.Spec.Replicas = new(int32(0))
sset, err = ssetClient.Update(context.Background(), sset, metav1.UpdateOptions{})
require.NoError(t, err)
@@ -2508,7 +2611,7 @@ func testAlertManagerMinReadySeconds(t *testing.T) {
framework.SetupPrometheusRBAC(context.Background(), t, testCtx, ns)
am := framework.MakeBasicAlertmanager(ns, "basic-am", 3)
- am.Spec.MinReadySeconds = ptr.To(int32(5))
+ am.Spec.MinReadySeconds = new(int32(5))
am, err := framework.CreateAlertmanagerAndWaitUntilReady(context.Background(), am)
require.NoError(t, err)
@@ -2517,7 +2620,7 @@ func testAlertManagerMinReadySeconds(t *testing.T) {
require.Equal(t, int32(5), amSS.Spec.MinReadySeconds)
- _, err = framework.PatchAlertmanagerAndWaitUntilReady(context.Background(), am.Name, am.Namespace, monitoringv1.AlertmanagerSpec{MinReadySeconds: ptr.To(int32(10))})
+ _, err = framework.PatchAlertmanagerAndWaitUntilReady(context.Background(), am.Name, am.Namespace, monitoringv1.AlertmanagerSpec{MinReadySeconds: new(int32(10))})
require.NoError(t, err)
amSS, err = framework.KubeClient.AppsV1().StatefulSets(ns).Get(context.Background(), "alertmanager-basic-am", metav1.GetOptions{})
@@ -2614,7 +2717,7 @@ func testAlertmanagerCRDValidation(t *testing.T) {
Options: []monitoringv1.PodDNSConfigOption{
{
Name: "ndots",
- Value: ptr.To("5"),
+ Value: new("5"),
},
},
},
@@ -2640,11 +2743,11 @@ func testAlertmanagerCRDValidation(t *testing.T) {
Options: []monitoringv1.PodDNSConfigOption{
{
Name: "ndots",
- Value: ptr.To("5"),
+ Value: new("5"),
},
{
Name: "timeout",
- Value: ptr.To("2"),
+ Value: new("2"),
},
},
},
@@ -2671,7 +2774,7 @@ func testAlertmanagerCRDValidation(t *testing.T) {
Options: []monitoringv1.PodDNSConfigOption{
{
Name: "", // Empty string violates MinLength constraint
- Value: ptr.To("some-value"),
+ Value: new("some-value"),
},
},
},
diff --git a/test/e2e/prometheus_shard_retention_policy_test.go b/test/e2e/prometheus_shard_retention_policy_test.go
index 5735068f474..b2beed8196b 100644
--- a/test/e2e/prometheus_shard_retention_policy_test.go
+++ b/test/e2e/prometheus_shard_retention_policy_test.go
@@ -26,7 +26,6 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
- "k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
"github.com/prometheus-operator/prometheus-operator/pkg/operator"
@@ -76,7 +75,7 @@ func testPrometheusTargetDistributionOnResharding(t *testing.T) {
{
TargetLabel: "__tmp_disable_sharding",
Action: "Replace",
- Replacement: ptr.To("true"),
+ Replacement: new("true"),
},
}
sm, err = framework.MonClientV1.ServiceMonitors(ns).Create(ctx, sm, metav1.CreateOptions{})
@@ -88,7 +87,7 @@ func testPrometheusTargetDistributionOnResharding(t *testing.T) {
// the Delete strategy because the second shard will not exist anymore in
// case of scale down.
prom := framework.MakeBasicPrometheus(ns, prometheusName, prometheusGroupLabel, 1)
- prom.Spec.Shards = ptr.To(int32(1))
+ prom.Spec.Shards = new(int32(1))
prom.Spec.ServiceMonitorSelector = &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
@@ -100,7 +99,7 @@ func testPrometheusTargetDistributionOnResharding(t *testing.T) {
}
prom.Spec.ShardRetentionPolicy = &monitoringv1.ShardRetentionPolicy{
- WhenScaled: ptr.To(monitoringv1.RetainWhenScaledRetentionType),
+ WhenScaled: new(monitoringv1.RetainWhenScaledRetentionType),
}
shardServices := make([]*corev1.Service, 2)
@@ -208,11 +207,11 @@ func testPrometheusRetentionPolicies(t *testing.T) {
}{
{
name: "delete policy",
- whenScaledDown: ptr.To(monitoringv1.DeleteWhenScaledRetentionType),
+ whenScaledDown: new(monitoringv1.DeleteWhenScaledRetentionType),
},
{
name: "retain policy",
- whenScaledDown: ptr.To(monitoringv1.RetainWhenScaledRetentionType),
+ whenScaledDown: new(monitoringv1.RetainWhenScaledRetentionType),
},
}
@@ -223,7 +222,7 @@ func testPrometheusRetentionPolicies(t *testing.T) {
p.Spec.ShardRetentionPolicy = &monitoringv1.ShardRetentionPolicy{
WhenScaled: tc.whenScaledDown,
}
- p.Spec.Shards = ptr.To(int32(2))
+ p.Spec.Shards = new(int32(2))
_, err := framework.CreatePrometheusAndWaitUntilReady(ctx, ns, p)
require.NoError(t, err)
@@ -301,9 +300,10 @@ func testPrometheusRetentionPolicies(t *testing.T) {
require.NoError(t, err)
require.Equal(t, int32(1), p.Status.Shards)
- sts, err = framework.KubeClient.AppsV1().StatefulSets(ns).List(ctx, metav1.ListOptions{LabelSelector: p.Status.Selector})
- require.NoError(t, err)
- require.Len(t, sts.Items, 1)
+ // The retention reconciler runs once per minute and the
+ // API server still needs to process the StatefulSet deletion
+ // so poll until only the active shard remains.
+ require.NoError(t, framework.WaitForStatefulSetReplicas(ctx, ns, metav1.ListOptions{LabelSelector: p.Status.Selector}, 1))
})
}
}
diff --git a/test/e2e/prometheus_test.go b/test/e2e/prometheus_test.go
index 7139b267298..ce228ce641e 100644
--- a/test/e2e/prometheus_test.go
+++ b/test/e2e/prometheus_test.go
@@ -144,7 +144,7 @@ func deployInstrumentedApplicationWithTLS(name, ns string) error {
TLSConfig: &monitoringv1.TLSConfig{
SafeTLSConfig: monitoringv1.SafeTLSConfig{
- ServerName: ptr.To("caandserver.com"),
+ ServerName: new("caandserver.com"),
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -1049,6 +1049,10 @@ func testPromStorageUpdate(t *testing.T) {
t.Fatal(err)
}
+ sts, err := framework.KubeClient.AppsV1().StatefulSets(ns).List(context.Background(), metav1.ListOptions{LabelSelector: p.Status.Selector})
+ require.NoError(t, err)
+ require.Len(t, sts.Items, 1)
+
p, err = framework.PatchPrometheusAndWaitUntilReady(
context.Background(),
p.Name,
@@ -1077,6 +1081,11 @@ func testPromStorageUpdate(t *testing.T) {
)
require.NoError(t, err)
+ updatedSts, err := framework.KubeClient.AppsV1().StatefulSets(ns).List(context.Background(), metav1.ListOptions{LabelSelector: p.Status.Selector})
+ require.NoError(t, err)
+ require.Len(t, updatedSts.Items, 1)
+ require.NotEqual(t, sts.Items[0].UID, updatedSts.Items[0].UID, "StatefulSet should have different UIDs because the statefulset has been recreated")
+
err = framework.WaitForBoundPVC(context.Background(), ns, "test=testPromStorageUpdate", 1)
require.NoError(t, err)
@@ -1095,7 +1104,7 @@ func testPromStorageUpdate(t *testing.T) {
},
},
Spec: corev1.PersistentVolumeClaimSpec{
- StorageClassName: ptr.To("unknown-storage-class"),
+ StorageClassName: new("unknown-storage-class"),
Resources: corev1.VolumeResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("200Mi"),
@@ -1161,7 +1170,7 @@ func testPromReloadConfig(t *testing.T) {
},
Key: "config.yaml",
}
- p.Spec.ReloadStrategy = ptr.To(tc.reloadStrategy)
+ p.Spec.ReloadStrategy = new(tc.reloadStrategy)
svc := framework.MakePrometheusService(p.Name, "not-relevant", corev1.ServiceTypeClusterIP)
@@ -2399,7 +2408,7 @@ func testPromAlertmanagerDiscovery(t *testing.T) {
p := framework.MakeBasicPrometheus(ns, prometheusName, group, 1)
framework.AddAlertingToPrometheus(p, ns, alertmanagerName)
- p.Spec.ServiceDiscoveryRole = ptr.To(tc.sdRole)
+ p.Spec.ServiceDiscoveryRole = new(tc.sdRole)
_, err := framework.CreatePrometheusAndWaitUntilReady(context.Background(), ns, p)
if err != nil {
t.Fatal(err)
@@ -3056,7 +3065,7 @@ func testPromArbitraryFSAcc(t *testing.T) {
HTTPConfigWithTLSFiles: monitoringv1.HTTPConfigWithTLSFiles{
TLSConfig: &monitoringv1.TLSConfig{
SafeTLSConfig: monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -3097,7 +3106,7 @@ func testPromArbitraryFSAcc(t *testing.T) {
HTTPConfigWithTLSFiles: monitoringv1.HTTPConfigWithTLSFiles{
TLSConfig: &monitoringv1.TLSConfig{
SafeTLSConfig: monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
CA: monitoringv1.SecretOrConfigMap{
ConfigMap: &corev1.ConfigMapKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -3357,7 +3366,7 @@ func testPromTLSConfigViaSecret(t *testing.T) {
HTTPConfigWithTLSFiles: monitoringv1.HTTPConfigWithTLSFiles{
TLSConfig: &monitoringv1.TLSConfig{
SafeTLSConfig: monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
Cert: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -3517,7 +3526,7 @@ func testPromSecurePodMonitor(t *testing.T) {
{
name: "basic-auth-secret",
endpoint: monitoringv1.PodMetricsEndpoint{
- Port: ptr.To("web"),
+ Port: new("web"),
HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
HTTPConfig: monitoringv1.HTTPConfig{
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
@@ -3546,7 +3555,7 @@ func testPromSecurePodMonitor(t *testing.T) {
{
name: "bearer-secret",
endpoint: monitoringv1.PodMetricsEndpoint{
- Port: ptr.To("web"),
+ Port: new("web"),
HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
HTTPConfig: monitoringv1.HTTPConfig{
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
@@ -3568,12 +3577,12 @@ func testPromSecurePodMonitor(t *testing.T) {
{
name: "tls-secret",
endpoint: monitoringv1.PodMetricsEndpoint{
- Port: ptr.To("mtls"),
+ Port: new("mtls"),
Scheme: ptr.To(monitoringv1.SchemeHTTPS),
HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
HTTPConfig: monitoringv1.HTTPConfig{
TLSConfig: &monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -3605,12 +3614,12 @@ func testPromSecurePodMonitor(t *testing.T) {
{
name: "tls-configmap",
endpoint: monitoringv1.PodMetricsEndpoint{
- Port: ptr.To("mtls"),
+ Port: new("mtls"),
Scheme: ptr.To(monitoringv1.SchemeHTTPS),
HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
HTTPConfig: monitoringv1.HTTPConfig{
TLSConfig: &monitoringv1.SafeTLSConfig{
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
CA: monitoringv1.SecretOrConfigMap{
ConfigMap: &corev1.ConfigMapKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -4026,7 +4035,7 @@ func testPromMinReadySeconds(t *testing.T) {
kubeClient := framework.KubeClient
prom := framework.MakeBasicPrometheus(ns, "basic-prometheus", "test-group", 1)
- prom.Spec.MinReadySeconds = ptr.To(int32(5))
+ prom.Spec.MinReadySeconds = new(int32(5))
prom, err := framework.CreatePrometheusAndWaitUntilReady(context.Background(), ns, prom)
require.NoError(t, err)
@@ -4041,7 +4050,7 @@ func testPromMinReadySeconds(t *testing.T) {
ns,
monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- MinReadySeconds: ptr.To(int32(10)),
+ MinReadySeconds: new(int32(10)),
},
},
)
@@ -4081,13 +4090,13 @@ func testPromEnforcedNamespaceLabel(t *testing.T) {
relabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "namespace",
- Replacement: ptr.To("ns1"),
+ Replacement: new("ns1"),
},
},
metricRelabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "namespace",
- Replacement: ptr.To("ns1"),
+ Replacement: new("ns1"),
},
},
},
@@ -4096,13 +4105,13 @@ func testPromEnforcedNamespaceLabel(t *testing.T) {
relabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "namespace",
- Replacement: ptr.To(""),
+ Replacement: new(""),
},
},
metricRelabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "namespace",
- Replacement: ptr.To(""),
+ Replacement: new(""),
},
},
},
@@ -4111,14 +4120,14 @@ func testPromEnforcedNamespaceLabel(t *testing.T) {
relabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "temp_namespace",
- Replacement: ptr.To("ns1"),
+ Replacement: new("ns1"),
},
},
metricRelabelConfigs: []monitoringv1.RelabelConfig{
{
Action: "labelmap",
Regex: "temp_namespace",
- Replacement: ptr.To("namespace"),
+ Replacement: new("namespace"),
},
{
Action: "labeldrop",
@@ -4239,13 +4248,13 @@ func testPromNamespaceEnforcementExclusion(t *testing.T) {
relabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "namespace",
- Replacement: ptr.To("ns1"),
+ Replacement: new("ns1"),
},
},
metricRelabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "namespace",
- Replacement: ptr.To("ns1"),
+ Replacement: new("ns1"),
},
},
expectedNamespace: "ns1",
@@ -4255,14 +4264,14 @@ func testPromNamespaceEnforcementExclusion(t *testing.T) {
relabelConfigs: []monitoringv1.RelabelConfig{
{
TargetLabel: "temp_namespace",
- Replacement: ptr.To("ns1"),
+ Replacement: new("ns1"),
},
},
metricRelabelConfigs: []monitoringv1.RelabelConfig{
{
Action: "labelmap",
Regex: "temp_namespace",
- Replacement: ptr.To("namespace"),
+ Replacement: new("namespace"),
},
{
Action: "labeldrop",
@@ -4606,7 +4615,7 @@ func testPrometheusCRDValidation(t *testing.T) {
},
},
Query: &monitoringv1.QuerySpec{
- MaxConcurrency: ptr.To(int32(100)),
+ MaxConcurrency: new(int32(100)),
},
},
},
@@ -4624,7 +4633,7 @@ func testPrometheusCRDValidation(t *testing.T) {
},
},
Query: &monitoringv1.QuerySpec{
- MaxConcurrency: ptr.To(int32(0)),
+ MaxConcurrency: new(int32(0)),
},
},
expectedError: true,
@@ -4647,7 +4656,7 @@ func testPrometheusCRDValidation(t *testing.T) {
Options: []monitoringv1.PodDNSConfigOption{
{
Name: "ndots",
- Value: ptr.To("5"),
+ Value: new("5"),
},
},
},
@@ -4693,7 +4702,7 @@ func testPrometheusCRDValidation(t *testing.T) {
Name: "test",
Port: intstr.FromInt(9797),
Scheme: ptr.To(monitoringv1.SchemeHTTPS),
- PathPrefix: ptr.To("/alerts"),
+ PathPrefix: new("/alerts"),
BearerTokenFile: "/file",
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion1),
},
@@ -4719,10 +4728,10 @@ func testPrometheusCRDValidation(t *testing.T) {
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
Name: "test",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromInt(9797),
Scheme: ptr.To(monitoringv1.SchemeHTTPS),
- PathPrefix: ptr.To("/alerts"),
+ PathPrefix: new("/alerts"),
BearerTokenFile: "/file",
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion1),
},
@@ -4747,10 +4756,10 @@ func testPrometheusCRDValidation(t *testing.T) {
Alerting: &monitoringv1.AlertingSpec{
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
Port: intstr.FromInt(9797),
Scheme: ptr.To(monitoringv1.SchemeHTTPS),
- PathPrefix: ptr.To("/alerts"),
+ PathPrefix: new("/alerts"),
BearerTokenFile: "/file",
APIVersion: ptr.To(monitoringv1.AlertmanagerAPIVersion1),
},
@@ -4876,7 +4885,7 @@ func testPrometheusCRDValidation(t *testing.T) {
Replicas: &replicas,
Version: operator.DefaultPrometheusVersion,
ServiceAccountName: "prometheus",
- TerminationGracePeriodSeconds: ptr.To(int64(-100)),
+ TerminationGracePeriodSeconds: new(int64(-100)),
},
},
expectedError: true,
@@ -4888,7 +4897,7 @@ func testPrometheusCRDValidation(t *testing.T) {
Replicas: &replicas,
Version: operator.DefaultPrometheusVersion,
ServiceAccountName: "prometheus",
- TerminationGracePeriodSeconds: ptr.To(int64(100)),
+ TerminationGracePeriodSeconds: new(int64(100)),
},
},
},
@@ -4970,7 +4979,7 @@ func testRelabelConfigCRDValidation(t *testing.T) {
SourceLabels: []monitoringv1.LabelName{"__address__"},
Action: "replace",
Regex: "([^:]+)(?::\\d+)?",
- Replacement: ptr.To("$1:80"),
+ Replacement: new("$1:80"),
TargetLabel: "__address__",
},
},
@@ -4980,9 +4989,9 @@ func testRelabelConfigCRDValidation(t *testing.T) {
relabelConfigs: []monitoringv1.RelabelConfig{
{
SourceLabels: []monitoringv1.LabelName{"__address__"},
- Separator: ptr.To(","),
+ Separator: new(","),
Regex: "([^:]+)(?::\\d+)?",
- Replacement: ptr.To("$1:80"),
+ Replacement: new("$1:80"),
TargetLabel: "__address__",
},
},
@@ -4991,7 +5000,7 @@ func testRelabelConfigCRDValidation(t *testing.T) {
scenario: "empty-separator",
relabelConfigs: []monitoringv1.RelabelConfig{
{
- Separator: ptr.To(""),
+ Separator: new(""),
},
},
},
@@ -5011,7 +5020,7 @@ func testRelabelConfigCRDValidation(t *testing.T) {
SourceLabels: []monitoringv1.LabelName{"app.info"},
Action: "replace",
TargetLabel: "app.info",
- Replacement: ptr.To("test.app"),
+ Replacement: new("test.app"),
},
},
},
@@ -5595,7 +5604,7 @@ func testPrometheusUTF8MetricsSupport(t *testing.T) {
},
},
Spec: appsv1.DeploymentSpec{
- Replicas: ptr.To(int32(1)),
+ Replicas: new(int32(1)),
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"app": "instrumented-sample-app"},
},
@@ -5826,7 +5835,7 @@ func testPrometheusUTF8LabelSupport(t *testing.T) {
},
},
Spec: appsv1.DeploymentSpec{
- Replicas: ptr.To(int32(1)),
+ Replicas: new(int32(1)),
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"app.name": "instrumented-sample-app"},
},
@@ -6118,7 +6127,7 @@ func testPrometheusShardingStrategyCELValidations(t *testing.T) {
p.Spec.ShardingStrategy = &monitoringv1.ShardingStrategy{
Mode: ptr.To(monitoringv1.TopologyShardingStrategyMode),
Topology: &monitoringv1.TopologyShardingStrategy{
- Values: []string{"zone1", "zone2"},
+ Values: []string{"zone-a", "zone-b"},
},
}
},
@@ -6127,11 +6136,11 @@ func testPrometheusShardingStrategyCELValidations(t *testing.T) {
{
name: "topology sharding with shards < values",
updateFn: func(p *monitoringv1.Prometheus) {
- p.Spec.Shards = ptr.To(int32(2))
+ p.Spec.Shards = new(int32(2))
p.Spec.ShardingStrategy = &monitoringv1.ShardingStrategy{
Mode: ptr.To(monitoringv1.TopologyShardingStrategyMode),
Topology: &monitoringv1.TopologyShardingStrategy{
- Values: []string{"zone1", "zone2", "zone3"},
+ Values: []string{"zone-a", "zone-b", "zone-c"},
},
}
},
@@ -6140,11 +6149,11 @@ func testPrometheusShardingStrategyCELValidations(t *testing.T) {
{
name: "topology sharding with shards >= values",
updateFn: func(p *monitoringv1.Prometheus) {
- p.Spec.Shards = ptr.To(int32(2))
+ p.Spec.Shards = new(int32(2))
p.Spec.ShardingStrategy = &monitoringv1.ShardingStrategy{
Mode: ptr.To(monitoringv1.TopologyShardingStrategyMode),
Topology: &monitoringv1.TopologyShardingStrategy{
- Values: []string{"zone1", "zone2"},
+ Values: []string{"zone-a", "zone-b"},
},
}
},
diff --git a/test/e2e/prometheusagent_test.go b/test/e2e/prometheusagent_test.go
index a7127684491..d85c281c163 100644
--- a/test/e2e/prometheusagent_test.go
+++ b/test/e2e/prometheusagent_test.go
@@ -35,7 +35,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/util/wait"
- "k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
@@ -140,7 +139,7 @@ func testAgentCheckStorageClass(t *testing.T) {
Storage: &monitoringv1.StorageSpec{
VolumeClaimTemplate: monitoringv1.EmbeddedPersistentVolumeClaim{
Spec: corev1.PersistentVolumeClaimSpec{
- StorageClassName: ptr.To("unknown-storage-class"),
+ StorageClassName: new("unknown-storage-class"),
Resources: corev1.VolumeResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("200Mi"),
@@ -686,7 +685,7 @@ func testDaemonSetInvalidReplicas(t *testing.T) {
p := framework.MakeBasicPrometheusAgentDaemonSet(ns, name)
// no replicas should be set in Daemonsets
- p.Spec.Replicas = ptr.To(int32(3))
+ p.Spec.Replicas = new(int32(3))
_, err = framework.CreatePrometheusAgentAndWaitUntilReady(ctx, ns, p)
require.Error(t, err)
@@ -717,7 +716,7 @@ func testDaemonSetInvalidStorage(t *testing.T) {
p.Spec.CommonPrometheusFields.Storage = &monitoringv1.StorageSpec{
VolumeClaimTemplate: monitoringv1.EmbeddedPersistentVolumeClaim{
Spec: corev1.PersistentVolumeClaimSpec{
- StorageClassName: ptr.To("standard"),
+ StorageClassName: new("standard"),
Resources: corev1.VolumeResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("200Mi"),
@@ -753,7 +752,7 @@ func testDaemonSetInvalidShards(t *testing.T) {
p := framework.MakeBasicPrometheusAgentDaemonSet(ns, name)
// shards cannot be greater than 1 in DaemonSets
- p.Spec.Shards = ptr.To(int32(2))
+ p.Spec.Shards = new(int32(2))
_, err = framework.CreatePrometheusAgentAndWaitUntilReady(ctx, ns, p)
require.Error(t, err)
diff --git a/test/e2e/repair_policy_test.go b/test/e2e/repair_policy_test.go
index 14c634fc20b..04a45337f86 100644
--- a/test/e2e/repair_policy_test.go
+++ b/test/e2e/repair_policy_test.go
@@ -124,7 +124,7 @@ func repairPrometheus(ns string) func(t *testing.T) {
prom.Namespace,
monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- Image: ptr.To(badImage),
+ Image: new(badImage),
},
},
)
@@ -141,7 +141,7 @@ func repairPrometheus(ns string) func(t *testing.T) {
prom.Namespace,
monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- Image: ptr.To(operator.DefaultPrometheusImage),
+ Image: new(operator.DefaultPrometheusImage),
},
},
)
@@ -166,7 +166,7 @@ func repairAlertmanager(ns string) func(t *testing.T) {
am.Name,
am.Namespace,
monitoringv1.AlertmanagerSpec{
- Image: ptr.To(badImage),
+ Image: new(badImage),
},
)
require.NoError(t, err)
diff --git a/test/e2e/scrapeconfig_test.go b/test/e2e/scrapeconfig_test.go
index cf0a4616302..0630bcea350 100644
--- a/test/e2e/scrapeconfig_test.go
+++ b/test/e2e/scrapeconfig_test.go
@@ -94,7 +94,7 @@ func testScrapeConfigCreation(t *testing.T) {
Selectors: []monitoringv1alpha1.K8SSelectorConfig{
{
Role: "Pod",
- Label: ptr.To("component=executor"),
+ Label: new("component=executor"),
},
},
},
@@ -111,7 +111,7 @@ func testScrapeConfigCreation(t *testing.T) {
},
RefreshInterval: &fiveMins,
Type: ptr.To(monitoringv1alpha1.DNSRecordType("A")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -124,7 +124,7 @@ func testScrapeConfigCreation(t *testing.T) {
Names: []string{""},
RefreshInterval: &fiveMins,
Type: ptr.To(monitoringv1alpha1.DNSRecordType("A")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
},
},
@@ -470,7 +470,7 @@ func testScrapeConfigKubernetesNodeRole(t *testing.T) {
}
sc.Spec.TLSConfig = &monitoringv1.SafeTLSConfig{
// since we cannot validate server name in cert
- InsecureSkipVerify: ptr.To(true),
+ InsecureSkipVerify: new(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -545,7 +545,7 @@ func testScrapeConfigDNSSDConfig(t *testing.T) {
{
Names: []string{"node.demo.do.prometheus.io"},
Type: ptr.To(monitoringv1alpha1.DNSRecordType("A")),
- Port: ptr.To(int32(9100)),
+ Port: new(int32(9100)),
},
}
_, err = framework.CreateScrapeConfig(context.Background(), ns, sc)
@@ -751,7 +751,7 @@ var ConsulSDTestCases = []scrapeCRDTestCase{
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "valid-server",
- PathPrefix: ptr.To("valid-server"),
+ PathPrefix: new("valid-server"),
},
},
},
@@ -763,7 +763,7 @@ var ConsulSDTestCases = []scrapeCRDTestCase{
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "valid-server",
- PathPrefix: ptr.To(""),
+ PathPrefix: new(""),
},
},
},
@@ -786,7 +786,7 @@ var ConsulSDTestCases = []scrapeCRDTestCase{
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "valid-server",
- Datacenter: ptr.To("valid-server"),
+ Datacenter: new("valid-server"),
},
},
},
@@ -798,7 +798,7 @@ var ConsulSDTestCases = []scrapeCRDTestCase{
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "valid-server",
- Datacenter: ptr.To(""),
+ Datacenter: new(""),
},
},
},
@@ -821,7 +821,7 @@ var ConsulSDTestCases = []scrapeCRDTestCase{
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "valid-server",
- Namespace: ptr.To("valid-server"),
+ Namespace: new("valid-server"),
},
},
},
@@ -833,7 +833,7 @@ var ConsulSDTestCases = []scrapeCRDTestCase{
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "valid-server",
- Namespace: ptr.To(""),
+ Namespace: new(""),
},
},
},
@@ -856,7 +856,7 @@ var ConsulSDTestCases = []scrapeCRDTestCase{
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "valid-server",
- Partition: ptr.To("valid-server"),
+ Partition: new("valid-server"),
},
},
},
@@ -868,7 +868,7 @@ var ConsulSDTestCases = []scrapeCRDTestCase{
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "valid-server",
- Partition: ptr.To(""),
+ Partition: new(""),
},
},
},
@@ -1020,7 +1020,7 @@ var ConsulSDTestCases = []scrapeCRDTestCase{
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "valid-server",
- TagSeparator: ptr.To(","),
+ TagSeparator: new(","),
},
},
},
@@ -1032,7 +1032,7 @@ var ConsulSDTestCases = []scrapeCRDTestCase{
ConsulSDConfigs: []monitoringv1alpha1.ConsulSDConfig{
{
Server: "valid-server",
- TagSeparator: ptr.To(""),
+ TagSeparator: new(""),
},
},
},
@@ -1114,7 +1114,7 @@ var K8STestCases = []scrapeCRDTestCase{
KubernetesSDConfigs: []monitoringv1alpha1.KubernetesSDConfig{
{
Role: "EndpointSlice",
- APIServer: ptr.To(""),
+ APIServer: new(""),
},
},
},
@@ -1207,7 +1207,7 @@ var K8STestCases = []scrapeCRDTestCase{
Selectors: []monitoringv1alpha1.K8SSelectorConfig{
{
Role: "Pod",
- Label: ptr.To(""),
+ Label: new(""),
},
},
},
@@ -1224,7 +1224,7 @@ var K8STestCases = []scrapeCRDTestCase{
Selectors: []monitoringv1alpha1.K8SSelectorConfig{
{
Role: "Pod",
- Label: ptr.To("node.kubernetes.io/instance-type=master"),
+ Label: new("node.kubernetes.io/instance-type=master"),
},
},
},
@@ -1241,7 +1241,7 @@ var K8STestCases = []scrapeCRDTestCase{
Selectors: []monitoringv1alpha1.K8SSelectorConfig{
{
Role: "Pod",
- Field: ptr.To(""),
+ Field: new(""),
},
},
},
@@ -1258,7 +1258,7 @@ var K8STestCases = []scrapeCRDTestCase{
Selectors: []monitoringv1alpha1.K8SSelectorConfig{
{
Role: "Pod",
- Field: ptr.To("metadata.name=foobar"),
+ Field: new("metadata.name=foobar"),
},
},
},
@@ -1275,7 +1275,7 @@ var K8STestCases = []scrapeCRDTestCase{
Selectors: []monitoringv1alpha1.K8SSelectorConfig{
{
Role: "Pod",
- Field: ptr.To("metadata.name=foobar"),
+ Field: new("metadata.name=foobar"),
},
},
},
@@ -1292,13 +1292,13 @@ var K8STestCases = []scrapeCRDTestCase{
Selectors: []monitoringv1alpha1.K8SSelectorConfig{
{
Role: "Pod",
- Label: ptr.To("node.kubernetes.io/instance-type=master"),
- Field: ptr.To("metadata.name=foobar"),
+ Label: new("node.kubernetes.io/instance-type=master"),
+ Field: new("metadata.name=foobar"),
},
{
Role: "Pod",
- Label: ptr.To("node.kubernetes.io/instance-type=master"),
- Field: ptr.To("metadata.name=foobar"),
+ Label: new("node.kubernetes.io/instance-type=master"),
+ Field: new("metadata.name=foobar"),
},
},
},
@@ -1313,7 +1313,7 @@ var K8STestCases = []scrapeCRDTestCase{
{
Role: "Pod",
Namespaces: &monitoringv1alpha1.NamespaceDiscovery{
- IncludeOwnNamespace: ptr.To(true),
+ IncludeOwnNamespace: new(true),
},
},
},
@@ -1327,7 +1327,7 @@ var K8STestCases = []scrapeCRDTestCase{
{
Role: "Pod",
Namespaces: &monitoringv1alpha1.NamespaceDiscovery{
- IncludeOwnNamespace: ptr.To(false),
+ IncludeOwnNamespace: new(false),
Names: []string{},
},
},
@@ -1370,7 +1370,7 @@ var K8STestCases = []scrapeCRDTestCase{
{
Role: "Pod",
Namespaces: &monitoringv1alpha1.NamespaceDiscovery{
- IncludeOwnNamespace: ptr.To(true),
+ IncludeOwnNamespace: new(true),
Names: []string{"default", "kube-system"},
},
},
@@ -1385,7 +1385,7 @@ var K8STestCases = []scrapeCRDTestCase{
{
Role: "Pod",
Namespaces: &monitoringv1alpha1.NamespaceDiscovery{
- IncludeOwnNamespace: ptr.To(true),
+ IncludeOwnNamespace: new(true),
Names: []string{"default", "default"},
},
},
@@ -1399,7 +1399,7 @@ var K8STestCases = []scrapeCRDTestCase{
KubernetesSDConfigs: []monitoringv1alpha1.KubernetesSDConfig{
{
Role: "Pod",
- AttachMetadata: &monitoringv1alpha1.AttachMetadata{Node: ptr.To(true)},
+ AttachMetadata: &monitoringv1alpha1.AttachMetadata{Node: new(true)},
},
},
},
@@ -1544,7 +1544,7 @@ var DNSSDTestCases = []scrapeCRDTestCase{
DNSSDConfigs: []monitoringv1alpha1.DNSSDConfig{
{
Names: []string{"test1"},
- Port: ptr.To(int32(8080)),
+ Port: new(int32(8080)),
},
},
},
@@ -1556,7 +1556,7 @@ var DNSSDTestCases = []scrapeCRDTestCase{
DNSSDConfigs: []monitoringv1alpha1.DNSSDConfig{
{
Names: []string{"test1"},
- Port: ptr.To(int32(80809)),
+ Port: new(int32(80809)),
},
},
},
@@ -1594,7 +1594,7 @@ var EC2SDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-west"),
+ Region: new("us-west"),
},
},
},
@@ -1614,7 +1614,7 @@ var EC2SDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To(""),
+ Region: new(""),
},
},
},
@@ -1625,7 +1625,7 @@ var EC2SDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- RoleARN: ptr.To("valid-role"),
+ RoleARN: new("valid-role"),
},
},
},
@@ -1645,7 +1645,7 @@ var EC2SDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- RoleARN: ptr.To(""),
+ RoleARN: new(""),
},
},
},
@@ -1656,7 +1656,7 @@ var EC2SDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Port: ptr.To(int32(8080)),
+ Port: new(int32(8080)),
},
},
},
@@ -1667,7 +1667,7 @@ var EC2SDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Port: ptr.To(int32(80809)),
+ Port: new(int32(80809)),
},
},
},
@@ -1678,7 +1678,7 @@ var EC2SDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-west"),
+ Region: new("us-west"),
Filters: []monitoringv1alpha1.Filter{
{
Name: "foo",
@@ -1695,7 +1695,7 @@ var EC2SDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-west"),
+ Region: new("us-west"),
Filters: []monitoringv1alpha1.Filter{
{
Name: "foo",
@@ -1712,7 +1712,7 @@ var EC2SDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-west"),
+ Region: new("us-west"),
Filters: []monitoringv1alpha1.Filter{
{
Name: "foo",
@@ -1729,7 +1729,7 @@ var EC2SDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
EC2SDConfigs: []monitoringv1alpha1.EC2SDConfig{
{
- Region: ptr.To("us-west"),
+ Region: new("us-west"),
Filters: []monitoringv1alpha1.Filter{
{
Name: "foo",
@@ -1752,14 +1752,14 @@ var ScrapeConfigCRDTestCases = []scrapeCRDTestCase{
{
name: "JobName: Empty String",
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
- JobName: ptr.To(""),
+ JobName: new(""),
},
expectedError: true,
},
{
name: "JobName: Valid Value",
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
- JobName: ptr.To("validJob"),
+ JobName: new("validJob"),
},
expectedError: false,
},
@@ -1797,14 +1797,14 @@ var ScrapeConfigCRDTestCases = []scrapeCRDTestCase{
{
name: "ScrapeClassName: Empty String",
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
- ScrapeClassName: ptr.To(""),
+ ScrapeClassName: new(""),
},
expectedError: true,
},
{
name: "ScrapeClassName: Valid Value",
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
- ScrapeClassName: ptr.To("default"),
+ ScrapeClassName: new("default"),
},
expectedError: false,
},
@@ -2071,7 +2071,7 @@ var DigitalOceanSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
DigitalOceanSDConfigs: []monitoringv1alpha1.DigitalOceanSDConfig{
{
- Port: ptr.To(int32(8080)),
+ Port: new(int32(8080)),
},
},
},
@@ -2082,7 +2082,7 @@ var DigitalOceanSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
DigitalOceanSDConfigs: []monitoringv1alpha1.DigitalOceanSDConfig{
{
- Port: ptr.To(int32(65536)), // maximum Port number = 65535
+ Port: new(int32(65536)), // maximum Port number = 65535
},
},
},
@@ -2093,7 +2093,7 @@ var DigitalOceanSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
DigitalOceanSDConfigs: []monitoringv1alpha1.DigitalOceanSDConfig{
{
- Port: ptr.To(int32(-1)), // minimum Port number = 0;
+ Port: new(int32(-1)), // minimum Port number = 0;
},
},
},
@@ -2161,7 +2161,7 @@ var IonosSDTestCases = []scrapeCRDTestCase{
IonosSDConfigs: []monitoringv1alpha1.IonosSDConfig{
{
DataCenterID: "11111111-1111-1111-1111-111111111111",
- Port: ptr.To(int32(8080)),
+ Port: new(int32(8080)),
},
},
},
@@ -2173,7 +2173,7 @@ var IonosSDTestCases = []scrapeCRDTestCase{
IonosSDConfigs: []monitoringv1alpha1.IonosSDConfig{
{
DataCenterID: "11111111-1111-1111-1111-111111111111",
- Port: ptr.To(int32(65536)), // maximum Port number = 65535
+ Port: new(int32(65536)), // maximum Port number = 65535
},
},
},
@@ -2185,7 +2185,7 @@ var IonosSDTestCases = []scrapeCRDTestCase{
IonosSDConfigs: []monitoringv1alpha1.IonosSDConfig{
{
DataCenterID: "11111111-1111-1111-1111-111111111111",
- Port: ptr.To(int32(-1)), // minimum Port number = 0
+ Port: new(int32(-1)), // minimum Port number = 0
},
},
},
@@ -2199,7 +2199,7 @@ var LightSailSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Region: ptr.To("us-east-1"),
+ Region: new("us-east-1"),
},
},
},
@@ -2210,7 +2210,7 @@ var LightSailSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Region: ptr.To(""),
+ Region: new(""),
},
},
},
@@ -2221,7 +2221,7 @@ var LightSailSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Endpoint: ptr.To("https://custom-endpoint.example.com"),
+ Endpoint: new("https://custom-endpoint.example.com"),
},
},
},
@@ -2233,7 +2233,7 @@ var LightSailSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Endpoint: ptr.To(""),
+ Endpoint: new(""),
},
},
},
@@ -2244,7 +2244,7 @@ var LightSailSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Port: ptr.To(int32(80)),
+ Port: new(int32(80)),
},
},
},
@@ -2255,7 +2255,7 @@ var LightSailSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Port: ptr.To(int32(-1)),
+ Port: new(int32(-1)),
},
},
},
@@ -2266,7 +2266,7 @@ var LightSailSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- Port: ptr.To(int32(65536)),
+ Port: new(int32(65536)),
},
},
},
@@ -2277,7 +2277,7 @@ var LightSailSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- RoleARN: ptr.To("arn:aws:iam::123456789012:role/MyRole"),
+ RoleARN: new("arn:aws:iam::123456789012:role/MyRole"),
},
},
},
@@ -2288,7 +2288,7 @@ var LightSailSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LightSailSDConfigs: []monitoringv1alpha1.LightSailSDConfig{
{
- RoleARN: ptr.To(""),
+ RoleARN: new(""),
},
},
},
@@ -2371,7 +2371,7 @@ var GCESDTestCases = []scrapeCRDTestCase{
{
Project: "devops-dev",
Zone: "us-west-1",
- Port: ptr.To(int32(65534)),
+ Port: new(int32(65534)),
},
},
},
@@ -2382,7 +2382,7 @@ var GCESDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
GCESDConfigs: []monitoringv1alpha1.GCESDConfig{
{
- Port: ptr.To(int32(-1)),
+ Port: new(int32(-1)),
},
},
},
@@ -2395,7 +2395,7 @@ var GCESDTestCases = []scrapeCRDTestCase{
{
Project: "devops-dev",
Zone: "us-west-1",
- Filter: ptr.To("filter-expression"),
+ Filter: new("filter-expression"),
},
},
},
@@ -2406,7 +2406,7 @@ var GCESDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
GCESDConfigs: []monitoringv1alpha1.GCESDConfig{
{
- Filter: ptr.To(""),
+ Filter: new(""),
},
},
},
@@ -2419,7 +2419,7 @@ var GCESDTestCases = []scrapeCRDTestCase{
{
Project: "devops-dev",
Zone: "us-west-1",
- TagSeparator: ptr.To("tag-value"),
+ TagSeparator: new("tag-value"),
},
},
},
@@ -2430,7 +2430,7 @@ var GCESDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
GCESDConfigs: []monitoringv1alpha1.GCESDConfig{
{
- TagSeparator: ptr.To(""),
+ TagSeparator: new(""),
},
},
},
@@ -2455,7 +2455,7 @@ var AzureSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
- Environment: ptr.To("AzurePublicCloud"),
+ Environment: new("AzurePublicCloud"),
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeSDK),
},
},
@@ -2487,7 +2487,7 @@ var AzureSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
- Environment: ptr.To("AzurePublicCloud"),
+ Environment: new("AzurePublicCloud"),
SubscriptionID: "11111111-1111-1111-1111-111111111111",
},
},
@@ -2499,7 +2499,7 @@ var AzureSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
- Environment: ptr.To(""),
+ Environment: new(""),
SubscriptionID: "11111111-1111-1111-1111-111111111111",
},
},
@@ -2511,7 +2511,7 @@ var AzureSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
- ResourceGroup: ptr.To("my-resource-group"),
+ ResourceGroup: new("my-resource-group"),
SubscriptionID: "11111111-1111-1111-1111-111111111111",
},
},
@@ -2523,7 +2523,7 @@ var AzureSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
- ResourceGroup: ptr.To(""),
+ ResourceGroup: new(""),
SubscriptionID: "11111111-1111-1111-1111-111111111111",
},
},
@@ -2560,8 +2560,8 @@ var AzureSDTestCases = []scrapeCRDTestCase{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeOAuth),
- TenantID: ptr.To("22222222-2222-2222-2222-222222222222"),
- ClientID: ptr.To("33333333-3333-3333-3333-333333333333"),
+ TenantID: new("22222222-2222-2222-2222-222222222222"),
+ ClientID: new("33333333-3333-3333-3333-333333333333"),
SubscriptionID: "11111111-1111-1111-1111-111111111111",
ClientSecret: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
@@ -2580,7 +2580,7 @@ var AzureSDTestCases = []scrapeCRDTestCase{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeOAuth),
- TenantID: ptr.To(""),
+ TenantID: new(""),
SubscriptionID: "11111111-1111-1111-1111-111111111111",
},
},
@@ -2593,7 +2593,7 @@ var AzureSDTestCases = []scrapeCRDTestCase{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
AuthenticationMethod: ptr.To(monitoringv1alpha1.AuthMethodTypeOAuth),
- ClientID: ptr.To(""),
+ ClientID: new(""),
SubscriptionID: "11111111-1111-1111-1111-111111111111",
},
},
@@ -2630,7 +2630,7 @@ var AzureSDTestCases = []scrapeCRDTestCase{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
SubscriptionID: "11111111-1111-1111-1111-111111111111",
- Port: ptr.To(int32(65534)),
+ Port: new(int32(65534)),
},
},
},
@@ -2642,7 +2642,7 @@ var AzureSDTestCases = []scrapeCRDTestCase{
AzureSDConfigs: []monitoringv1alpha1.AzureSDConfig{
{
SubscriptionID: "11111111-1111-1111-1111-111111111111",
- Port: ptr.To(int32(-1)),
+ Port: new(int32(-1)),
},
},
},
@@ -2660,7 +2660,7 @@ var OVHCloudSDTestCases = []scrapeCRDTestCase{
ApplicationSecret: corev1.SecretKeySelector{Key: "valid-secret-key"},
ConsumerKey: corev1.SecretKeySelector{Key: "valid-consumer-key"},
Service: monitoringv1alpha1.OVHServiceDedicatedServer,
- Endpoint: ptr.To("https://api.ovh.com/endpoint"),
+ Endpoint: new("https://api.ovh.com/endpoint"),
RefreshInterval: ptr.To(monitoringv1.Duration("30s")),
},
},
@@ -2800,7 +2800,7 @@ var OVHCloudSDTestCases = []scrapeCRDTestCase{
ApplicationSecret: corev1.SecretKeySelector{Key: "valid-secret-key"},
ConsumerKey: corev1.SecretKeySelector{Key: "valid-consumer-key"},
Service: monitoringv1alpha1.OVHServiceVPS,
- Endpoint: ptr.To(""),
+ Endpoint: new(""),
},
},
},
@@ -3001,7 +3001,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- Username: ptr.To("admin"),
+ Username: new("admin"),
},
},
},
@@ -3014,7 +3014,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- Username: ptr.To(""),
+ Username: new(""),
},
},
},
@@ -3027,7 +3027,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- UserID: ptr.To("ac3377633149401296f6c0d92d79dc16"),
+ UserID: new("ac3377633149401296f6c0d92d79dc16"),
},
},
},
@@ -3040,7 +3040,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- UserID: ptr.To(""),
+ UserID: new(""),
},
},
},
@@ -3053,7 +3053,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- DomainID: ptr.To("e0353a670a9e496da891347c589539e9"),
+ DomainID: new("e0353a670a9e496da891347c589539e9"),
},
},
},
@@ -3066,7 +3066,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- DomainID: ptr.To(""),
+ DomainID: new(""),
},
},
},
@@ -3079,7 +3079,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- DomainName: ptr.To("default"),
+ DomainName: new("default"),
},
},
},
@@ -3092,7 +3092,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- DomainName: ptr.To(""),
+ DomainName: new(""),
},
},
},
@@ -3105,7 +3105,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- ProjectName: ptr.To("default"),
+ ProjectName: new("default"),
},
},
},
@@ -3118,7 +3118,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- ProjectName: ptr.To(""),
+ ProjectName: new(""),
},
},
},
@@ -3131,7 +3131,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- ProjectID: ptr.To("343d245e850143a096806dfaefa9afdc"),
+ ProjectID: new("343d245e850143a096806dfaefa9afdc"),
},
},
},
@@ -3144,7 +3144,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- ProjectID: ptr.To(""),
+ ProjectID: new(""),
},
},
},
@@ -3157,7 +3157,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- ApplicationCredentialName: ptr.To("monitoring"),
+ ApplicationCredentialName: new("monitoring"),
},
},
},
@@ -3170,7 +3170,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- ApplicationCredentialName: ptr.To(""),
+ ApplicationCredentialName: new(""),
},
},
},
@@ -3183,7 +3183,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- ApplicationCredentialID: ptr.To("aa809205ed614a0e854bac92c0768bb9"),
+ ApplicationCredentialID: new("aa809205ed614a0e854bac92c0768bb9"),
},
},
},
@@ -3196,7 +3196,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- ApplicationCredentialID: ptr.To(""),
+ ApplicationCredentialID: new(""),
},
},
},
@@ -3209,7 +3209,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- AllTenants: ptr.To(true),
+ AllTenants: new(true),
},
},
},
@@ -3222,7 +3222,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- AllTenants: ptr.To(false),
+ AllTenants: new(false),
},
},
},
@@ -3261,7 +3261,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- Port: ptr.To(int32(8080)),
+ Port: new(int32(8080)),
},
},
},
@@ -3274,7 +3274,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- Port: ptr.To(int32(-1)),
+ Port: new(int32(-1)),
},
},
},
@@ -3287,7 +3287,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- Port: ptr.To(int32(65537)),
+ Port: new(int32(65537)),
},
},
},
@@ -3300,7 +3300,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- Availability: ptr.To("public"),
+ Availability: new("public"),
},
},
},
@@ -3313,7 +3313,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- Availability: ptr.To("admin"),
+ Availability: new("admin"),
},
},
},
@@ -3326,7 +3326,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- Availability: ptr.To("internal"),
+ Availability: new("internal"),
},
},
},
@@ -3339,7 +3339,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- Availability: ptr.To("private"),
+ Availability: new("private"),
},
},
},
@@ -3352,7 +3352,7 @@ var OpenStackSDTestCases = []scrapeCRDTestCase{
{
Role: monitoringv1alpha1.OpenStackRoleHypervisor,
Region: "default",
- Availability: ptr.To(""),
+ Availability: new(""),
},
},
},
@@ -3409,7 +3409,7 @@ var KumaSDTestCases = []scrapeCRDTestCase{
KumaSDConfigs: []monitoringv1alpha1.KumaSDConfig{
{
Server: "http://example.com",
- ClientID: ptr.To("valid-client-id"),
+ ClientID: new("valid-client-id"),
},
},
},
@@ -3421,7 +3421,7 @@ var KumaSDTestCases = []scrapeCRDTestCase{
KumaSDConfigs: []monitoringv1alpha1.KumaSDConfig{
{
Server: "http://example.com",
- ClientID: ptr.To(""),
+ ClientID: new(""),
},
},
},
@@ -3481,7 +3481,7 @@ var KumaSDTestCases = []scrapeCRDTestCase{
KumaSDConfigs: []monitoringv1alpha1.KumaSDConfig{
{
Server: "http://example.com",
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -3493,7 +3493,7 @@ var KumaSDTestCases = []scrapeCRDTestCase{
KumaSDConfigs: []monitoringv1alpha1.KumaSDConfig{
{
Server: "http://example.com",
- FollowRedirects: ptr.To(false),
+ FollowRedirects: new(false),
},
},
},
@@ -3505,7 +3505,7 @@ var KumaSDTestCases = []scrapeCRDTestCase{
KumaSDConfigs: []monitoringv1alpha1.KumaSDConfig{
{
Server: "http://example.com",
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -3517,7 +3517,7 @@ var KumaSDTestCases = []scrapeCRDTestCase{
KumaSDConfigs: []monitoringv1alpha1.KumaSDConfig{
{
Server: "http://example.com",
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
},
},
@@ -3766,7 +3766,7 @@ var ScalewaySDTestCases = []scrapeCRDTestCase{
},
Key: "key.pem",
},
- NameFilter: ptr.To("my-server"),
+ NameFilter: new("my-server"),
},
},
},
@@ -3786,7 +3786,7 @@ var ScalewaySDTestCases = []scrapeCRDTestCase{
},
Key: "key.pem",
},
- NameFilter: ptr.To(""),
+ NameFilter: new(""),
},
},
},
@@ -3866,7 +3866,7 @@ var ScalewaySDTestCases = []scrapeCRDTestCase{
},
Key: "key.pem",
},
- Zone: ptr.To("fr-par-1"),
+ Zone: new("fr-par-1"),
},
},
},
@@ -3886,7 +3886,7 @@ var ScalewaySDTestCases = []scrapeCRDTestCase{
},
Key: "key.pem",
},
- Zone: ptr.To(""),
+ Zone: new(""),
},
},
},
@@ -3906,7 +3906,7 @@ var ScalewaySDTestCases = []scrapeCRDTestCase{
},
Key: "key.pem",
},
- Port: ptr.To(int32(8080)),
+ Port: new(int32(8080)),
},
},
},
@@ -3926,7 +3926,7 @@ var ScalewaySDTestCases = []scrapeCRDTestCase{
},
Key: "key.pem",
},
- Port: ptr.To(int32(65536)), // maximum Port number = 65535
+ Port: new(int32(65536)), // maximum Port number = 65535
},
},
},
@@ -3946,7 +3946,7 @@ var ScalewaySDTestCases = []scrapeCRDTestCase{
},
Key: "key.pem",
},
- Port: ptr.To(int32(-1)), // minimum Port number = 0;
+ Port: new(int32(-1)), // minimum Port number = 0;
},
},
},
@@ -4034,7 +4034,7 @@ var DockerSDTestCases = []scrapeCRDTestCase{
DockerSDConfigs: []monitoringv1alpha1.DockerSDConfig{
{
Host: "unix:///var/run/docker.sock",
- Port: ptr.To(int32(80)),
+ Port: new(int32(80)),
},
},
},
@@ -4046,7 +4046,7 @@ var DockerSDTestCases = []scrapeCRDTestCase{
DockerSDConfigs: []monitoringv1alpha1.DockerSDConfig{
{
Host: "unix:///var/run/docker.sock",
- Port: ptr.To(int32(-1)),
+ Port: new(int32(-1)),
},
},
},
@@ -4058,7 +4058,7 @@ var DockerSDTestCases = []scrapeCRDTestCase{
DockerSDConfigs: []monitoringv1alpha1.DockerSDConfig{
{
Host: "unix:///var/run/docker.sock",
- HostNetworkingHost: ptr.To("localhost"),
+ HostNetworkingHost: new("localhost"),
},
},
},
@@ -4070,7 +4070,7 @@ var DockerSDTestCases = []scrapeCRDTestCase{
DockerSDConfigs: []monitoringv1alpha1.DockerSDConfig{
{
Host: "unix:///var/run/docker.sock",
- HostNetworkingHost: ptr.To(""),
+ HostNetworkingHost: new(""),
},
},
},
@@ -4082,7 +4082,7 @@ var DockerSDTestCases = []scrapeCRDTestCase{
DockerSDConfigs: []monitoringv1alpha1.DockerSDConfig{
{
Host: "unix:///var/run/docker.sock",
- MatchFirstNetwork: ptr.To(true),
+ MatchFirstNetwork: new(true),
},
},
},
@@ -4094,7 +4094,7 @@ var DockerSDTestCases = []scrapeCRDTestCase{
DockerSDConfigs: []monitoringv1alpha1.DockerSDConfig{
{
Host: "unix:///var/run/docker.sock",
- MatchFirstNetwork: ptr.To(false),
+ MatchFirstNetwork: new(false),
},
},
},
@@ -4198,7 +4198,7 @@ var DockerSDTestCases = []scrapeCRDTestCase{
DockerSDConfigs: []monitoringv1alpha1.DockerSDConfig{
{
Host: "unix:///var/run/docker.sock",
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -4210,7 +4210,7 @@ var DockerSDTestCases = []scrapeCRDTestCase{
DockerSDConfigs: []monitoringv1alpha1.DockerSDConfig{
{
Host: "unix:///var/run/docker.sock",
- FollowRedirects: ptr.To(false),
+ FollowRedirects: new(false),
},
},
},
@@ -4222,7 +4222,7 @@ var DockerSDTestCases = []scrapeCRDTestCase{
DockerSDConfigs: []monitoringv1alpha1.DockerSDConfig{
{
Host: "unix:///var/run/docker.sock",
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -4234,7 +4234,7 @@ var DockerSDTestCases = []scrapeCRDTestCase{
DockerSDConfigs: []monitoringv1alpha1.DockerSDConfig{
{
Host: "unix:///var/run/docker.sock",
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
},
},
@@ -4262,7 +4262,7 @@ var DockerSwarmSDTestCases = []scrapeCRDTestCase{
{
Host: "tcp://localhost",
Role: "Services",
- Port: ptr.To(int32(80)),
+ Port: new(int32(80)),
},
},
},
@@ -4275,7 +4275,7 @@ var DockerSwarmSDTestCases = []scrapeCRDTestCase{
{
Host: "tcp://localhost",
Role: "Services",
- Port: ptr.To(int32(-1)),
+ Port: new(int32(-1)),
},
},
},
@@ -4385,7 +4385,7 @@ var DockerSwarmSDTestCases = []scrapeCRDTestCase{
{
Host: "tcp://localhost",
Role: "Services",
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -4398,7 +4398,7 @@ var DockerSwarmSDTestCases = []scrapeCRDTestCase{
{
Host: "tcp://localhost",
Role: "Services",
- FollowRedirects: ptr.To(false),
+ FollowRedirects: new(false),
},
},
},
@@ -4411,7 +4411,7 @@ var DockerSwarmSDTestCases = []scrapeCRDTestCase{
{
Host: "tcp://localhost",
Role: "Services",
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -4424,7 +4424,7 @@ var DockerSwarmSDTestCases = []scrapeCRDTestCase{
{
Host: "tcp://localhost",
Role: "Services",
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
},
},
@@ -4461,7 +4461,7 @@ var HetznerSDTestCases = []scrapeCRDTestCase{
HetznerSDConfigs: []monitoringv1alpha1.HetznerSDConfig{
{
Role: "Hcloud",
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -4473,7 +4473,7 @@ var HetznerSDTestCases = []scrapeCRDTestCase{
HetznerSDConfigs: []monitoringv1alpha1.HetznerSDConfig{
{
Role: "Hcloud",
- FollowRedirects: ptr.To(false),
+ FollowRedirects: new(false),
},
},
},
@@ -4485,7 +4485,7 @@ var HetznerSDTestCases = []scrapeCRDTestCase{
HetznerSDConfigs: []monitoringv1alpha1.HetznerSDConfig{
{
Role: "Hcloud",
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -4497,7 +4497,7 @@ var HetznerSDTestCases = []scrapeCRDTestCase{
HetznerSDConfigs: []monitoringv1alpha1.HetznerSDConfig{
{
Role: "Hcloud",
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
},
},
@@ -4509,7 +4509,7 @@ var HetznerSDTestCases = []scrapeCRDTestCase{
HetznerSDConfigs: []monitoringv1alpha1.HetznerSDConfig{
{
Role: "Hcloud",
- Port: ptr.To(int32(80)),
+ Port: new(int32(80)),
},
},
},
@@ -4521,7 +4521,7 @@ var HetznerSDTestCases = []scrapeCRDTestCase{
HetznerSDConfigs: []monitoringv1alpha1.HetznerSDConfig{
{
Role: "Hcloud",
- Port: ptr.To(int32(-1)),
+ Port: new(int32(-1)),
},
},
},
@@ -4557,7 +4557,7 @@ var HetznerSDTestCases = []scrapeCRDTestCase{
HetznerSDConfigs: []monitoringv1alpha1.HetznerSDConfig{
{
Role: "Hcloud",
- LabelSelector: ptr.To("foo"),
+ LabelSelector: new("foo"),
},
},
},
@@ -4569,7 +4569,7 @@ var HetznerSDTestCases = []scrapeCRDTestCase{
HetznerSDConfigs: []monitoringv1alpha1.HetznerSDConfig{
{
Role: "Hcloud",
- LabelSelector: ptr.To(""),
+ LabelSelector: new(""),
},
},
},
@@ -4583,7 +4583,7 @@ var LinodeSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LinodeSDConfigs: []monitoringv1alpha1.LinodeSDConfig{
{
- Region: ptr.To("us-east"),
+ Region: new("us-east"),
},
},
},
@@ -4594,7 +4594,7 @@ var LinodeSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LinodeSDConfigs: []monitoringv1alpha1.LinodeSDConfig{
{
- Region: ptr.To(""),
+ Region: new(""),
},
},
},
@@ -4605,7 +4605,7 @@ var LinodeSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LinodeSDConfigs: []monitoringv1alpha1.LinodeSDConfig{
{
- Port: ptr.To(int32(80)),
+ Port: new(int32(80)),
},
},
},
@@ -4616,7 +4616,7 @@ var LinodeSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LinodeSDConfigs: []monitoringv1alpha1.LinodeSDConfig{
{
- Port: ptr.To(int32(-1)),
+ Port: new(int32(-1)),
},
},
},
@@ -4627,7 +4627,7 @@ var LinodeSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LinodeSDConfigs: []monitoringv1alpha1.LinodeSDConfig{
{
- TagSeparator: ptr.To(","),
+ TagSeparator: new(","),
},
},
},
@@ -4660,7 +4660,7 @@ var LinodeSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LinodeSDConfigs: []monitoringv1alpha1.LinodeSDConfig{
{
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -4671,7 +4671,7 @@ var LinodeSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LinodeSDConfigs: []monitoringv1alpha1.LinodeSDConfig{
{
- FollowRedirects: ptr.To(false),
+ FollowRedirects: new(false),
},
},
},
@@ -4682,7 +4682,7 @@ var LinodeSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LinodeSDConfigs: []monitoringv1alpha1.LinodeSDConfig{
{
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -4693,7 +4693,7 @@ var LinodeSDTestCases = []scrapeCRDTestCase{
scrapeConfigSpec: monitoringv1alpha1.ScrapeConfigSpec{
LinodeSDConfigs: []monitoringv1alpha1.LinodeSDConfig{
{
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
},
},
@@ -4741,7 +4741,7 @@ var NomadSDTestCases = []scrapeCRDTestCase{
NomadSDConfigs: []monitoringv1alpha1.NomadSDConfig{
{
Server: "http://localhost:4646",
- AllowStale: ptr.To(true),
+ AllowStale: new(true),
},
},
},
@@ -4753,7 +4753,7 @@ var NomadSDTestCases = []scrapeCRDTestCase{
NomadSDConfigs: []monitoringv1alpha1.NomadSDConfig{
{
Server: "http://localhost:4646",
- AllowStale: ptr.To(false),
+ AllowStale: new(false),
},
},
},
@@ -4765,7 +4765,7 @@ var NomadSDTestCases = []scrapeCRDTestCase{
NomadSDConfigs: []monitoringv1alpha1.NomadSDConfig{
{
Server: "http://localhost:4646",
- Namespace: ptr.To("default"),
+ Namespace: new("default"),
},
},
},
@@ -4777,7 +4777,7 @@ var NomadSDTestCases = []scrapeCRDTestCase{
NomadSDConfigs: []monitoringv1alpha1.NomadSDConfig{
{
Server: "http://localhost:4646",
- Namespace: ptr.To(""),
+ Namespace: new(""),
},
},
},
@@ -4813,7 +4813,7 @@ var NomadSDTestCases = []scrapeCRDTestCase{
NomadSDConfigs: []monitoringv1alpha1.NomadSDConfig{
{
Server: "http://localhost:4646",
- Region: ptr.To("us-east"),
+ Region: new("us-east"),
},
},
},
@@ -4825,7 +4825,7 @@ var NomadSDTestCases = []scrapeCRDTestCase{
NomadSDConfigs: []monitoringv1alpha1.NomadSDConfig{
{
Server: "http://localhost:4646",
- Region: ptr.To(""),
+ Region: new(""),
},
},
},
@@ -4837,7 +4837,7 @@ var NomadSDTestCases = []scrapeCRDTestCase{
NomadSDConfigs: []monitoringv1alpha1.NomadSDConfig{
{
Server: "http://localhost:4646",
- TagSeparator: ptr.To(","),
+ TagSeparator: new(","),
},
},
},
@@ -4849,7 +4849,7 @@ var NomadSDTestCases = []scrapeCRDTestCase{
NomadSDConfigs: []monitoringv1alpha1.NomadSDConfig{
{
Server: "http://localhost:4646",
- TagSeparator: ptr.To(""),
+ TagSeparator: new(""),
},
},
},
@@ -4861,7 +4861,7 @@ var NomadSDTestCases = []scrapeCRDTestCase{
NomadSDConfigs: []monitoringv1alpha1.NomadSDConfig{
{
Server: "http://localhost:4646",
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -4873,7 +4873,7 @@ var NomadSDTestCases = []scrapeCRDTestCase{
NomadSDConfigs: []monitoringv1alpha1.NomadSDConfig{
{
Server: "http://localhost:4646",
- FollowRedirects: ptr.To(false),
+ FollowRedirects: new(false),
},
},
},
@@ -4885,7 +4885,7 @@ var NomadSDTestCases = []scrapeCRDTestCase{
NomadSDConfigs: []monitoringv1alpha1.NomadSDConfig{
{
Server: "http://localhost:4646",
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -4897,7 +4897,7 @@ var NomadSDTestCases = []scrapeCRDTestCase{
NomadSDConfigs: []monitoringv1alpha1.NomadSDConfig{
{
Server: "http://localhost:4646",
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
},
},
@@ -4971,7 +4971,7 @@ var PuppetDBSDTestCases = []scrapeCRDTestCase{
{
URL: "https://puppetdb.example.com",
Query: "nodes { certname = \"macbook-pro.local\" }",
- IncludeParameters: ptr.To(true),
+ IncludeParameters: new(true),
},
},
},
@@ -4984,7 +4984,7 @@ var PuppetDBSDTestCases = []scrapeCRDTestCase{
{
URL: "https://puppetdb.example.com",
Query: "nodes { certname = \"macbook-pro.local\" }",
- IncludeParameters: ptr.To(false),
+ IncludeParameters: new(false),
},
},
},
@@ -5023,7 +5023,7 @@ var PuppetDBSDTestCases = []scrapeCRDTestCase{
{
URL: "https://puppetdb.example.com",
Query: "nodes { certname = \"macbook-pro.local\" }",
- Port: ptr.To(int32(80)),
+ Port: new(int32(80)),
},
},
},
@@ -5036,7 +5036,7 @@ var PuppetDBSDTestCases = []scrapeCRDTestCase{
{
URL: "https://puppetdb.example.com",
Query: "nodes { certname = \"macbook-pro.local\" }",
- Port: ptr.To(int32(-1)),
+ Port: new(int32(-1)),
},
},
},
@@ -5049,7 +5049,7 @@ var PuppetDBSDTestCases = []scrapeCRDTestCase{
{
URL: "https://puppetdb.example.com",
Query: "nodes { certname = \"macbook-pro.local\" }",
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -5062,7 +5062,7 @@ var PuppetDBSDTestCases = []scrapeCRDTestCase{
{
URL: "https://puppetdb.example.com",
Query: "nodes { certname = \"macbook-pro.local\" }",
- FollowRedirects: ptr.To(false),
+ FollowRedirects: new(false),
},
},
},
@@ -5075,7 +5075,7 @@ var PuppetDBSDTestCases = []scrapeCRDTestCase{
{
URL: "https://puppetdb.example.com",
Query: "nodes { certname = \"macbook-pro.local\" }",
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -5088,7 +5088,7 @@ var PuppetDBSDTestCases = []scrapeCRDTestCase{
{
URL: "https://puppetdb.example.com",
Query: "nodes { certname = \"macbook-pro.local\" }",
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
},
},
@@ -5136,7 +5136,7 @@ var EurekaSDTestCases = []scrapeCRDTestCase{
EurekaSDConfigs: []monitoringv1alpha1.EurekaSDConfig{
{
Server: "http://localhost:8761/eureka",
- FollowRedirects: ptr.To(true),
+ FollowRedirects: new(true),
},
},
},
@@ -5148,7 +5148,7 @@ var EurekaSDTestCases = []scrapeCRDTestCase{
EurekaSDConfigs: []monitoringv1alpha1.EurekaSDConfig{
{
Server: "http://localhost:8761/eureka",
- FollowRedirects: ptr.To(false),
+ FollowRedirects: new(false),
},
},
},
@@ -5160,7 +5160,7 @@ var EurekaSDTestCases = []scrapeCRDTestCase{
EurekaSDConfigs: []monitoringv1alpha1.EurekaSDConfig{
{
Server: "http://localhost:8761/eureka",
- EnableHTTP2: ptr.To(true),
+ EnableHTTP2: new(true),
},
},
},
@@ -5172,7 +5172,7 @@ var EurekaSDTestCases = []scrapeCRDTestCase{
EurekaSDConfigs: []monitoringv1alpha1.EurekaSDConfig{
{
Server: "http://localhost:8761/eureka",
- EnableHTTP2: ptr.To(false),
+ EnableHTTP2: new(false),
},
},
},
diff --git a/test/e2e/thanosruler_test.go b/test/e2e/thanosruler_test.go
index 08111eeb99d..1740eed1242 100644
--- a/test/e2e/thanosruler_test.go
+++ b/test/e2e/thanosruler_test.go
@@ -27,7 +27,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
- "k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
testFramework "github.com/prometheus-operator/prometheus-operator/test/framework"
@@ -276,7 +275,7 @@ func testTRMinReadySeconds(t *testing.T) {
kubeClient := framework.KubeClient
thanosRuler := framework.MakeBasicThanosRuler("test-thanos", 1, "http://test.example.com")
- thanosRuler.Spec.MinReadySeconds = ptr.To(int32(5))
+ thanosRuler.Spec.MinReadySeconds = new(int32(5))
thanosRuler, err := framework.CreateThanosRulerAndWaitUntilReady(context.Background(), ns, thanosRuler)
require.NoError(t, err)
@@ -284,7 +283,7 @@ func testTRMinReadySeconds(t *testing.T) {
require.NoError(t, err)
require.Equal(t, int32(5), trSS.Spec.MinReadySeconds)
- thanosRuler.Spec.MinReadySeconds = ptr.To(int32(10))
+ thanosRuler.Spec.MinReadySeconds = new(int32(10))
_, err = framework.PatchThanosRulerAndWaitUntilReady(context.Background(), thanosRuler.Name, ns, thanosRuler.Spec)
require.NoError(t, err)
@@ -473,7 +472,7 @@ func testTRCheckStorageClass(t *testing.T) {
Storage: &monitoringv1.StorageSpec{
VolumeClaimTemplate: monitoringv1.EmbeddedPersistentVolumeClaim{
Spec: corev1.PersistentVolumeClaimSpec{
- StorageClassName: ptr.To("unknown-storage-class"),
+ StorageClassName: new("unknown-storage-class"),
Resources: corev1.VolumeResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("200Mi"),
@@ -575,9 +574,9 @@ func testThanosRulerStateless(t *testing.T) {
// remote-write receiver for Thanos ruler.
prometheus := framework.MakeBasicPrometheus(ns, name, name, 1)
prometheus.Spec.EnableRemoteWriteReceiver = true
- prometheus, err := framework.CreatePrometheusAndWaitUntilReady(ctx, ns, prometheus)
- // Ensure that the Promehteus resource selects no rule.
+ // Ensure that Prometheus does not evaluate rules; only Thanos Ruler should.
prometheus.Spec.RuleSelector = nil
+ prometheus, err := framework.CreatePrometheusAndWaitUntilReady(ctx, ns, prometheus)
require.NoError(t, err)
promSVC := framework.MakePrometheusService(prometheus.Name, name, corev1.ServiceTypeClusterIP)
diff --git a/test/e2e/topology_sharding_test.go b/test/e2e/topology_sharding_test.go
index bac6619eaec..70e6ba4b752 100644
--- a/test/e2e/topology_sharding_test.go
+++ b/test/e2e/topology_sharding_test.go
@@ -62,10 +62,15 @@ func testPrometheusTopologySharding(t *testing.T) {
err = framework.DeployAppServiceMonitor(ctx, ns)
require.NoError(t, err)
+ // Create a pod monitor for the app deployment.
+ err = framework.DeployAppPodMonitor(ctx, ns)
+ require.NoError(t, err)
+
const (
prometheusName = "topology-sharding"
)
p := framework.MakeBasicPrometheus(ns, prometheusName, testFramework.AppGroupLabel, 1)
+ p.Spec.ServiceDiscoveryRole = ptr.To(monitoringv1.EndpointSliceRole)
p.Spec.ShardingStrategy = &monitoringv1.ShardingStrategy{
Mode: ptr.To(monitoringv1.TopologyShardingStrategyMode),
Topology: &monitoringv1.TopologyShardingStrategy{
@@ -76,7 +81,7 @@ func testPrometheusTopologySharding(t *testing.T) {
Values: []string{"zone-a", "zone-b"},
},
}
- p.Spec.Shards = ptr.To(int32(2))
+ p.Spec.Shards = new(int32(2))
shardServices := make([]*corev1.Service, 2)
for i := range shardServices {
@@ -112,35 +117,81 @@ func testPrometheusTopologySharding(t *testing.T) {
}
// Ensure that each shard scrapes a non-zero number of targets and that
- // the total across all shards equals the number of app replicas (10).
+ // the total across all shards for a given monitor resource equals the
+ // number of app replicas (10).
t.Run("target distribution", func(t *testing.T) {
- var pollErr error
- err := wait.PollUntilContextTimeout(ctx, 5*time.Second, 2*time.Minute, false, func(ctx context.Context) (bool, error) {
- total := 0
- for _, svc := range shardServices {
- err := framework.WaitForHealthyTargetsWithCondition(
- context.Background(),
- ns,
- svc.Name,
- func(targets []*testFramework.Target) error {
- if len(targets) == 0 {
- return errors.New("expected non-zero targets")
- }
- total += len(targets)
- return nil
- },
- )
- if err != nil {
- pollErr = fmt.Errorf("%s: %w", svc.Name, err)
+ t.Run("service monitor", func(t *testing.T) {
+ var pollErr error
+ err := wait.PollUntilContextTimeout(ctx, 5*time.Second, 2*time.Minute, false, func(ctx context.Context) (bool, error) {
+ total := 0
+ for _, svc := range shardServices {
+ err := framework.WaitForHealthyTargetsWithCondition(
+ context.Background(),
+ ns,
+ svc.Name,
+ func(targets []*testFramework.Target) error {
+ count := 0
+ for _, target := range targets {
+ if target.Labels["job"] == testFramework.AppGroupLabel {
+ count++
+ }
+ }
+ if count == 0 {
+ return errors.New("expected non-zero service monitor targets")
+ }
+ total += count
+ return nil
+ },
+ )
+ if err != nil {
+ pollErr = fmt.Errorf("%s: %w", svc.Name, err)
+ return false, nil
+ }
+ }
+ if total != 10 {
+ pollErr = fmt.Errorf("expected 10 service monitor targets, got %d", total)
+ return false, nil
+ }
+ return true, nil
+ })
+ require.NoError(t, err, fmt.Sprintf("%s: %s", err, pollErr))
+ })
+
+ t.Run("pod monitor", func(t *testing.T) {
+ var pollErr error
+ err := wait.PollUntilContextTimeout(ctx, 5*time.Second, 2*time.Minute, false, func(ctx context.Context) (bool, error) {
+ total := 0
+ for _, svc := range shardServices {
+ err := framework.WaitForHealthyTargetsWithCondition(
+ context.Background(),
+ ns,
+ svc.Name,
+ func(targets []*testFramework.Target) error {
+ count := 0
+ for _, target := range targets {
+ if target.Labels["job"] == ns+"/"+testFramework.AppGroupLabel {
+ count++
+ }
+ }
+ if count == 0 {
+ return errors.New("expected non-zero pod monitor targets")
+ }
+ total += count
+ return nil
+ },
+ )
+ if err != nil {
+ pollErr = fmt.Errorf("%s: %w", svc.Name, err)
+ return false, nil
+ }
+ }
+ if total != 10 {
+ pollErr = fmt.Errorf("expected 10 pod monitor targets, got %d", total)
return false, nil
}
- }
- if total != 10 {
- pollErr = fmt.Errorf("expected 10 total targets, got %d", total)
- return false, nil
- }
- return true, nil
+ return true, nil
+ })
+ require.NoError(t, err, fmt.Sprintf("%s: %s", err, pollErr))
})
- require.NoError(t, err, fmt.Sprintf("%s: %s", err, pollErr))
})
}
diff --git a/test/framework/alertmanager.go b/test/framework/alertmanager.go
index f7623f3faef..ac36d3f2985 100644
--- a/test/framework/alertmanager.go
+++ b/test/framework/alertmanager.go
@@ -36,7 +36,6 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/util/yaml"
- "k8s.io/utils/ptr"
"github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
@@ -285,7 +284,7 @@ func (f *Framework) PatchAlertmanager(ctx context.Context, name, ns string, spec
types.ApplyPatchType,
b,
metav1.PatchOptions{
- Force: ptr.To(true),
+ Force: new(true),
FieldManager: "e2e-test",
},
)
@@ -303,7 +302,7 @@ func (f *Framework) UpdateAlertmanagerReplicasAndWaitUntilReady(ctx context.Cont
name,
ns,
monitoringv1.AlertmanagerSpec{
- Replicas: ptr.To(replicas),
+ Replicas: new(replicas),
},
)
}
@@ -508,7 +507,7 @@ func (f *Framework) WaitForAlertmanagerFiringAlert(ctx context.Context, ns, svcN
}
for _, alert := range alerts {
- if alert.Labels["alertname"] == alertName && alert.Status.State != ptr.To("firing") {
+ if alert.Labels["alertname"] == alertName && alert.Status.State != new("firing") {
return true, nil
}
}
diff --git a/test/framework/app.go b/test/framework/app.go
index 221790e7ce6..5bdac062534 100644
--- a/test/framework/app.go
+++ b/test/framework/app.go
@@ -19,7 +19,6 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
@@ -27,8 +26,10 @@ import (
const (
// AppGroupLabel is the value of the "group" label for the instrumented sample
// app resources.
- AppGroupLabel = "app"
- appSecretAuthName = "auth"
+ AppGroupLabel = "app"
+ appSecretAuthName = "auth"
+ appSecretAuthUserKey = "user"
+ appSecretAuthPassKey = "pass"
)
// DeployBasicAuthApp deploys the instrumented sample app with the given number
@@ -39,7 +40,10 @@ func (f *Framework) DeployBasicAuthApp(ctx context.Context, ns string, replicas
if err != nil {
return err
}
- dep.Spec.Replicas = ptr.To(replicas)
+ dep.Spec.Replicas = new(replicas)
+ dep.Labels = map[string]string{"group": AppGroupLabel}
+ dep.Spec.Selector.MatchLabels = dep.Labels
+ dep.Spec.Template.Labels = dep.Labels
if err := f.CreateDeployment(ctx, ns, dep); err != nil {
return err
@@ -47,10 +51,8 @@ func (f *Framework) DeployBasicAuthApp(ctx context.Context, ns string, replicas
svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
- Name: AppGroupLabel,
- Labels: map[string]string{
- "group": AppGroupLabel,
- },
+ Name: AppGroupLabel,
+ Labels: dep.Labels,
},
Spec: corev1.ServiceSpec{
Selector: dep.Spec.Template.Labels,
@@ -70,10 +72,11 @@ func (f *Framework) DeployBasicAuthApp(ctx context.Context, ns string, replicas
ObjectMeta: metav1.ObjectMeta{
Name: appSecretAuthName,
Namespace: ns,
+ Labels: dep.Labels,
},
StringData: map[string]string{
- "user": "user",
- "pass": "pass",
+ appSecretAuthUserKey: "user",
+ appSecretAuthPassKey: "pass",
},
Type: corev1.SecretTypeOpaque,
}
@@ -81,6 +84,33 @@ func (f *Framework) DeployBasicAuthApp(ctx context.Context, ns string, replicas
return err
}
+// DeployAppPodMonitor creates a PodMonitor for the app deployed by DeployBasicAuthApp.
+func (f *Framework) DeployAppPodMonitor(ctx context.Context, ns string) error {
+ pm := f.MakeBasicPodMonitor(AppGroupLabel)
+ pm.Spec.PodMetricsEndpoints[0] = monitoringv1.PodMetricsEndpoint{
+ Interval: monitoringv1.Duration("5s"),
+ Port: new("web"),
+ HTTPConfigWithProxy: monitoringv1.HTTPConfigWithProxy{
+ HTTPConfig: monitoringv1.HTTPConfig{
+ HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
+ BasicAuth: &monitoringv1.BasicAuth{
+ Username: corev1.SecretKeySelector{
+ Key: appSecretAuthUserKey,
+ LocalObjectReference: corev1.LocalObjectReference{Name: appSecretAuthName},
+ },
+ Password: corev1.SecretKeySelector{
+ Key: appSecretAuthPassKey,
+ LocalObjectReference: corev1.LocalObjectReference{Name: appSecretAuthName},
+ },
+ },
+ },
+ },
+ },
+ }
+ _, err := f.MonClientV1.PodMonitors(ns).Create(ctx, pm, metav1.CreateOptions{})
+ return err
+}
+
// DeployAppServiceMonitor creates a ServiceMonitor for the app deployed by DeployBasicAuthApp.
func (f *Framework) DeployAppServiceMonitor(ctx context.Context, ns string) error {
sm := f.MakeBasicServiceMonitor(AppGroupLabel)
@@ -92,11 +122,11 @@ func (f *Framework) DeployAppServiceMonitor(ctx context.Context, ns string) erro
HTTPConfigWithoutTLS: monitoringv1.HTTPConfigWithoutTLS{
BasicAuth: &monitoringv1.BasicAuth{
Username: corev1.SecretKeySelector{
- Key: "user",
+ Key: appSecretAuthUserKey,
LocalObjectReference: corev1.LocalObjectReference{Name: appSecretAuthName},
},
Password: corev1.SecretKeySelector{
- Key: "pass",
+ Key: appSecretAuthPassKey,
LocalObjectReference: corev1.LocalObjectReference{Name: appSecretAuthName},
},
},
diff --git a/test/framework/context.go b/test/framework/context.go
index c1a1b64bfea..09c99b9764a 100644
--- a/test/framework/context.go
+++ b/test/framework/context.go
@@ -21,6 +21,7 @@ import (
"io"
"os"
"path/filepath"
+ "slices"
"strconv"
"strings"
"testing"
@@ -570,8 +571,8 @@ func (ctx *TestCtx) Cleanup(t *testing.T) {
t.Helper()
var eg errgroup.Group
- for i := len(ctx.cleanUpFns) - 1; i >= 0; i-- {
- eg.Go(ctx.cleanUpFns[i])
+ for _, v := range slices.Backward(ctx.cleanUpFns) {
+ eg.Go(v)
}
if err := eg.Wait(); err != nil {
diff --git a/test/framework/framework.go b/test/framework/framework.go
index 8a93c3c7a3e..76955179808 100644
--- a/test/framework/framework.go
+++ b/test/framework/framework.go
@@ -43,7 +43,6 @@ import (
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
certutil "k8s.io/client-go/util/cert"
- "k8s.io/utils/ptr"
"github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
@@ -817,7 +816,7 @@ func (f *Framework) CreateOrUpdateAdmissionWebhookServer(
return nil, nil, err
}
if len(nodes) == 1 {
- deploy.Spec.Replicas = ptr.To(int32(1))
+ deploy.Spec.Replicas = new(int32(1))
deploy.Spec.Template.Spec.Affinity = nil
deploy.Spec.Strategy = appsv1.DeploymentStrategy{}
}
diff --git a/test/framework/prometheus.go b/test/framework/prometheus.go
index c3829fcf843..b3b3b6aa1b6 100644
--- a/test/framework/prometheus.go
+++ b/test/framework/prometheus.go
@@ -224,7 +224,7 @@ func (prwtc PromRemoteWriteTestConfig) AddRemoteWriteWithTLSToPrometheus(p *moni
URL: monitoringv1.URL(url),
MessageVersion: prwtc.RemoteWriteMessageVersion,
QueueConfig: &monitoringv1.QueueConfig{
- BatchSendDeadline: (*monitoringv1.Duration)(ptr.To("1s")),
+ BatchSendDeadline: (*monitoringv1.Duration)(new("1s")),
},
}}
@@ -234,7 +234,7 @@ func (prwtc PromRemoteWriteTestConfig) AddRemoteWriteWithTLSToPrometheus(p *moni
p.Spec.RemoteWrite[0].TLSConfig = &monitoringv1.TLSConfig{
SafeTLSConfig: monitoringv1.SafeTLSConfig{
- ServerName: ptr.To("caandserver.com"),
+ ServerName: new("caandserver.com"),
},
}
@@ -285,7 +285,7 @@ func (prwtc PromRemoteWriteTestConfig) AddRemoteWriteWithTLSToPrometheus(p *moni
}
case prwtc.InsecureSkipVerify:
- p.Spec.RemoteWrite[0].TLSConfig.InsecureSkipVerify = ptr.To(true)
+ p.Spec.RemoteWrite[0].TLSConfig.InsecureSkipVerify = new(true)
}
}
@@ -317,7 +317,7 @@ func (f *Framework) EnableRemoteWriteReceiverWithTLS(p *monitoringv1.Prometheus)
Key: PrivateKey,
},
// Liveness/readiness probes don't work when using "RequireAndVerifyClientCert".
- ClientAuthType: ptr.To("VerifyClientCertIfGiven"),
+ ClientAuthType: new("VerifyClientCertIfGiven"),
},
},
}
@@ -327,7 +327,7 @@ func (f *Framework) AddAlertingToPrometheus(p *monitoringv1.Prometheus, ns, name
p.Spec.Alerting = &monitoringv1.AlertingSpec{
Alertmanagers: []monitoringv1.AlertmanagerEndpoints{
{
- Namespace: ptr.To(ns),
+ Namespace: new(ns),
Name: fmt.Sprintf("alertmanager-%s", name),
Port: intstr.FromString("web"),
},
@@ -375,7 +375,7 @@ func (f *Framework) MakeBasicPodMonitor(name string) *monitoringv1.PodMonitor {
},
PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
- Port: ptr.To("web"),
+ Port: new("web"),
Interval: "30s",
},
},
@@ -450,7 +450,7 @@ func (f *Framework) UpdatePrometheusReplicasAndWaitUntilReady(ctx context.Contex
ns,
monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
- Replicas: ptr.To(replicas),
+ Replicas: new(replicas),
},
},
)
@@ -497,7 +497,7 @@ func (f *Framework) PatchPrometheus(ctx context.Context, name, ns string, spec m
types.ApplyPatchType,
b,
metav1.PatchOptions{
- Force: ptr.To(true),
+ Force: new(true),
FieldManager: "e2e-test",
},
)
diff --git a/test/framework/prometheusagent.go b/test/framework/prometheusagent.go
index 7bb012939f7..5ea4bdbdd0e 100644
--- a/test/framework/prometheusagent.go
+++ b/test/framework/prometheusagent.go
@@ -249,7 +249,7 @@ func (f *Framework) PatchPrometheusAgent(ctx context.Context, name, ns string, s
types.ApplyPatchType,
b,
metav1.PatchOptions{
- Force: ptr.To(true),
+ Force: new(true),
FieldManager: "e2e-test",
},
)
diff --git a/test/framework/statefulset.go b/test/framework/statefulset.go
index 2051a8fa3bb..15ffc0f1317 100644
--- a/test/framework/statefulset.go
+++ b/test/framework/statefulset.go
@@ -19,9 +19,11 @@ import (
"fmt"
"maps"
"slices"
+ "time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
+ "k8s.io/apimachinery/pkg/util/wait"
)
// RemoveAllLabelsFromStatefulSet removes all labels from a StatefulSet using JSON Patch.
@@ -51,3 +53,25 @@ func (f *Framework) RemoveAllLabelsFromStatefulSet(ctx context.Context, name, na
return nil
}
+
+// WaitForStatefulSetReplicas polls until the number of StatefulSets in the
+// given namespace matching listOpts equals expected.
+func (f *Framework) WaitForStatefulSetReplicas(ctx context.Context, ns string, listOpts metav1.ListOptions, expected int) error {
+ var loopErr error
+ err := wait.PollUntilContextTimeout(ctx, 5*time.Second, 2*time.Minute, true, func(ctx context.Context) (bool, error) {
+ sts, listErr := f.KubeClient.AppsV1().StatefulSets(ns).List(ctx, listOpts)
+ if listErr != nil {
+ loopErr = fmt.Errorf("failed to list StatefulSets in namespace %s: %w", ns, listErr)
+ return false, nil
+ }
+ if len(sts.Items) != expected {
+ loopErr = fmt.Errorf("expected %d StatefulSets in namespace %s, got %d", expected, ns, len(sts.Items))
+ return false, nil
+ }
+ return true, nil
+ })
+ if err != nil {
+ return fmt.Errorf("%v: %w", loopErr, err)
+ }
+ return nil
+}
diff --git a/test/framework/thanosruler.go b/test/framework/thanosruler.go
index 4701d70ed41..daeb21a55f5 100644
--- a/test/framework/thanosruler.go
+++ b/test/framework/thanosruler.go
@@ -96,7 +96,7 @@ func (f *Framework) PatchThanosRuler(ctx context.Context, name, ns string, spec
types.ApplyPatchType,
b,
metav1.PatchOptions{
- Force: ptr.To(true),
+ Force: new(true),
FieldManager: "e2e-test",
},
)
@@ -114,7 +114,7 @@ func (f *Framework) UpdateThanosRulerReplicasAndWaitUntilReady(ctx context.Conte
name,
ns,
monitoringv1.ThanosRulerSpec{
- Replicas: ptr.To(replicas),
+ Replicas: new(replicas),
},
)
}
diff --git a/vendor/github.com/armon/go-metrics/.gitignore b/vendor/github.com/armon/go-metrics/.gitignore
new file mode 100644
index 00000000000..e5750f5720e
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/.gitignore
@@ -0,0 +1,26 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+/metrics.out
+
+.idea
diff --git a/vendor/github.com/armon/go-metrics/.travis.yml b/vendor/github.com/armon/go-metrics/.travis.yml
new file mode 100644
index 00000000000..87d230c8d78
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/.travis.yml
@@ -0,0 +1,13 @@
+language: go
+
+go:
+ - "1.x"
+
+env:
+ - GO111MODULE=on
+
+install:
+ - go get ./...
+
+script:
+ - go test ./...
diff --git a/vendor/github.com/armon/go-metrics/LICENSE b/vendor/github.com/armon/go-metrics/LICENSE
new file mode 100644
index 00000000000..106569e542b
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Armon Dadgar
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/armon/go-metrics/README.md b/vendor/github.com/armon/go-metrics/README.md
new file mode 100644
index 00000000000..aa73348c08d
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/README.md
@@ -0,0 +1,91 @@
+go-metrics
+==========
+
+This library provides a `metrics` package which can be used to instrument code,
+expose application metrics, and profile runtime performance in a flexible manner.
+
+Current API: [](https://godoc.org/github.com/armon/go-metrics)
+
+Sinks
+-----
+
+The `metrics` package makes use of a `MetricSink` interface to support delivery
+to any type of backend. Currently the following sinks are provided:
+
+* StatsiteSink : Sinks to a [statsite](https://github.com/armon/statsite/) instance (TCP)
+* StatsdSink: Sinks to a [StatsD](https://github.com/etsy/statsd/) / statsite instance (UDP)
+* PrometheusSink: Sinks to a [Prometheus](http://prometheus.io/) metrics endpoint (exposed via HTTP for scrapes)
+* InmemSink : Provides in-memory aggregation, can be used to export stats
+* FanoutSink : Sinks to multiple sinks. Enables writing to multiple statsite instances for example.
+* BlackholeSink : Sinks to nowhere
+
+In addition to the sinks, the `InmemSignal` can be used to catch a signal,
+and dump a formatted output of recent metrics. For example, when a process gets
+a SIGUSR1, it can dump to stderr recent performance metrics for debugging.
+
+Labels
+------
+
+Most metrics do have an equivalent ending with `WithLabels`, such methods
+allow to push metrics with labels and use some features of underlying Sinks
+(ex: translated into Prometheus labels).
+
+Since some of these labels may increase greatly cardinality of metrics, the
+library allow to filter labels using a blacklist/whitelist filtering system
+which is global to all metrics.
+
+* If `Config.AllowedLabels` is not nil, then only labels specified in this value will be sent to underlying Sink, otherwise, all labels are sent by default.
+* If `Config.BlockedLabels` is not nil, any label specified in this value will not be sent to underlying Sinks.
+
+By default, both `Config.AllowedLabels` and `Config.BlockedLabels` are nil, meaning that
+no tags are filetered at all, but it allow to a user to globally block some tags with high
+cardinality at application level.
+
+Examples
+--------
+
+Here is an example of using the package:
+
+```go
+func SlowMethod() {
+ // Profiling the runtime of a method
+ defer metrics.MeasureSince([]string{"SlowMethod"}, time.Now())
+}
+
+// Configure a statsite sink as the global metrics sink
+sink, _ := metrics.NewStatsiteSink("statsite:8125")
+metrics.NewGlobal(metrics.DefaultConfig("service-name"), sink)
+
+// Emit a Key/Value pair
+metrics.EmitKey([]string{"questions", "meaning of life"}, 42)
+```
+
+Here is an example of setting up a signal handler:
+
+```go
+// Setup the inmem sink and signal handler
+inm := metrics.NewInmemSink(10*time.Second, time.Minute)
+sig := metrics.DefaultInmemSignal(inm)
+metrics.NewGlobal(metrics.DefaultConfig("service-name"), inm)
+
+// Run some code
+inm.SetGauge([]string{"foo"}, 42)
+inm.EmitKey([]string{"bar"}, 30)
+
+inm.IncrCounter([]string{"baz"}, 42)
+inm.IncrCounter([]string{"baz"}, 1)
+inm.IncrCounter([]string{"baz"}, 80)
+
+inm.AddSample([]string{"method", "wow"}, 42)
+inm.AddSample([]string{"method", "wow"}, 100)
+inm.AddSample([]string{"method", "wow"}, 22)
+
+....
+```
+
+When a signal comes in, output like the following will be dumped to stderr:
+
+ [2014-01-28 14:57:33.04 -0800 PST][G] 'foo': 42.000
+ [2014-01-28 14:57:33.04 -0800 PST][P] 'bar': 30.000
+ [2014-01-28 14:57:33.04 -0800 PST][C] 'baz': Count: 3 Min: 1.000 Mean: 41.000 Max: 80.000 Stddev: 39.509
+ [2014-01-28 14:57:33.04 -0800 PST][S] 'method.wow': Count: 3 Min: 22.000 Mean: 54.667 Max: 100.000 Stddev: 40.513
\ No newline at end of file
diff --git a/vendor/github.com/armon/go-metrics/const_unix.go b/vendor/github.com/armon/go-metrics/const_unix.go
new file mode 100644
index 00000000000..31098dd57e5
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/const_unix.go
@@ -0,0 +1,12 @@
+// +build !windows
+
+package metrics
+
+import (
+ "syscall"
+)
+
+const (
+ // DefaultSignal is used with DefaultInmemSignal
+ DefaultSignal = syscall.SIGUSR1
+)
diff --git a/vendor/github.com/armon/go-metrics/const_windows.go b/vendor/github.com/armon/go-metrics/const_windows.go
new file mode 100644
index 00000000000..38136af3e42
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/const_windows.go
@@ -0,0 +1,13 @@
+// +build windows
+
+package metrics
+
+import (
+ "syscall"
+)
+
+const (
+ // DefaultSignal is used with DefaultInmemSignal
+ // Windows has no SIGUSR1, use SIGBREAK
+ DefaultSignal = syscall.Signal(21)
+)
diff --git a/vendor/github.com/armon/go-metrics/inmem.go b/vendor/github.com/armon/go-metrics/inmem.go
new file mode 100644
index 00000000000..7c427aca979
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/inmem.go
@@ -0,0 +1,339 @@
+package metrics
+
+import (
+ "bytes"
+ "fmt"
+ "math"
+ "net/url"
+ "strings"
+ "sync"
+ "time"
+)
+
+var spaceReplacer = strings.NewReplacer(" ", "_")
+
+// InmemSink provides a MetricSink that does in-memory aggregation
+// without sending metrics over a network. It can be embedded within
+// an application to provide profiling information.
+type InmemSink struct {
+ // How long is each aggregation interval
+ interval time.Duration
+
+ // Retain controls how many metrics interval we keep
+ retain time.Duration
+
+ // maxIntervals is the maximum length of intervals.
+ // It is retain / interval.
+ maxIntervals int
+
+ // intervals is a slice of the retained intervals
+ intervals []*IntervalMetrics
+ intervalLock sync.RWMutex
+
+ rateDenom float64
+}
+
+// IntervalMetrics stores the aggregated metrics
+// for a specific interval
+type IntervalMetrics struct {
+ sync.RWMutex
+
+ // The start time of the interval
+ Interval time.Time
+
+ // Gauges maps the key to the last set value
+ Gauges map[string]GaugeValue
+
+ // Points maps the string to the list of emitted values
+ // from EmitKey
+ Points map[string][]float32
+
+ // Counters maps the string key to a sum of the counter
+ // values
+ Counters map[string]SampledValue
+
+ // Samples maps the key to an AggregateSample,
+ // which has the rolled up view of a sample
+ Samples map[string]SampledValue
+
+ // done is closed when this interval has ended, and a new IntervalMetrics
+ // has been created to receive any future metrics.
+ done chan struct{}
+}
+
+// NewIntervalMetrics creates a new IntervalMetrics for a given interval
+func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
+ return &IntervalMetrics{
+ Interval: intv,
+ Gauges: make(map[string]GaugeValue),
+ Points: make(map[string][]float32),
+ Counters: make(map[string]SampledValue),
+ Samples: make(map[string]SampledValue),
+ done: make(chan struct{}),
+ }
+}
+
+// AggregateSample is used to hold aggregate metrics
+// about a sample
+type AggregateSample struct {
+ Count int // The count of emitted pairs
+ Rate float64 // The values rate per time unit (usually 1 second)
+ Sum float64 // The sum of values
+ SumSq float64 `json:"-"` // The sum of squared values
+ Min float64 // Minimum value
+ Max float64 // Maximum value
+ LastUpdated time.Time `json:"-"` // When value was last updated
+}
+
+// Computes a Stddev of the values
+func (a *AggregateSample) Stddev() float64 {
+ num := (float64(a.Count) * a.SumSq) - math.Pow(a.Sum, 2)
+ div := float64(a.Count * (a.Count - 1))
+ if div == 0 {
+ return 0
+ }
+ return math.Sqrt(num / div)
+}
+
+// Computes a mean of the values
+func (a *AggregateSample) Mean() float64 {
+ if a.Count == 0 {
+ return 0
+ }
+ return a.Sum / float64(a.Count)
+}
+
+// Ingest is used to update a sample
+func (a *AggregateSample) Ingest(v float64, rateDenom float64) {
+ a.Count++
+ a.Sum += v
+ a.SumSq += (v * v)
+ if v < a.Min || a.Count == 1 {
+ a.Min = v
+ }
+ if v > a.Max || a.Count == 1 {
+ a.Max = v
+ }
+ a.Rate = float64(a.Sum) / rateDenom
+ a.LastUpdated = time.Now()
+}
+
+func (a *AggregateSample) String() string {
+ if a.Count == 0 {
+ return "Count: 0"
+ } else if a.Stddev() == 0 {
+ return fmt.Sprintf("Count: %d Sum: %0.3f LastUpdated: %s", a.Count, a.Sum, a.LastUpdated)
+ } else {
+ return fmt.Sprintf("Count: %d Min: %0.3f Mean: %0.3f Max: %0.3f Stddev: %0.3f Sum: %0.3f LastUpdated: %s",
+ a.Count, a.Min, a.Mean(), a.Max, a.Stddev(), a.Sum, a.LastUpdated)
+ }
+}
+
+// NewInmemSinkFromURL creates an InmemSink from a URL. It is used
+// (and tested) from NewMetricSinkFromURL.
+func NewInmemSinkFromURL(u *url.URL) (MetricSink, error) {
+ params := u.Query()
+
+ interval, err := time.ParseDuration(params.Get("interval"))
+ if err != nil {
+ return nil, fmt.Errorf("Bad 'interval' param: %s", err)
+ }
+
+ retain, err := time.ParseDuration(params.Get("retain"))
+ if err != nil {
+ return nil, fmt.Errorf("Bad 'retain' param: %s", err)
+ }
+
+ return NewInmemSink(interval, retain), nil
+}
+
+// NewInmemSink is used to construct a new in-memory sink.
+// Uses an aggregation interval and maximum retention period.
+func NewInmemSink(interval, retain time.Duration) *InmemSink {
+ rateTimeUnit := time.Second
+ i := &InmemSink{
+ interval: interval,
+ retain: retain,
+ maxIntervals: int(retain / interval),
+ rateDenom: float64(interval.Nanoseconds()) / float64(rateTimeUnit.Nanoseconds()),
+ }
+ i.intervals = make([]*IntervalMetrics, 0, i.maxIntervals)
+ return i
+}
+
+func (i *InmemSink) SetGauge(key []string, val float32) {
+ i.SetGaugeWithLabels(key, val, nil)
+}
+
+func (i *InmemSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ k, name := i.flattenKeyLabels(key, labels)
+ intv := i.getInterval()
+
+ intv.Lock()
+ defer intv.Unlock()
+ intv.Gauges[k] = GaugeValue{Name: name, Value: val, Labels: labels}
+}
+
+func (i *InmemSink) EmitKey(key []string, val float32) {
+ k := i.flattenKey(key)
+ intv := i.getInterval()
+
+ intv.Lock()
+ defer intv.Unlock()
+ vals := intv.Points[k]
+ intv.Points[k] = append(vals, val)
+}
+
+func (i *InmemSink) IncrCounter(key []string, val float32) {
+ i.IncrCounterWithLabels(key, val, nil)
+}
+
+func (i *InmemSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ k, name := i.flattenKeyLabels(key, labels)
+ intv := i.getInterval()
+
+ intv.Lock()
+ defer intv.Unlock()
+
+ agg, ok := intv.Counters[k]
+ if !ok {
+ agg = SampledValue{
+ Name: name,
+ AggregateSample: &AggregateSample{},
+ Labels: labels,
+ }
+ intv.Counters[k] = agg
+ }
+ agg.Ingest(float64(val), i.rateDenom)
+}
+
+func (i *InmemSink) AddSample(key []string, val float32) {
+ i.AddSampleWithLabels(key, val, nil)
+}
+
+func (i *InmemSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
+ k, name := i.flattenKeyLabels(key, labels)
+ intv := i.getInterval()
+
+ intv.Lock()
+ defer intv.Unlock()
+
+ agg, ok := intv.Samples[k]
+ if !ok {
+ agg = SampledValue{
+ Name: name,
+ AggregateSample: &AggregateSample{},
+ Labels: labels,
+ }
+ intv.Samples[k] = agg
+ }
+ agg.Ingest(float64(val), i.rateDenom)
+}
+
+// Data is used to retrieve all the aggregated metrics
+// Intervals may be in use, and a read lock should be acquired
+func (i *InmemSink) Data() []*IntervalMetrics {
+ // Get the current interval, forces creation
+ i.getInterval()
+
+ i.intervalLock.RLock()
+ defer i.intervalLock.RUnlock()
+
+ n := len(i.intervals)
+ intervals := make([]*IntervalMetrics, n)
+
+ copy(intervals[:n-1], i.intervals[:n-1])
+ current := i.intervals[n-1]
+
+ // make its own copy for current interval
+ intervals[n-1] = &IntervalMetrics{}
+ copyCurrent := intervals[n-1]
+ current.RLock()
+ *copyCurrent = *current
+ // RWMutex is not safe to copy, so create a new instance on the copy
+ copyCurrent.RWMutex = sync.RWMutex{}
+
+ copyCurrent.Gauges = make(map[string]GaugeValue, len(current.Gauges))
+ for k, v := range current.Gauges {
+ copyCurrent.Gauges[k] = v
+ }
+ // saved values will be not change, just copy its link
+ copyCurrent.Points = make(map[string][]float32, len(current.Points))
+ for k, v := range current.Points {
+ copyCurrent.Points[k] = v
+ }
+ copyCurrent.Counters = make(map[string]SampledValue, len(current.Counters))
+ for k, v := range current.Counters {
+ copyCurrent.Counters[k] = v.deepCopy()
+ }
+ copyCurrent.Samples = make(map[string]SampledValue, len(current.Samples))
+ for k, v := range current.Samples {
+ copyCurrent.Samples[k] = v.deepCopy()
+ }
+ current.RUnlock()
+
+ return intervals
+}
+
+// getInterval returns the current interval. A new interval is created if no
+// previous interval exists, or if the current time is beyond the window for the
+// current interval.
+func (i *InmemSink) getInterval() *IntervalMetrics {
+ intv := time.Now().Truncate(i.interval)
+
+ // Attempt to return the existing interval first, because it only requires
+ // a read lock.
+ i.intervalLock.RLock()
+ n := len(i.intervals)
+ if n > 0 && i.intervals[n-1].Interval == intv {
+ defer i.intervalLock.RUnlock()
+ return i.intervals[n-1]
+ }
+ i.intervalLock.RUnlock()
+
+ i.intervalLock.Lock()
+ defer i.intervalLock.Unlock()
+
+ // Re-check for an existing interval now that the lock is re-acquired.
+ n = len(i.intervals)
+ if n > 0 && i.intervals[n-1].Interval == intv {
+ return i.intervals[n-1]
+ }
+
+ current := NewIntervalMetrics(intv)
+ i.intervals = append(i.intervals, current)
+ if n > 0 {
+ close(i.intervals[n-1].done)
+ }
+
+ n++
+ // Prune old intervals if the count exceeds the max.
+ if n >= i.maxIntervals {
+ copy(i.intervals[0:], i.intervals[n-i.maxIntervals:])
+ i.intervals = i.intervals[:i.maxIntervals]
+ }
+ return current
+}
+
+// Flattens the key for formatting, removes spaces
+func (i *InmemSink) flattenKey(parts []string) string {
+ buf := &bytes.Buffer{}
+
+ joined := strings.Join(parts, ".")
+
+ spaceReplacer.WriteString(buf, joined)
+
+ return buf.String()
+}
+
+// Flattens the key for formatting along with its labels, removes spaces
+func (i *InmemSink) flattenKeyLabels(parts []string, labels []Label) (string, string) {
+ key := i.flattenKey(parts)
+ buf := bytes.NewBufferString(key)
+
+ for _, label := range labels {
+ spaceReplacer.WriteString(buf, fmt.Sprintf(";%s=%s", label.Name, label.Value))
+ }
+
+ return buf.String(), key
+}
diff --git a/vendor/github.com/armon/go-metrics/inmem_endpoint.go b/vendor/github.com/armon/go-metrics/inmem_endpoint.go
new file mode 100644
index 00000000000..24eefa96389
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/inmem_endpoint.go
@@ -0,0 +1,162 @@
+package metrics
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "sort"
+ "time"
+)
+
+// MetricsSummary holds a roll-up of metrics info for a given interval
+type MetricsSummary struct {
+ Timestamp string
+ Gauges []GaugeValue
+ Points []PointValue
+ Counters []SampledValue
+ Samples []SampledValue
+}
+
+type GaugeValue struct {
+ Name string
+ Hash string `json:"-"`
+ Value float32
+
+ Labels []Label `json:"-"`
+ DisplayLabels map[string]string `json:"Labels"`
+}
+
+type PointValue struct {
+ Name string
+ Points []float32
+}
+
+type SampledValue struct {
+ Name string
+ Hash string `json:"-"`
+ *AggregateSample
+ Mean float64
+ Stddev float64
+
+ Labels []Label `json:"-"`
+ DisplayLabels map[string]string `json:"Labels"`
+}
+
+// deepCopy allocates a new instance of AggregateSample
+func (source *SampledValue) deepCopy() SampledValue {
+ dest := *source
+ if source.AggregateSample != nil {
+ dest.AggregateSample = &AggregateSample{}
+ *dest.AggregateSample = *source.AggregateSample
+ }
+ return dest
+}
+
+// DisplayMetrics returns a summary of the metrics from the most recent finished interval.
+func (i *InmemSink) DisplayMetrics(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
+ data := i.Data()
+
+ var interval *IntervalMetrics
+ n := len(data)
+ switch {
+ case n == 0:
+ return nil, fmt.Errorf("no metric intervals have been initialized yet")
+ case n == 1:
+ // Show the current interval if it's all we have
+ interval = data[0]
+ default:
+ // Show the most recent finished interval if we have one
+ interval = data[n-2]
+ }
+
+ return newMetricSummaryFromInterval(interval), nil
+}
+
+func newMetricSummaryFromInterval(interval *IntervalMetrics) MetricsSummary {
+ interval.RLock()
+ defer interval.RUnlock()
+
+ summary := MetricsSummary{
+ Timestamp: interval.Interval.Round(time.Second).UTC().String(),
+ Gauges: make([]GaugeValue, 0, len(interval.Gauges)),
+ Points: make([]PointValue, 0, len(interval.Points)),
+ }
+
+ // Format and sort the output of each metric type, so it gets displayed in a
+ // deterministic order.
+ for name, points := range interval.Points {
+ summary.Points = append(summary.Points, PointValue{name, points})
+ }
+ sort.Slice(summary.Points, func(i, j int) bool {
+ return summary.Points[i].Name < summary.Points[j].Name
+ })
+
+ for hash, value := range interval.Gauges {
+ value.Hash = hash
+ value.DisplayLabels = make(map[string]string)
+ for _, label := range value.Labels {
+ value.DisplayLabels[label.Name] = label.Value
+ }
+ value.Labels = nil
+
+ summary.Gauges = append(summary.Gauges, value)
+ }
+ sort.Slice(summary.Gauges, func(i, j int) bool {
+ return summary.Gauges[i].Hash < summary.Gauges[j].Hash
+ })
+
+ summary.Counters = formatSamples(interval.Counters)
+ summary.Samples = formatSamples(interval.Samples)
+
+ return summary
+}
+
+func formatSamples(source map[string]SampledValue) []SampledValue {
+ output := make([]SampledValue, 0, len(source))
+ for hash, sample := range source {
+ displayLabels := make(map[string]string)
+ for _, label := range sample.Labels {
+ displayLabels[label.Name] = label.Value
+ }
+
+ output = append(output, SampledValue{
+ Name: sample.Name,
+ Hash: hash,
+ AggregateSample: sample.AggregateSample,
+ Mean: sample.AggregateSample.Mean(),
+ Stddev: sample.AggregateSample.Stddev(),
+ DisplayLabels: displayLabels,
+ })
+ }
+ sort.Slice(output, func(i, j int) bool {
+ return output[i].Hash < output[j].Hash
+ })
+
+ return output
+}
+
+type Encoder interface {
+ Encode(interface{}) error
+}
+
+// Stream writes metrics using encoder.Encode each time an interval ends. Runs
+// until the request context is cancelled, or the encoder returns an error.
+// The caller is responsible for logging any errors from encoder.
+func (i *InmemSink) Stream(ctx context.Context, encoder Encoder) {
+ interval := i.getInterval()
+
+ for {
+ select {
+ case <-interval.done:
+ summary := newMetricSummaryFromInterval(interval)
+ if err := encoder.Encode(summary); err != nil {
+ return
+ }
+
+ // update interval to the next one
+ interval = i.getInterval()
+ case <-ctx.Done():
+ return
+ }
+ }
+}
diff --git a/vendor/github.com/armon/go-metrics/inmem_signal.go b/vendor/github.com/armon/go-metrics/inmem_signal.go
new file mode 100644
index 00000000000..0937f4aedf7
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/inmem_signal.go
@@ -0,0 +1,117 @@
+package metrics
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "os/signal"
+ "strings"
+ "sync"
+ "syscall"
+)
+
+// InmemSignal is used to listen for a given signal, and when received,
+// to dump the current metrics from the InmemSink to an io.Writer
+type InmemSignal struct {
+ signal syscall.Signal
+ inm *InmemSink
+ w io.Writer
+ sigCh chan os.Signal
+
+ stop bool
+ stopCh chan struct{}
+ stopLock sync.Mutex
+}
+
+// NewInmemSignal creates a new InmemSignal which listens for a given signal,
+// and dumps the current metrics out to a writer
+func NewInmemSignal(inmem *InmemSink, sig syscall.Signal, w io.Writer) *InmemSignal {
+ i := &InmemSignal{
+ signal: sig,
+ inm: inmem,
+ w: w,
+ sigCh: make(chan os.Signal, 1),
+ stopCh: make(chan struct{}),
+ }
+ signal.Notify(i.sigCh, sig)
+ go i.run()
+ return i
+}
+
+// DefaultInmemSignal returns a new InmemSignal that responds to SIGUSR1
+// and writes output to stderr. Windows uses SIGBREAK
+func DefaultInmemSignal(inmem *InmemSink) *InmemSignal {
+ return NewInmemSignal(inmem, DefaultSignal, os.Stderr)
+}
+
+// Stop is used to stop the InmemSignal from listening
+func (i *InmemSignal) Stop() {
+ i.stopLock.Lock()
+ defer i.stopLock.Unlock()
+
+ if i.stop {
+ return
+ }
+ i.stop = true
+ close(i.stopCh)
+ signal.Stop(i.sigCh)
+}
+
+// run is a long running routine that handles signals
+func (i *InmemSignal) run() {
+ for {
+ select {
+ case <-i.sigCh:
+ i.dumpStats()
+ case <-i.stopCh:
+ return
+ }
+ }
+}
+
+// dumpStats is used to dump the data to output writer
+func (i *InmemSignal) dumpStats() {
+ buf := bytes.NewBuffer(nil)
+
+ data := i.inm.Data()
+ // Skip the last period which is still being aggregated
+ for j := 0; j < len(data)-1; j++ {
+ intv := data[j]
+ intv.RLock()
+ for _, val := range intv.Gauges {
+ name := i.flattenLabels(val.Name, val.Labels)
+ fmt.Fprintf(buf, "[%v][G] '%s': %0.3f\n", intv.Interval, name, val.Value)
+ }
+ for name, vals := range intv.Points {
+ for _, val := range vals {
+ fmt.Fprintf(buf, "[%v][P] '%s': %0.3f\n", intv.Interval, name, val)
+ }
+ }
+ for _, agg := range intv.Counters {
+ name := i.flattenLabels(agg.Name, agg.Labels)
+ fmt.Fprintf(buf, "[%v][C] '%s': %s\n", intv.Interval, name, agg.AggregateSample)
+ }
+ for _, agg := range intv.Samples {
+ name := i.flattenLabels(agg.Name, agg.Labels)
+ fmt.Fprintf(buf, "[%v][S] '%s': %s\n", intv.Interval, name, agg.AggregateSample)
+ }
+ intv.RUnlock()
+ }
+
+ // Write out the bytes
+ i.w.Write(buf.Bytes())
+}
+
+// Flattens the key for formatting along with its labels, removes spaces
+func (i *InmemSignal) flattenLabels(name string, labels []Label) string {
+ buf := bytes.NewBufferString(name)
+ replacer := strings.NewReplacer(" ", "_", ":", "_")
+
+ for _, label := range labels {
+ replacer.WriteString(buf, ".")
+ replacer.WriteString(buf, label.Value)
+ }
+
+ return buf.String()
+}
diff --git a/vendor/github.com/armon/go-metrics/metrics.go b/vendor/github.com/armon/go-metrics/metrics.go
new file mode 100644
index 00000000000..36642a42937
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/metrics.go
@@ -0,0 +1,299 @@
+package metrics
+
+import (
+ "runtime"
+ "strings"
+ "time"
+
+ iradix "github.com/hashicorp/go-immutable-radix"
+)
+
+type Label struct {
+ Name string
+ Value string
+}
+
+func (m *Metrics) SetGauge(key []string, val float32) {
+ m.SetGaugeWithLabels(key, val, nil)
+}
+
+func (m *Metrics) SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ if m.HostName != "" {
+ if m.EnableHostnameLabel {
+ labels = append(labels, Label{"host", m.HostName})
+ } else if m.EnableHostname {
+ key = insert(0, m.HostName, key)
+ }
+ }
+ if m.EnableTypePrefix {
+ key = insert(0, "gauge", key)
+ }
+ if m.ServiceName != "" {
+ if m.EnableServiceLabel {
+ labels = append(labels, Label{"service", m.ServiceName})
+ } else {
+ key = insert(0, m.ServiceName, key)
+ }
+ }
+ allowed, labelsFiltered := m.allowMetric(key, labels)
+ if !allowed {
+ return
+ }
+ m.sink.SetGaugeWithLabels(key, val, labelsFiltered)
+}
+
+func (m *Metrics) EmitKey(key []string, val float32) {
+ if m.EnableTypePrefix {
+ key = insert(0, "kv", key)
+ }
+ if m.ServiceName != "" {
+ key = insert(0, m.ServiceName, key)
+ }
+ allowed, _ := m.allowMetric(key, nil)
+ if !allowed {
+ return
+ }
+ m.sink.EmitKey(key, val)
+}
+
+func (m *Metrics) IncrCounter(key []string, val float32) {
+ m.IncrCounterWithLabels(key, val, nil)
+}
+
+func (m *Metrics) IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ if m.HostName != "" && m.EnableHostnameLabel {
+ labels = append(labels, Label{"host", m.HostName})
+ }
+ if m.EnableTypePrefix {
+ key = insert(0, "counter", key)
+ }
+ if m.ServiceName != "" {
+ if m.EnableServiceLabel {
+ labels = append(labels, Label{"service", m.ServiceName})
+ } else {
+ key = insert(0, m.ServiceName, key)
+ }
+ }
+ allowed, labelsFiltered := m.allowMetric(key, labels)
+ if !allowed {
+ return
+ }
+ m.sink.IncrCounterWithLabels(key, val, labelsFiltered)
+}
+
+func (m *Metrics) AddSample(key []string, val float32) {
+ m.AddSampleWithLabels(key, val, nil)
+}
+
+func (m *Metrics) AddSampleWithLabels(key []string, val float32, labels []Label) {
+ if m.HostName != "" && m.EnableHostnameLabel {
+ labels = append(labels, Label{"host", m.HostName})
+ }
+ if m.EnableTypePrefix {
+ key = insert(0, "sample", key)
+ }
+ if m.ServiceName != "" {
+ if m.EnableServiceLabel {
+ labels = append(labels, Label{"service", m.ServiceName})
+ } else {
+ key = insert(0, m.ServiceName, key)
+ }
+ }
+ allowed, labelsFiltered := m.allowMetric(key, labels)
+ if !allowed {
+ return
+ }
+ m.sink.AddSampleWithLabels(key, val, labelsFiltered)
+}
+
+func (m *Metrics) MeasureSince(key []string, start time.Time) {
+ m.MeasureSinceWithLabels(key, start, nil)
+}
+
+func (m *Metrics) MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
+ if m.HostName != "" && m.EnableHostnameLabel {
+ labels = append(labels, Label{"host", m.HostName})
+ }
+ if m.EnableTypePrefix {
+ key = insert(0, "timer", key)
+ }
+ if m.ServiceName != "" {
+ if m.EnableServiceLabel {
+ labels = append(labels, Label{"service", m.ServiceName})
+ } else {
+ key = insert(0, m.ServiceName, key)
+ }
+ }
+ allowed, labelsFiltered := m.allowMetric(key, labels)
+ if !allowed {
+ return
+ }
+ now := time.Now()
+ elapsed := now.Sub(start)
+ msec := float32(elapsed.Nanoseconds()) / float32(m.TimerGranularity)
+ m.sink.AddSampleWithLabels(key, msec, labelsFiltered)
+}
+
+// UpdateFilter overwrites the existing filter with the given rules.
+func (m *Metrics) UpdateFilter(allow, block []string) {
+ m.UpdateFilterAndLabels(allow, block, m.AllowedLabels, m.BlockedLabels)
+}
+
+// UpdateFilterAndLabels overwrites the existing filter with the given rules.
+func (m *Metrics) UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
+ m.filterLock.Lock()
+ defer m.filterLock.Unlock()
+
+ m.AllowedPrefixes = allow
+ m.BlockedPrefixes = block
+
+ if allowedLabels == nil {
+ // Having a white list means we take only elements from it
+ m.allowedLabels = nil
+ } else {
+ m.allowedLabels = make(map[string]bool)
+ for _, v := range allowedLabels {
+ m.allowedLabels[v] = true
+ }
+ }
+ m.blockedLabels = make(map[string]bool)
+ for _, v := range blockedLabels {
+ m.blockedLabels[v] = true
+ }
+ m.AllowedLabels = allowedLabels
+ m.BlockedLabels = blockedLabels
+
+ m.filter = iradix.New()
+ for _, prefix := range m.AllowedPrefixes {
+ m.filter, _, _ = m.filter.Insert([]byte(prefix), true)
+ }
+ for _, prefix := range m.BlockedPrefixes {
+ m.filter, _, _ = m.filter.Insert([]byte(prefix), false)
+ }
+}
+
+func (m *Metrics) Shutdown() {
+ if ss, ok := m.sink.(ShutdownSink); ok {
+ ss.Shutdown()
+ }
+}
+
+// labelIsAllowed return true if a should be included in metric
+// the caller should lock m.filterLock while calling this method
+func (m *Metrics) labelIsAllowed(label *Label) bool {
+ labelName := (*label).Name
+ if m.blockedLabels != nil {
+ _, ok := m.blockedLabels[labelName]
+ if ok {
+ // If present, let's remove this label
+ return false
+ }
+ }
+ if m.allowedLabels != nil {
+ _, ok := m.allowedLabels[labelName]
+ return ok
+ }
+ // Allow by default
+ return true
+}
+
+// filterLabels return only allowed labels
+// the caller should lock m.filterLock while calling this method
+func (m *Metrics) filterLabels(labels []Label) []Label {
+ if labels == nil {
+ return nil
+ }
+ toReturn := []Label{}
+ for _, label := range labels {
+ if m.labelIsAllowed(&label) {
+ toReturn = append(toReturn, label)
+ }
+ }
+ return toReturn
+}
+
+// Returns whether the metric should be allowed based on configured prefix filters
+// Also return the applicable labels
+func (m *Metrics) allowMetric(key []string, labels []Label) (bool, []Label) {
+ m.filterLock.RLock()
+ defer m.filterLock.RUnlock()
+
+ if m.filter == nil || m.filter.Len() == 0 {
+ return m.Config.FilterDefault, m.filterLabels(labels)
+ }
+
+ _, allowed, ok := m.filter.Root().LongestPrefix([]byte(strings.Join(key, ".")))
+ if !ok {
+ return m.Config.FilterDefault, m.filterLabels(labels)
+ }
+
+ return allowed.(bool), m.filterLabels(labels)
+}
+
+// Periodically collects runtime stats to publish
+func (m *Metrics) collectStats() {
+ for {
+ time.Sleep(m.ProfileInterval)
+ m.EmitRuntimeStats()
+ }
+}
+
+// Emits various runtime statsitics
+func (m *Metrics) EmitRuntimeStats() {
+ // Export number of Goroutines
+ numRoutines := runtime.NumGoroutine()
+ m.SetGauge([]string{"runtime", "num_goroutines"}, float32(numRoutines))
+
+ // Export memory stats
+ var stats runtime.MemStats
+ runtime.ReadMemStats(&stats)
+ m.SetGauge([]string{"runtime", "alloc_bytes"}, float32(stats.Alloc))
+ m.SetGauge([]string{"runtime", "sys_bytes"}, float32(stats.Sys))
+ m.SetGauge([]string{"runtime", "malloc_count"}, float32(stats.Mallocs))
+ m.SetGauge([]string{"runtime", "free_count"}, float32(stats.Frees))
+ m.SetGauge([]string{"runtime", "heap_objects"}, float32(stats.HeapObjects))
+ m.SetGauge([]string{"runtime", "total_gc_pause_ns"}, float32(stats.PauseTotalNs))
+ m.SetGauge([]string{"runtime", "total_gc_runs"}, float32(stats.NumGC))
+
+ // Export info about the last few GC runs
+ num := stats.NumGC
+
+ // Handle wrap around
+ if num < m.lastNumGC {
+ m.lastNumGC = 0
+ }
+
+ // Ensure we don't scan more than 256
+ if num-m.lastNumGC >= 256 {
+ m.lastNumGC = num - 255
+ }
+
+ for i := m.lastNumGC; i < num; i++ {
+ pause := stats.PauseNs[i%256]
+ m.AddSample([]string{"runtime", "gc_pause_ns"}, float32(pause))
+ }
+ m.lastNumGC = num
+}
+
+// Creates a new slice with the provided string value as the first element
+// and the provided slice values as the remaining values.
+// Ordering of the values in the provided input slice is kept in tact in the output slice.
+func insert(i int, v string, s []string) []string {
+ // Allocate new slice to avoid modifying the input slice
+ newS := make([]string, len(s)+1)
+
+ // Copy s[0, i-1] into newS
+ for j := 0; j < i; j++ {
+ newS[j] = s[j]
+ }
+
+ // Insert provided element at index i
+ newS[i] = v
+
+ // Copy s[i, len(s)-1] into newS starting at newS[i+1]
+ for j := i; j < len(s); j++ {
+ newS[j+1] = s[j]
+ }
+
+ return newS
+}
diff --git a/vendor/github.com/armon/go-metrics/sink.go b/vendor/github.com/armon/go-metrics/sink.go
new file mode 100644
index 00000000000..6f4108ff405
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/sink.go
@@ -0,0 +1,132 @@
+package metrics
+
+import (
+ "fmt"
+ "net/url"
+)
+
+// The MetricSink interface is used to transmit metrics information
+// to an external system
+type MetricSink interface {
+ // A Gauge should retain the last value it is set to
+ SetGauge(key []string, val float32)
+ SetGaugeWithLabels(key []string, val float32, labels []Label)
+
+ // Should emit a Key/Value pair for each call
+ EmitKey(key []string, val float32)
+
+ // Counters should accumulate values
+ IncrCounter(key []string, val float32)
+ IncrCounterWithLabels(key []string, val float32, labels []Label)
+
+ // Samples are for timing information, where quantiles are used
+ AddSample(key []string, val float32)
+ AddSampleWithLabels(key []string, val float32, labels []Label)
+}
+
+type ShutdownSink interface {
+ MetricSink
+
+ // Shutdown the metric sink, flush metrics to storage, and cleanup resources.
+ // Called immediately prior to application exit. Implementations must block
+ // until metrics are flushed to storage.
+ Shutdown()
+}
+
+// BlackholeSink is used to just blackhole messages
+type BlackholeSink struct{}
+
+func (*BlackholeSink) SetGauge(key []string, val float32) {}
+func (*BlackholeSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {}
+func (*BlackholeSink) EmitKey(key []string, val float32) {}
+func (*BlackholeSink) IncrCounter(key []string, val float32) {}
+func (*BlackholeSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {}
+func (*BlackholeSink) AddSample(key []string, val float32) {}
+func (*BlackholeSink) AddSampleWithLabels(key []string, val float32, labels []Label) {}
+
+// FanoutSink is used to sink to fanout values to multiple sinks
+type FanoutSink []MetricSink
+
+func (fh FanoutSink) SetGauge(key []string, val float32) {
+ fh.SetGaugeWithLabels(key, val, nil)
+}
+
+func (fh FanoutSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ for _, s := range fh {
+ s.SetGaugeWithLabels(key, val, labels)
+ }
+}
+
+func (fh FanoutSink) EmitKey(key []string, val float32) {
+ for _, s := range fh {
+ s.EmitKey(key, val)
+ }
+}
+
+func (fh FanoutSink) IncrCounter(key []string, val float32) {
+ fh.IncrCounterWithLabels(key, val, nil)
+}
+
+func (fh FanoutSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ for _, s := range fh {
+ s.IncrCounterWithLabels(key, val, labels)
+ }
+}
+
+func (fh FanoutSink) AddSample(key []string, val float32) {
+ fh.AddSampleWithLabels(key, val, nil)
+}
+
+func (fh FanoutSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
+ for _, s := range fh {
+ s.AddSampleWithLabels(key, val, labels)
+ }
+}
+
+func (fh FanoutSink) Shutdown() {
+ for _, s := range fh {
+ if ss, ok := s.(ShutdownSink); ok {
+ ss.Shutdown()
+ }
+ }
+}
+
+// sinkURLFactoryFunc is an generic interface around the *SinkFromURL() function provided
+// by each sink type
+type sinkURLFactoryFunc func(*url.URL) (MetricSink, error)
+
+// sinkRegistry supports the generic NewMetricSink function by mapping URL
+// schemes to metric sink factory functions
+var sinkRegistry = map[string]sinkURLFactoryFunc{
+ "statsd": NewStatsdSinkFromURL,
+ "statsite": NewStatsiteSinkFromURL,
+ "inmem": NewInmemSinkFromURL,
+}
+
+// NewMetricSinkFromURL allows a generic URL input to configure any of the
+// supported sinks. The scheme of the URL identifies the type of the sink, the
+// and query parameters are used to set options.
+//
+// "statsd://" - Initializes a StatsdSink. The host and port are passed through
+// as the "addr" of the sink
+//
+// "statsite://" - Initializes a StatsiteSink. The host and port become the
+// "addr" of the sink
+//
+// "inmem://" - Initializes an InmemSink. The host and port are ignored. The
+// "interval" and "duration" query parameters must be specified with valid
+// durations, see NewInmemSink for details.
+func NewMetricSinkFromURL(urlStr string) (MetricSink, error) {
+ u, err := url.Parse(urlStr)
+ if err != nil {
+ return nil, err
+ }
+
+ sinkURLFactoryFunc := sinkRegistry[u.Scheme]
+ if sinkURLFactoryFunc == nil {
+ return nil, fmt.Errorf(
+ "cannot create metric sink, unrecognized sink name: %q", u.Scheme)
+ }
+
+ return sinkURLFactoryFunc(u)
+}
diff --git a/vendor/github.com/armon/go-metrics/start.go b/vendor/github.com/armon/go-metrics/start.go
new file mode 100644
index 00000000000..38976f8dc93
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/start.go
@@ -0,0 +1,158 @@
+package metrics
+
+import (
+ "os"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ iradix "github.com/hashicorp/go-immutable-radix"
+)
+
+// Config is used to configure metrics settings
+type Config struct {
+ ServiceName string // Prefixed with keys to separate services
+ HostName string // Hostname to use. If not provided and EnableHostname, it will be os.Hostname
+ EnableHostname bool // Enable prefixing gauge values with hostname
+ EnableHostnameLabel bool // Enable adding hostname to labels
+ EnableServiceLabel bool // Enable adding service to labels
+ EnableRuntimeMetrics bool // Enables profiling of runtime metrics (GC, Goroutines, Memory)
+ EnableTypePrefix bool // Prefixes key with a type ("counter", "gauge", "timer")
+ TimerGranularity time.Duration // Granularity of timers.
+ ProfileInterval time.Duration // Interval to profile runtime metrics
+
+ AllowedPrefixes []string // A list of metric prefixes to allow, with '.' as the separator
+ BlockedPrefixes []string // A list of metric prefixes to block, with '.' as the separator
+ AllowedLabels []string // A list of metric labels to allow, with '.' as the separator
+ BlockedLabels []string // A list of metric labels to block, with '.' as the separator
+ FilterDefault bool // Whether to allow metrics by default
+}
+
+// Metrics represents an instance of a metrics sink that can
+// be used to emit
+type Metrics struct {
+ Config
+ lastNumGC uint32
+ sink MetricSink
+ filter *iradix.Tree
+ allowedLabels map[string]bool
+ blockedLabels map[string]bool
+ filterLock sync.RWMutex // Lock filters and allowedLabels/blockedLabels access
+}
+
+// Shared global metrics instance
+var globalMetrics atomic.Value // *Metrics
+
+func init() {
+ // Initialize to a blackhole sink to avoid errors
+ globalMetrics.Store(&Metrics{sink: &BlackholeSink{}})
+}
+
+// Default returns the shared global metrics instance.
+func Default() *Metrics {
+ return globalMetrics.Load().(*Metrics)
+}
+
+// DefaultConfig provides a sane default configuration
+func DefaultConfig(serviceName string) *Config {
+ c := &Config{
+ ServiceName: serviceName, // Use client provided service
+ HostName: "",
+ EnableHostname: true, // Enable hostname prefix
+ EnableRuntimeMetrics: true, // Enable runtime profiling
+ EnableTypePrefix: false, // Disable type prefix
+ TimerGranularity: time.Millisecond, // Timers are in milliseconds
+ ProfileInterval: time.Second, // Poll runtime every second
+ FilterDefault: true, // Don't filter metrics by default
+ }
+
+ // Try to get the hostname
+ name, _ := os.Hostname()
+ c.HostName = name
+ return c
+}
+
+// New is used to create a new instance of Metrics
+func New(conf *Config, sink MetricSink) (*Metrics, error) {
+ met := &Metrics{}
+ met.Config = *conf
+ met.sink = sink
+ met.UpdateFilterAndLabels(conf.AllowedPrefixes, conf.BlockedPrefixes, conf.AllowedLabels, conf.BlockedLabels)
+
+ // Start the runtime collector
+ if conf.EnableRuntimeMetrics {
+ go met.collectStats()
+ }
+ return met, nil
+}
+
+// NewGlobal is the same as New, but it assigns the metrics object to be
+// used globally as well as returning it.
+func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
+ metrics, err := New(conf, sink)
+ if err == nil {
+ globalMetrics.Store(metrics)
+ }
+ return metrics, err
+}
+
+// Proxy all the methods to the globalMetrics instance
+func SetGauge(key []string, val float32) {
+ globalMetrics.Load().(*Metrics).SetGauge(key, val)
+}
+
+func SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ globalMetrics.Load().(*Metrics).SetGaugeWithLabels(key, val, labels)
+}
+
+func EmitKey(key []string, val float32) {
+ globalMetrics.Load().(*Metrics).EmitKey(key, val)
+}
+
+func IncrCounter(key []string, val float32) {
+ globalMetrics.Load().(*Metrics).IncrCounter(key, val)
+}
+
+func IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ globalMetrics.Load().(*Metrics).IncrCounterWithLabels(key, val, labels)
+}
+
+func AddSample(key []string, val float32) {
+ globalMetrics.Load().(*Metrics).AddSample(key, val)
+}
+
+func AddSampleWithLabels(key []string, val float32, labels []Label) {
+ globalMetrics.Load().(*Metrics).AddSampleWithLabels(key, val, labels)
+}
+
+func MeasureSince(key []string, start time.Time) {
+ globalMetrics.Load().(*Metrics).MeasureSince(key, start)
+}
+
+func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
+ globalMetrics.Load().(*Metrics).MeasureSinceWithLabels(key, start, labels)
+}
+
+func UpdateFilter(allow, block []string) {
+ globalMetrics.Load().(*Metrics).UpdateFilter(allow, block)
+}
+
+// UpdateFilterAndLabels set allow/block prefixes of metrics while allowedLabels
+// and blockedLabels - when not nil - allow filtering of labels in order to
+// block/allow globally labels (especially useful when having large number of
+// values for a given label). See README.md for more information about usage.
+func UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
+ globalMetrics.Load().(*Metrics).UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels)
+}
+
+// Shutdown disables metric collection, then blocks while attempting to flush metrics to storage.
+// WARNING: Not all MetricSink backends support this functionality, and calling this will cause them to leak resources.
+// This is intended for use immediately prior to application exit.
+func Shutdown() {
+ m := globalMetrics.Load().(*Metrics)
+ // Swap whatever MetricSink is currently active with a BlackholeSink. Callers must not have a
+ // reason to expect that calls to the library will successfully collect metrics after Shutdown
+ // has been called.
+ globalMetrics.Store(&Metrics{sink: &BlackholeSink{}})
+ m.Shutdown()
+}
diff --git a/vendor/github.com/armon/go-metrics/statsd.go b/vendor/github.com/armon/go-metrics/statsd.go
new file mode 100644
index 00000000000..1bfffce46e2
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/statsd.go
@@ -0,0 +1,184 @@
+package metrics
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "net"
+ "net/url"
+ "strings"
+ "time"
+)
+
+const (
+ // statsdMaxLen is the maximum size of a packet
+ // to send to statsd
+ statsdMaxLen = 1400
+)
+
+// StatsdSink provides a MetricSink that can be used
+// with a statsite or statsd metrics server. It uses
+// only UDP packets, while StatsiteSink uses TCP.
+type StatsdSink struct {
+ addr string
+ metricQueue chan string
+}
+
+// NewStatsdSinkFromURL creates an StatsdSink from a URL. It is used
+// (and tested) from NewMetricSinkFromURL.
+func NewStatsdSinkFromURL(u *url.URL) (MetricSink, error) {
+ return NewStatsdSink(u.Host)
+}
+
+// NewStatsdSink is used to create a new StatsdSink
+func NewStatsdSink(addr string) (*StatsdSink, error) {
+ s := &StatsdSink{
+ addr: addr,
+ metricQueue: make(chan string, 4096),
+ }
+ go s.flushMetrics()
+ return s, nil
+}
+
+// Close is used to stop flushing to statsd
+func (s *StatsdSink) Shutdown() {
+ close(s.metricQueue)
+}
+
+func (s *StatsdSink) SetGauge(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsdSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsdSink) EmitKey(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|kv\n", flatKey, val))
+}
+
+func (s *StatsdSink) IncrCounter(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
+}
+
+func (s *StatsdSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
+}
+
+func (s *StatsdSink) AddSample(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
+}
+
+func (s *StatsdSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
+}
+
+// Flattens the key for formatting, removes spaces
+func (s *StatsdSink) flattenKey(parts []string) string {
+ joined := strings.Join(parts, ".")
+ return strings.Map(func(r rune) rune {
+ switch r {
+ case ':':
+ fallthrough
+ case ' ':
+ return '_'
+ default:
+ return r
+ }
+ }, joined)
+}
+
+// Flattens the key along with labels for formatting, removes spaces
+func (s *StatsdSink) flattenKeyLabels(parts []string, labels []Label) string {
+ for _, label := range labels {
+ parts = append(parts, label.Value)
+ }
+ return s.flattenKey(parts)
+}
+
+// Does a non-blocking push to the metrics queue
+func (s *StatsdSink) pushMetric(m string) {
+ select {
+ case s.metricQueue <- m:
+ default:
+ }
+}
+
+// Flushes metrics
+func (s *StatsdSink) flushMetrics() {
+ var sock net.Conn
+ var err error
+ var wait <-chan time.Time
+ ticker := time.NewTicker(flushInterval)
+ defer ticker.Stop()
+
+CONNECT:
+ // Create a buffer
+ buf := bytes.NewBuffer(nil)
+
+ // Attempt to connect
+ sock, err = net.Dial("udp", s.addr)
+ if err != nil {
+ log.Printf("[ERR] Error connecting to statsd! Err: %s", err)
+ goto WAIT
+ }
+
+ for {
+ select {
+ case metric, ok := <-s.metricQueue:
+ // Get a metric from the queue
+ if !ok {
+ goto QUIT
+ }
+
+ // Check if this would overflow the packet size
+ if len(metric)+buf.Len() > statsdMaxLen {
+ _, err := sock.Write(buf.Bytes())
+ buf.Reset()
+ if err != nil {
+ log.Printf("[ERR] Error writing to statsd! Err: %s", err)
+ goto WAIT
+ }
+ }
+
+ // Append to the buffer
+ buf.WriteString(metric)
+
+ case <-ticker.C:
+ if buf.Len() == 0 {
+ continue
+ }
+
+ _, err := sock.Write(buf.Bytes())
+ buf.Reset()
+ if err != nil {
+ log.Printf("[ERR] Error flushing to statsd! Err: %s", err)
+ goto WAIT
+ }
+ }
+ }
+
+WAIT:
+ // Wait for a while
+ wait = time.After(time.Duration(5) * time.Second)
+ for {
+ select {
+ // Dequeue the messages to avoid backlog
+ case _, ok := <-s.metricQueue:
+ if !ok {
+ goto QUIT
+ }
+ case <-wait:
+ goto CONNECT
+ }
+ }
+QUIT:
+ s.metricQueue = nil
+}
diff --git a/vendor/github.com/armon/go-metrics/statsite.go b/vendor/github.com/armon/go-metrics/statsite.go
new file mode 100644
index 00000000000..6c0d284d2dd
--- /dev/null
+++ b/vendor/github.com/armon/go-metrics/statsite.go
@@ -0,0 +1,172 @@
+package metrics
+
+import (
+ "bufio"
+ "fmt"
+ "log"
+ "net"
+ "net/url"
+ "strings"
+ "time"
+)
+
+const (
+ // We force flush the statsite metrics after this period of
+ // inactivity. Prevents stats from getting stuck in a buffer
+ // forever.
+ flushInterval = 100 * time.Millisecond
+)
+
+// NewStatsiteSinkFromURL creates an StatsiteSink from a URL. It is used
+// (and tested) from NewMetricSinkFromURL.
+func NewStatsiteSinkFromURL(u *url.URL) (MetricSink, error) {
+ return NewStatsiteSink(u.Host)
+}
+
+// StatsiteSink provides a MetricSink that can be used with a
+// statsite metrics server
+type StatsiteSink struct {
+ addr string
+ metricQueue chan string
+}
+
+// NewStatsiteSink is used to create a new StatsiteSink
+func NewStatsiteSink(addr string) (*StatsiteSink, error) {
+ s := &StatsiteSink{
+ addr: addr,
+ metricQueue: make(chan string, 4096),
+ }
+ go s.flushMetrics()
+ return s, nil
+}
+
+// Close is used to stop flushing to statsite
+func (s *StatsiteSink) Shutdown() {
+ close(s.metricQueue)
+}
+
+func (s *StatsiteSink) SetGauge(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsiteSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsiteSink) EmitKey(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|kv\n", flatKey, val))
+}
+
+func (s *StatsiteSink) IncrCounter(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
+}
+
+func (s *StatsiteSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
+}
+
+func (s *StatsiteSink) AddSample(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
+}
+
+func (s *StatsiteSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
+}
+
+// Flattens the key for formatting, removes spaces
+func (s *StatsiteSink) flattenKey(parts []string) string {
+ joined := strings.Join(parts, ".")
+ return strings.Map(func(r rune) rune {
+ switch r {
+ case ':':
+ fallthrough
+ case ' ':
+ return '_'
+ default:
+ return r
+ }
+ }, joined)
+}
+
+// Flattens the key along with labels for formatting, removes spaces
+func (s *StatsiteSink) flattenKeyLabels(parts []string, labels []Label) string {
+ for _, label := range labels {
+ parts = append(parts, label.Value)
+ }
+ return s.flattenKey(parts)
+}
+
+// Does a non-blocking push to the metrics queue
+func (s *StatsiteSink) pushMetric(m string) {
+ select {
+ case s.metricQueue <- m:
+ default:
+ }
+}
+
+// Flushes metrics
+func (s *StatsiteSink) flushMetrics() {
+ var sock net.Conn
+ var err error
+ var wait <-chan time.Time
+ var buffered *bufio.Writer
+ ticker := time.NewTicker(flushInterval)
+ defer ticker.Stop()
+
+CONNECT:
+ // Attempt to connect
+ sock, err = net.Dial("tcp", s.addr)
+ if err != nil {
+ log.Printf("[ERR] Error connecting to statsite! Err: %s", err)
+ goto WAIT
+ }
+
+ // Create a buffered writer
+ buffered = bufio.NewWriter(sock)
+
+ for {
+ select {
+ case metric, ok := <-s.metricQueue:
+ // Get a metric from the queue
+ if !ok {
+ goto QUIT
+ }
+
+ // Try to send to statsite
+ _, err := buffered.Write([]byte(metric))
+ if err != nil {
+ log.Printf("[ERR] Error writing to statsite! Err: %s", err)
+ goto WAIT
+ }
+ case <-ticker.C:
+ if err := buffered.Flush(); err != nil {
+ log.Printf("[ERR] Error flushing to statsite! Err: %s", err)
+ goto WAIT
+ }
+ }
+ }
+
+WAIT:
+ // Wait for a while
+ wait = time.After(time.Duration(5) * time.Second)
+ for {
+ select {
+ // Dequeue the messages to avoid backlog
+ case _, ok := <-s.metricQueue:
+ if !ok {
+ goto QUIT
+ }
+ case <-wait:
+ goto CONNECT
+ }
+ }
+QUIT:
+ s.metricQueue = nil
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go
index 57bfbfb694c..e589f615619 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go
@@ -3,4 +3,4 @@
package aws
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.41.5"
+const goModuleVersion = "1.41.7"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md
index 404561eede3..a977899a4a2 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md
+++ b/vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md
@@ -1,3 +1,25 @@
+# v1.32.18 (2026-05-22)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.32.17 (2026-04-29)
+
+* **Dependency Update**: Update to smithy-go v1.25.1.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.32.16 (2026-04-17)
+
+* **Dependency Update**: Bump smithy-go to 1.25.0 to support endpointBdd trait
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.32.15 (2026-04-16)
+
+* No change notes available for this release.
+
+# v1.32.14 (2026-04-02)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
# v1.32.13 (2026-03-26)
* **Dependency Update**: Updated to the latest SDK module versions
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go
index 80aee928f6d..36b7e501ce1 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go
@@ -3,4 +3,4 @@
package config
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.32.13"
+const goModuleVersion = "1.32.18"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/errors.go b/vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/errors.go
similarity index 100%
rename from vendor/github.com/aws/aws-sdk-go-v2/internal/ini/errors.go
rename to vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/errors.go
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/ini.go b/vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/ini.go
similarity index 100%
rename from vendor/github.com/aws/aws-sdk-go-v2/internal/ini/ini.go
rename to vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/ini.go
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/parse.go b/vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/parse.go
similarity index 100%
rename from vendor/github.com/aws/aws-sdk-go-v2/internal/ini/parse.go
rename to vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/parse.go
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/sections.go b/vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/sections.go
similarity index 100%
rename from vendor/github.com/aws/aws-sdk-go-v2/internal/ini/sections.go
rename to vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/sections.go
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/strings.go b/vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/strings.go
similarity index 100%
rename from vendor/github.com/aws/aws-sdk-go-v2/internal/ini/strings.go
rename to vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/strings.go
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/token.go b/vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/token.go
similarity index 100%
rename from vendor/github.com/aws/aws-sdk-go-v2/internal/ini/token.go
rename to vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/token.go
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/tokenize.go b/vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/tokenize.go
similarity index 100%
rename from vendor/github.com/aws/aws-sdk-go-v2/internal/ini/tokenize.go
rename to vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/tokenize.go
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/value.go b/vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/value.go
similarity index 100%
rename from vendor/github.com/aws/aws-sdk-go-v2/internal/ini/value.go
rename to vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/value.go
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/shared_config.go b/vendor/github.com/aws/aws-sdk-go-v2/config/shared_config.go
index 44c616fd57e..5b251f54f57 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/config/shared_config.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/config/shared_config.go
@@ -12,8 +12,8 @@ import (
"time"
"github.com/aws/aws-sdk-go-v2/aws"
+ "github.com/aws/aws-sdk-go-v2/config/internal/ini"
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
- "github.com/aws/aws-sdk-go-v2/internal/ini"
"github.com/aws/aws-sdk-go-v2/internal/shareddefaults"
"github.com/aws/smithy-go/logging"
smithyrequestcompression "github.com/aws/smithy-go/private/requestcompression"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md
index e0af6364ae1..1eda74ea7c6 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md
+++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md
@@ -1,3 +1,21 @@
+# v1.19.17 (2026-05-22)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.19.16 (2026-04-29)
+
+* **Dependency Update**: Update to smithy-go v1.25.1.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.19.15 (2026-04-17)
+
+* **Dependency Update**: Bump smithy-go to 1.25.0 to support endpointBdd trait
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.19.14 (2026-04-02)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
# v1.19.13 (2026-03-26)
* **Dependency Update**: Updated to the latest SDK module versions
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go
index 450279760ec..cfabb14a687 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go
@@ -3,4 +3,4 @@
package credentials
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.19.13"
+const goModuleVersion = "1.19.17"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/CHANGELOG.md
index 829592ace27..e17294549fc 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/CHANGELOG.md
+++ b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/CHANGELOG.md
@@ -1,3 +1,13 @@
+# v1.18.23 (2026-04-29)
+
+* **Dependency Update**: Update to smithy-go v1.25.1.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.18.22 (2026-04-17)
+
+* **Dependency Update**: Bump smithy-go to 1.25.0 to support endpointBdd trait
+* **Dependency Update**: Updated to the latest SDK module versions
+
# v1.18.21 (2026-03-26)
* **Dependency Update**: Updated to the latest SDK module versions
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/go_module_metadata.go
index 52c3d3923dd..7f59387edc3 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/go_module_metadata.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/go_module_metadata.go
@@ -3,4 +3,4 @@
package imds
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.18.21"
+const goModuleVersion = "1.18.23"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md
index 1def5e2d9fa..0990a4143a7 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md
@@ -1,3 +1,13 @@
+# v1.4.23 (2026-04-29)
+
+* **Dependency Update**: Update to smithy-go v1.25.1.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.22 (2026-04-17)
+
+* **Dependency Update**: Bump smithy-go to 1.25.0 to support endpointBdd trait
+* **Dependency Update**: Updated to the latest SDK module versions
+
# v1.4.21 (2026-03-26)
* **Dependency Update**: Updated to the latest SDK module versions
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go
index 548da96016c..05a8d3e7bc1 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go
@@ -3,4 +3,4 @@
package configsources
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.4.21"
+const goModuleVersion = "1.4.23"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md
index a2a1c183ffa..49577e3e94c 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md
@@ -1,3 +1,13 @@
+# v2.7.23 (2026-04-29)
+
+* **Dependency Update**: Update to smithy-go v1.25.1.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v2.7.22 (2026-04-17)
+
+* **Dependency Update**: Bump smithy-go to 1.25.0 to support endpointBdd trait
+* **Dependency Update**: Updated to the latest SDK module versions
+
# v2.7.21 (2026-03-26)
* **Dependency Update**: Updated to the latest SDK module versions
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go
index 03a0b8c0380..1e92900a1e8 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go
@@ -3,4 +3,4 @@
package endpoints
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "2.7.21"
+const goModuleVersion = "2.7.23"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/CHANGELOG.md
deleted file mode 100644
index fdf434a5ebc..00000000000
--- a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/CHANGELOG.md
+++ /dev/null
@@ -1,296 +0,0 @@
-# v1.8.6 (2026-03-13)
-
-* **Bug Fix**: Replace usages of the old ioutil/ package throughout the SDK.
-
-# v1.8.5 (2026-03-03)
-
-* **Bug Fix**: Modernize non codegen files with go fix
-* **Dependency Update**: Bump minimum Go version to 1.24
-
-# v1.8.4 (2025-10-16)
-
-* **Dependency Update**: Bump minimum Go version to 1.23.
-
-# v1.8.3 (2025-02-18)
-
-* **Bug Fix**: Bump go version to 1.22
-
-# v1.8.2 (2025-01-24)
-
-* **Bug Fix**: Refactor filepath.Walk to filepath.WalkDir
-
-# v1.8.1 (2024-08-15)
-
-* **Dependency Update**: Bump minimum Go version to 1.21.
-
-# v1.8.0 (2024-02-13)
-
-* **Feature**: Bump minimum Go version to 1.20 per our language support policy.
-
-# v1.7.3 (2024-01-22)
-
-* **Bug Fix**: Remove invalid escaping of shared config values. All values in the shared config file will now be interpreted literally, save for fully-quoted strings which are unwrapped for legacy reasons.
-
-# v1.7.2 (2023-12-08)
-
-* **Bug Fix**: Correct loading of [services *] sections into shared config.
-
-# v1.7.1 (2023-11-16)
-
-* **Bug Fix**: Fix recognition of trailing comments in shared config properties. # or ; separators that aren't preceded by whitespace at the end of a property value should be considered part of it.
-
-# v1.7.0 (2023-11-13)
-
-* **Feature**: Replace the legacy config parser with a modern, less-strict implementation. Parsing failures within a section will now simply ignore the invalid line rather than silently drop the entire section.
-
-# v1.6.0 (2023-11-09.2)
-
-* **Feature**: BREAKFIX: In order to support subproperty parsing, invalid property definitions must not be ignored
-
-# v1.5.2 (2023-11-09)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.5.1 (2023-11-07)
-
-* **Bug Fix**: Fix subproperty performance regression
-
-# v1.5.0 (2023-11-01)
-
-* **Feature**: Adds support for configured endpoints via environment variables and the AWS shared configuration file.
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.4.0 (2023-10-31)
-
-* **Feature**: **BREAKING CHANGE**: Bump minimum go version to 1.19 per the revised [go version support policy](https://aws.amazon.com/blogs/developer/aws-sdk-for-go-aligns-with-go-release-policy-on-supported-runtimes/).
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.45 (2023-10-12)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.44 (2023-10-06)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.43 (2023-09-22)
-
-* **Bug Fix**: Fixed a bug where merging `max_attempts` or `duration_seconds` fields across shared config files with invalid values would silently default them to 0.
-* **Bug Fix**: Move type assertion of config values out of the parsing stage, which resolves an issue where the contents of a profile would silently be dropped with certain numeric formats.
-
-# v1.3.42 (2023-08-21)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.41 (2023-08-18)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.40 (2023-08-17)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.39 (2023-08-07)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.38 (2023-07-31)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.37 (2023-07-28)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.36 (2023-07-13)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.35 (2023-06-13)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.34 (2023-04-24)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.33 (2023-04-07)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.32 (2023-03-21)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.31 (2023-03-10)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.30 (2023-02-20)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.29 (2023-02-03)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.28 (2022-12-15)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.27 (2022-12-02)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.26 (2022-10-24)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.25 (2022-10-21)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.24 (2022-09-20)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.23 (2022-09-14)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.22 (2022-09-02)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.21 (2022-08-31)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.20 (2022-08-29)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.19 (2022-08-11)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.18 (2022-08-09)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.17 (2022-08-08)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.16 (2022-08-01)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.15 (2022-07-05)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.14 (2022-06-29)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.13 (2022-06-07)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.12 (2022-05-17)
-
-* **Bug Fix**: Removes the fuzz testing files from the module, as they are invalid and not used.
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.11 (2022-04-25)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.10 (2022-03-30)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.9 (2022-03-24)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.8 (2022-03-23)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.7 (2022-03-08)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.6 (2022-02-24)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.5 (2022-01-28)
-
-* **Bug Fix**: Fixes the SDK's handling of `duration_sections` in the shared credentials file or specified in multiple shared config and shared credentials files under the same profile. [#1568](https://github.com/aws/aws-sdk-go-v2/pull/1568). Thanks to [Amir Szekely](https://github.com/kichik) for help reproduce this bug.
-
-# v1.3.4 (2022-01-14)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.3 (2022-01-07)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.2 (2021-12-02)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.1 (2021-11-19)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.3.0 (2021-11-06)
-
-* **Feature**: The SDK now supports configuration of FIPS and DualStack endpoints using environment variables, shared configuration, or programmatically.
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.2.5 (2021-10-21)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.2.4 (2021-10-11)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.2.3 (2021-09-17)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.2.2 (2021-08-27)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.2.1 (2021-08-19)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.2.0 (2021-08-04)
-
-* **Feature**: adds error handling for defered close calls
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.1.1 (2021-07-15)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.1.0 (2021-07-01)
-
-* **Feature**: Support for `:`, `=`, `[`, `]` being present in expression values.
-
-# v1.0.1 (2021-06-25)
-
-* **Dependency Update**: Updated to the latest SDK module versions
-
-# v1.0.0 (2021-05-20)
-
-* **Release**: The `github.com/aws/aws-sdk-go-v2/internal/ini` package is now a Go Module.
-* **Dependency Update**: Updated to the latest SDK module versions
-
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/go_module_metadata.go
deleted file mode 100644
index 1dc2e12aa8f..00000000000
--- a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/go_module_metadata.go
+++ /dev/null
@@ -1,6 +0,0 @@
-// Code generated by internal/repotools/cmd/updatemodulemeta DO NOT EDIT.
-
-package ini
-
-// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.8.6"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/CHANGELOG.md
new file mode 100644
index 00000000000..e1e3c23a740
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/CHANGELOG.md
@@ -0,0 +1,460 @@
+# v1.4.24 (2026-04-29)
+
+* **Dependency Update**: Update to smithy-go v1.25.1.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.23 (2026-04-17)
+
+* **Dependency Update**: Bump smithy-go to 1.25.0 to support endpointBdd trait
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.22 (2026-03-26)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.21 (2026-03-13)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.20 (2026-03-05)
+
+* **Bug Fix**: Read the correct auth property for SigV4A signing names.
+
+# v1.4.19 (2026-03-03)
+
+* **Bug Fix**: Modernize non codegen files with go fix
+* **Dependency Update**: Bump minimum Go version to 1.24
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.18 (2026-02-23)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.17 (2026-01-09)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.16 (2025-12-08)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.15 (2025-12-02)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+* **Dependency Update**: Upgrade to smithy-go v1.24.0. Notably this version of the library reduces the allocation footprint of the middleware system. We observe a ~10% reduction in allocations per SDK call with this change.
+
+# v1.4.14 (2025-11-19.2)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.13 (2025-11-04)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+* **Dependency Update**: Upgrade to smithy-go v1.23.2 which should convey some passive reduction of overall allocations, especially when not using the metrics system.
+
+# v1.4.12 (2025-10-30)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.11 (2025-10-23)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.10 (2025-10-16)
+
+* **Dependency Update**: Bump minimum Go version to 1.23.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.9 (2025-09-26)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.8 (2025-09-23)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.7 (2025-09-08)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.6 (2025-08-29)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.5 (2025-08-27)
+
+* **Dependency Update**: Update to smithy-go v1.23.0.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.4 (2025-08-21)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.3 (2025-08-11)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.2 (2025-08-04)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.1 (2025-07-30)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.4.0 (2025-07-28)
+
+* **Feature**: Add support for HTTP interceptors.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.37 (2025-07-19)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.36 (2025-06-17)
+
+* **Dependency Update**: Update to smithy-go v1.22.4.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.35 (2025-06-10)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.34 (2025-02-27)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.33 (2025-02-18)
+
+* **Bug Fix**: Bump go version to 1.22
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.32 (2025-02-05)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.31 (2025-01-31)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.30 (2025-01-30)
+
+* **Bug Fix**: Do not sign Transfer-Encoding header in Sigv4[a]. Fixes a signer mismatch issue with S3 Accelerate.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.29 (2025-01-24)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+* **Dependency Update**: Upgrade to smithy-go v1.22.2.
+
+# v1.3.28 (2025-01-15)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.27 (2025-01-09)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.26 (2024-12-19)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.25 (2024-12-02)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.24 (2024-11-18)
+
+* **Dependency Update**: Update to smithy-go v1.22.1.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.23 (2024-11-06)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.22 (2024-10-28)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.21 (2024-10-08)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.20 (2024-10-07)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.19 (2024-10-04)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.18 (2024-09-20)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.17 (2024-09-03)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.16 (2024-08-15)
+
+* **Dependency Update**: Bump minimum Go version to 1.21.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.15 (2024-07-10.2)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.14 (2024-07-10)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.13 (2024-06-28)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.12 (2024-06-19)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.11 (2024-06-18)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.10 (2024-06-17)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.9 (2024-06-07)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.8 (2024-06-03)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.7 (2024-05-16)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.6 (2024-05-15)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.5 (2024-03-29)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.4 (2024-03-18)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.3 (2024-03-07)
+
+* **Bug Fix**: Remove dependency on go-cmp.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.2 (2024-02-23)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.1 (2024-02-21)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.3.0 (2024-02-13)
+
+* **Feature**: Bump minimum Go version to 1.20 per our language support policy.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.2.10 (2024-01-04)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.2.9 (2023-12-07)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.2.8 (2023-12-01)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.2.7 (2023-11-30)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.2.6 (2023-11-29)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.2.5 (2023-11-28.2)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.2.4 (2023-11-20)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.2.3 (2023-11-15)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.2.2 (2023-11-09)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.2.1 (2023-11-01)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.2.0 (2023-10-31)
+
+* **Feature**: **BREAKING CHANGE**: Bump minimum go version to 1.19 per the revised [go version support policy](https://aws.amazon.com/blogs/developer/aws-sdk-for-go-aligns-with-go-release-policy-on-supported-runtimes/).
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.1.6 (2023-10-12)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.1.5 (2023-10-06)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.1.4 (2023-08-21)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.1.3 (2023-08-18)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.1.2 (2023-08-17)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.1.1 (2023-08-07)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.1.0 (2023-07-31)
+
+* **Feature**: Adds support for smithy-modeled endpoint resolution. A new rules-based endpoint resolution will be added to the SDK which will supercede and deprecate existing endpoint resolution. Specifically, EndpointResolver will be deprecated while BaseEndpoint and EndpointResolverV2 will take its place. For more information, please see the Endpoints section in our Developer Guide.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.28 (2023-07-28)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.27 (2023-07-13)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.26 (2023-06-13)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.25 (2023-04-24)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.24 (2023-04-07)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.23 (2023-03-21)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.22 (2023-03-10)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.21 (2023-02-20)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.20 (2023-02-14)
+
+* No change notes available for this release.
+
+# v1.0.19 (2023-02-03)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.18 (2022-12-15)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.17 (2022-12-02)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.16 (2022-10-24)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.15 (2022-10-21)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.14 (2022-09-20)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.13 (2022-09-14)
+
+* **Bug Fix**: Fixes an issues where an error from an underlying SigV4 credential provider would not be surfaced from the SigV4a credential provider. Contribution by [sakthipriyan-aqfer](https://github.com/sakthipriyan-aqfer).
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.12 (2022-09-02)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.11 (2022-08-31)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.10 (2022-08-29)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.9 (2022-08-11)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.8 (2022-08-09)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.7 (2022-08-08)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.6 (2022-08-01)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.5 (2022-07-05)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.4 (2022-06-29)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.3 (2022-06-07)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.2 (2022-05-17)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.1 (2022-04-25)
+
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.0 (2022-04-07)
+
+* **Release**: New internal v4a signing module location.
+
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/LICENSE.txt b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/LICENSE.txt
similarity index 100%
rename from vendor/github.com/aws/aws-sdk-go-v2/internal/ini/LICENSE.txt
rename to vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/LICENSE.txt
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/credentials.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/credentials.go
new file mode 100644
index 00000000000..3ae3a019e62
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/credentials.go
@@ -0,0 +1,141 @@
+package v4a
+
+import (
+ "context"
+ "crypto/ecdsa"
+ "fmt"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/aws/aws-sdk-go-v2/aws"
+ "github.com/aws/aws-sdk-go-v2/internal/sdk"
+)
+
+// Credentials is Context, ECDSA, and Optional Session Token that can be used
+// to sign requests using SigV4a
+type Credentials struct {
+ Context string
+ PrivateKey *ecdsa.PrivateKey
+ SessionToken string
+
+ // Time the credentials will expire.
+ CanExpire bool
+ Expires time.Time
+}
+
+// Expired returns if the credentials have expired.
+func (v Credentials) Expired() bool {
+ if v.CanExpire {
+ return !v.Expires.After(sdk.NowTime())
+ }
+
+ return false
+}
+
+// HasKeys returns if the credentials keys are set.
+func (v Credentials) HasKeys() bool {
+ return len(v.Context) > 0 && v.PrivateKey != nil
+}
+
+// SymmetricCredentialAdaptor wraps a SigV4 AccessKey/SecretKey provider and adapts the credentials
+// to a ECDSA PrivateKey for signing with SiV4a
+type SymmetricCredentialAdaptor struct {
+ SymmetricProvider aws.CredentialsProvider
+
+ asymmetric atomic.Value
+ m sync.Mutex
+}
+
+// Retrieve retrieves symmetric credentials from the underlying provider.
+func (s *SymmetricCredentialAdaptor) Retrieve(ctx context.Context) (aws.Credentials, error) {
+ symCreds, err := s.retrieveFromSymmetricProvider(ctx)
+ if err != nil {
+ return aws.Credentials{}, err
+ }
+
+ if asymCreds := s.getCreds(); asymCreds == nil {
+ return symCreds, nil
+ }
+
+ s.m.Lock()
+ defer s.m.Unlock()
+
+ asymCreds := s.getCreds()
+ if asymCreds == nil {
+ return symCreds, nil
+ }
+
+ // if the context does not match the access key id clear it
+ if asymCreds.Context != symCreds.AccessKeyID {
+ s.asymmetric.Store((*Credentials)(nil))
+ }
+
+ return symCreds, nil
+}
+
+// RetrievePrivateKey returns credentials suitable for SigV4a signing
+func (s *SymmetricCredentialAdaptor) RetrievePrivateKey(ctx context.Context) (Credentials, error) {
+ if asymCreds := s.getCreds(); asymCreds != nil {
+ return *asymCreds, nil
+ }
+
+ s.m.Lock()
+ defer s.m.Unlock()
+
+ if asymCreds := s.getCreds(); asymCreds != nil {
+ return *asymCreds, nil
+ }
+
+ symmetricCreds, err := s.retrieveFromSymmetricProvider(ctx)
+ if err != nil {
+ return Credentials{}, fmt.Errorf("failed to retrieve symmetric credentials: %v", err)
+ }
+
+ privateKey, err := deriveKeyFromAccessKeyPair(symmetricCreds.AccessKeyID, symmetricCreds.SecretAccessKey)
+ if err != nil {
+ return Credentials{}, fmt.Errorf("failed to derive assymetric key from credentials")
+ }
+
+ creds := Credentials{
+ Context: symmetricCreds.AccessKeyID,
+ PrivateKey: privateKey,
+ SessionToken: symmetricCreds.SessionToken,
+ CanExpire: symmetricCreds.CanExpire,
+ Expires: symmetricCreds.Expires,
+ }
+
+ s.asymmetric.Store(&creds)
+
+ return creds, nil
+}
+
+func (s *SymmetricCredentialAdaptor) getCreds() *Credentials {
+ v := s.asymmetric.Load()
+
+ if v == nil {
+ return nil
+ }
+
+ c := v.(*Credentials)
+ if c != nil && c.HasKeys() && !c.Expired() {
+ return c
+ }
+
+ return nil
+}
+
+func (s *SymmetricCredentialAdaptor) retrieveFromSymmetricProvider(ctx context.Context) (aws.Credentials, error) {
+ credentials, err := s.SymmetricProvider.Retrieve(ctx)
+ if err != nil {
+ return aws.Credentials{}, err
+ }
+
+ return credentials, nil
+}
+
+// CredentialsProvider is the interface for a provider to retrieve credentials
+// to sign requests with.
+type CredentialsProvider interface {
+ RetrievePrivateKey(context.Context) (Credentials, error)
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/error.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/error.go
new file mode 100644
index 00000000000..380d1742714
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/error.go
@@ -0,0 +1,17 @@
+package v4a
+
+import "fmt"
+
+// SigningError indicates an error condition occurred while performing SigV4a signing
+type SigningError struct {
+ Err error
+}
+
+func (e *SigningError) Error() string {
+ return fmt.Sprintf("failed to sign request: %v", e.Err)
+}
+
+// Unwrap returns the underlying error cause
+func (e *SigningError) Unwrap() error {
+ return e.Err
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/go_module_metadata.go
new file mode 100644
index 00000000000..455cb74e1a5
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/go_module_metadata.go
@@ -0,0 +1,6 @@
+// Code generated by internal/repotools/cmd/updatemodulemeta DO NOT EDIT.
+
+package v4a
+
+// goModuleVersion is the tagged release for this module
+const goModuleVersion = "1.4.24"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/crypto/compare.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/crypto/compare.go
new file mode 100644
index 00000000000..1d0f25f8c20
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/crypto/compare.go
@@ -0,0 +1,30 @@
+package crypto
+
+import "fmt"
+
+// ConstantTimeByteCompare is a constant-time byte comparison of x and y. This function performs an absolute comparison
+// if the two byte slices assuming they represent a big-endian number.
+//
+// error if len(x) != len(y)
+// -1 if x < y
+// 0 if x == y
+// +1 if x > y
+func ConstantTimeByteCompare(x, y []byte) (int, error) {
+ if len(x) != len(y) {
+ return 0, fmt.Errorf("slice lengths do not match")
+ }
+
+ xLarger, yLarger := 0, 0
+
+ for i := 0; i < len(x); i++ {
+ xByte, yByte := int(x[i]), int(y[i])
+
+ x := ((yByte - xByte) >> 8) & 1
+ y := ((xByte - yByte) >> 8) & 1
+
+ xLarger |= x &^ yLarger
+ yLarger |= y &^ xLarger
+ }
+
+ return xLarger - yLarger, nil
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/crypto/ecc.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/crypto/ecc.go
new file mode 100644
index 00000000000..758c73fcb3e
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/crypto/ecc.go
@@ -0,0 +1,113 @@
+package crypto
+
+import (
+ "bytes"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/hmac"
+ "encoding/asn1"
+ "encoding/binary"
+ "fmt"
+ "hash"
+ "math"
+ "math/big"
+)
+
+type ecdsaSignature struct {
+ R, S *big.Int
+}
+
+// ECDSAKey takes the given elliptic curve, and private key (d) byte slice
+// and returns the private ECDSA key.
+func ECDSAKey(curve elliptic.Curve, d []byte) *ecdsa.PrivateKey {
+ return ECDSAKeyFromPoint(curve, (&big.Int{}).SetBytes(d))
+}
+
+// ECDSAKeyFromPoint takes the given elliptic curve and point and returns the
+// private and public keypair
+func ECDSAKeyFromPoint(curve elliptic.Curve, d *big.Int) *ecdsa.PrivateKey {
+ pX, pY := curve.ScalarBaseMult(d.Bytes())
+
+ privKey := &ecdsa.PrivateKey{
+ PublicKey: ecdsa.PublicKey{
+ Curve: curve,
+ X: pX,
+ Y: pY,
+ },
+ D: d,
+ }
+
+ return privKey
+}
+
+// ECDSAPublicKey takes the provide curve and (x, y) coordinates and returns
+// *ecdsa.PublicKey. Returns an error if the given points are not on the curve.
+func ECDSAPublicKey(curve elliptic.Curve, x, y []byte) (*ecdsa.PublicKey, error) {
+ xPoint := (&big.Int{}).SetBytes(x)
+ yPoint := (&big.Int{}).SetBytes(y)
+
+ if !curve.IsOnCurve(xPoint, yPoint) {
+ return nil, fmt.Errorf("point(%v, %v) is not on the given curve", xPoint.String(), yPoint.String())
+ }
+
+ return &ecdsa.PublicKey{
+ Curve: curve,
+ X: xPoint,
+ Y: yPoint,
+ }, nil
+}
+
+// VerifySignature takes the provided public key, hash, and asn1 encoded signature and returns
+// whether the given signature is valid.
+func VerifySignature(key *ecdsa.PublicKey, hash []byte, signature []byte) (bool, error) {
+ var ecdsaSignature ecdsaSignature
+
+ _, err := asn1.Unmarshal(signature, &ecdsaSignature)
+ if err != nil {
+ return false, err
+ }
+
+ return ecdsa.Verify(key, hash, ecdsaSignature.R, ecdsaSignature.S), nil
+}
+
+// HMACKeyDerivation provides an implementation of a NIST-800-108 of a KDF (Key Derivation Function) in Counter Mode.
+// For the purposes of this implantation HMAC is used as the PRF (Pseudorandom function), where the value of
+// `r` is defined as a 4 byte counter.
+func HMACKeyDerivation(hash func() hash.Hash, bitLen int, key []byte, label, context []byte) ([]byte, error) {
+ // verify that we won't overflow the counter
+ n := int64(math.Ceil((float64(bitLen) / 8) / float64(hash().Size())))
+ if n > 0x7FFFFFFF {
+ return nil, fmt.Errorf("unable to derive key of size %d using 32-bit counter", bitLen)
+ }
+
+ // verify the requested bit length is not larger then the length encoding size
+ if int64(bitLen) > 0x7FFFFFFF {
+ return nil, fmt.Errorf("bitLen is greater than 32-bits")
+ }
+
+ fixedInput := bytes.NewBuffer(nil)
+ fixedInput.Write(label)
+ fixedInput.WriteByte(0x00)
+ fixedInput.Write(context)
+ if err := binary.Write(fixedInput, binary.BigEndian, int32(bitLen)); err != nil {
+ return nil, fmt.Errorf("failed to write bit length to fixed input string: %v", err)
+ }
+
+ var output []byte
+
+ h := hmac.New(hash, key)
+
+ for i := int64(1); i <= n; i++ {
+ h.Reset()
+ if err := binary.Write(h, binary.BigEndian, int32(i)); err != nil {
+ return nil, err
+ }
+ _, err := h.Write(fixedInput.Bytes())
+ if err != nil {
+ return nil, err
+ }
+ output = append(output, h.Sum(nil)...)
+ }
+
+ return output[:bitLen/8], nil
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/const.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/const.go
new file mode 100644
index 00000000000..89a76e2eaab
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/const.go
@@ -0,0 +1,36 @@
+package v4
+
+const (
+ // EmptyStringSHA256 is the hex encoded sha256 value of an empty string
+ EmptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
+
+ // UnsignedPayload indicates that the request payload body is unsigned
+ UnsignedPayload = "UNSIGNED-PAYLOAD"
+
+ // AmzAlgorithmKey indicates the signing algorithm
+ AmzAlgorithmKey = "X-Amz-Algorithm"
+
+ // AmzSecurityTokenKey indicates the security token to be used with temporary credentials
+ AmzSecurityTokenKey = "X-Amz-Security-Token"
+
+ // AmzDateKey is the UTC timestamp for the request in the format YYYYMMDD'T'HHMMSS'Z'
+ AmzDateKey = "X-Amz-Date"
+
+ // AmzCredentialKey is the access key ID and credential scope
+ AmzCredentialKey = "X-Amz-Credential"
+
+ // AmzSignedHeadersKey is the set of headers signed for the request
+ AmzSignedHeadersKey = "X-Amz-SignedHeaders"
+
+ // AmzSignatureKey is the query parameter to store the SigV4 signature
+ AmzSignatureKey = "X-Amz-Signature"
+
+ // TimeFormat is the time format to be used in the X-Amz-Date header or query parameter
+ TimeFormat = "20060102T150405Z"
+
+ // ShortTimeFormat is the shorten time format used in the credential scope
+ ShortTimeFormat = "20060102"
+
+ // ContentSHAKey is the SHA256 of request body
+ ContentSHAKey = "X-Amz-Content-Sha256"
+)
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/header_rules.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/header_rules.go
new file mode 100644
index 00000000000..a15177e8f3f
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/header_rules.go
@@ -0,0 +1,82 @@
+package v4
+
+import (
+ sdkstrings "github.com/aws/aws-sdk-go-v2/internal/strings"
+)
+
+// Rules houses a set of Rule needed for validation of a
+// string value
+type Rules []Rule
+
+// Rule interface allows for more flexible rules and just simply
+// checks whether or not a value adheres to that Rule
+type Rule interface {
+ IsValid(value string) bool
+}
+
+// IsValid will iterate through all rules and see if any rules
+// apply to the value and supports nested rules
+func (r Rules) IsValid(value string) bool {
+ for _, rule := range r {
+ if rule.IsValid(value) {
+ return true
+ }
+ }
+ return false
+}
+
+// MapRule generic Rule for maps
+type MapRule map[string]struct{}
+
+// IsValid for the map Rule satisfies whether it exists in the map
+func (m MapRule) IsValid(value string) bool {
+ _, ok := m[value]
+ return ok
+}
+
+// AllowList is a generic Rule for whitelisting
+type AllowList struct {
+ Rule
+}
+
+// IsValid for AllowList checks if the value is within the AllowList
+func (w AllowList) IsValid(value string) bool {
+ return w.Rule.IsValid(value)
+}
+
+// DenyList is a generic Rule for blacklisting
+type DenyList struct {
+ Rule
+}
+
+// IsValid for AllowList checks if the value is within the AllowList
+func (b DenyList) IsValid(value string) bool {
+ return !b.Rule.IsValid(value)
+}
+
+// Patterns is a list of strings to match against
+type Patterns []string
+
+// IsValid for Patterns checks each pattern and returns if a match has
+// been found
+func (p Patterns) IsValid(value string) bool {
+ for _, pattern := range p {
+ if sdkstrings.HasPrefixFold(value, pattern) {
+ return true
+ }
+ }
+ return false
+}
+
+// InclusiveRules rules allow for rules to depend on one another
+type InclusiveRules []Rule
+
+// IsValid will return true if all rules are true
+func (r InclusiveRules) IsValid(value string) bool {
+ for _, rule := range r {
+ if !rule.IsValid(value) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/headers.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/headers.go
new file mode 100644
index 00000000000..688f834742c
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/headers.go
@@ -0,0 +1,68 @@
+package v4
+
+// IgnoredHeaders is a list of headers that are ignored during signing
+var IgnoredHeaders = Rules{
+ DenyList{
+ MapRule{
+ "Authorization": struct{}{},
+ "User-Agent": struct{}{},
+ "X-Amzn-Trace-Id": struct{}{},
+ "Transfer-Encoding": struct{}{},
+ },
+ },
+}
+
+// RequiredSignedHeaders is a whitelist for Build canonical headers.
+var RequiredSignedHeaders = Rules{
+ AllowList{
+ MapRule{
+ "Cache-Control": struct{}{},
+ "Content-Disposition": struct{}{},
+ "Content-Encoding": struct{}{},
+ "Content-Language": struct{}{},
+ "Content-Md5": struct{}{},
+ "Content-Type": struct{}{},
+ "Expires": struct{}{},
+ "If-Match": struct{}{},
+ "If-Modified-Since": struct{}{},
+ "If-None-Match": struct{}{},
+ "If-Unmodified-Since": struct{}{},
+ "Range": struct{}{},
+ "X-Amz-Acl": struct{}{},
+ "X-Amz-Copy-Source": struct{}{},
+ "X-Amz-Copy-Source-If-Match": struct{}{},
+ "X-Amz-Copy-Source-If-Modified-Since": struct{}{},
+ "X-Amz-Copy-Source-If-None-Match": struct{}{},
+ "X-Amz-Copy-Source-If-Unmodified-Since": struct{}{},
+ "X-Amz-Copy-Source-Range": struct{}{},
+ "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm": struct{}{},
+ "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key": struct{}{},
+ "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-Md5": struct{}{},
+ "X-Amz-Grant-Full-control": struct{}{},
+ "X-Amz-Grant-Read": struct{}{},
+ "X-Amz-Grant-Read-Acp": struct{}{},
+ "X-Amz-Grant-Write": struct{}{},
+ "X-Amz-Grant-Write-Acp": struct{}{},
+ "X-Amz-Metadata-Directive": struct{}{},
+ "X-Amz-Mfa": struct{}{},
+ "X-Amz-Request-Payer": struct{}{},
+ "X-Amz-Server-Side-Encryption": struct{}{},
+ "X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": struct{}{},
+ "X-Amz-Server-Side-Encryption-Customer-Algorithm": struct{}{},
+ "X-Amz-Server-Side-Encryption-Customer-Key": struct{}{},
+ "X-Amz-Server-Side-Encryption-Customer-Key-Md5": struct{}{},
+ "X-Amz-Storage-Class": struct{}{},
+ "X-Amz-Website-Redirect-Location": struct{}{},
+ "X-Amz-Content-Sha256": struct{}{},
+ "X-Amz-Tagging": struct{}{},
+ },
+ },
+ Patterns{"X-Amz-Meta-"},
+}
+
+// AllowedQueryHoisting is a whitelist for Build query headers. The boolean value
+// represents whether or not it is a pattern.
+var AllowedQueryHoisting = InclusiveRules{
+ DenyList{RequiredSignedHeaders},
+ Patterns{"X-Amz-"},
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/hmac.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/hmac.go
new file mode 100644
index 00000000000..e7fa7a1b1e6
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/hmac.go
@@ -0,0 +1,13 @@
+package v4
+
+import (
+ "crypto/hmac"
+ "crypto/sha256"
+)
+
+// HMACSHA256 computes a HMAC-SHA256 of data given the provided key.
+func HMACSHA256(key []byte, data []byte) []byte {
+ hash := hmac.New(sha256.New, key)
+ hash.Write(data)
+ return hash.Sum(nil)
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/host.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/host.go
new file mode 100644
index 00000000000..bf93659a43f
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/host.go
@@ -0,0 +1,75 @@
+package v4
+
+import (
+ "net/http"
+ "strings"
+)
+
+// SanitizeHostForHeader removes default port from host and updates request.Host
+func SanitizeHostForHeader(r *http.Request) {
+ host := getHost(r)
+ port := portOnly(host)
+ if port != "" && isDefaultPort(r.URL.Scheme, port) {
+ r.Host = stripPort(host)
+ }
+}
+
+// Returns host from request
+func getHost(r *http.Request) string {
+ if r.Host != "" {
+ return r.Host
+ }
+
+ return r.URL.Host
+}
+
+// Hostname returns u.Host, without any port number.
+//
+// If Host is an IPv6 literal with a port number, Hostname returns the
+// IPv6 literal without the square brackets. IPv6 literals may include
+// a zone identifier.
+//
+// Copied from the Go 1.8 standard library (net/url)
+func stripPort(hostport string) string {
+ colon := strings.IndexByte(hostport, ':')
+ if colon == -1 {
+ return hostport
+ }
+ if i := strings.IndexByte(hostport, ']'); i != -1 {
+ return strings.TrimPrefix(hostport[:i], "[")
+ }
+ return hostport[:colon]
+}
+
+// Port returns the port part of u.Host, without the leading colon.
+// If u.Host doesn't contain a port, Port returns an empty string.
+//
+// Copied from the Go 1.8 standard library (net/url)
+func portOnly(hostport string) string {
+ colon := strings.IndexByte(hostport, ':')
+ if colon == -1 {
+ return ""
+ }
+ if i := strings.Index(hostport, "]:"); i != -1 {
+ return hostport[i+len("]:"):]
+ }
+ if strings.Contains(hostport, "]") {
+ return ""
+ }
+ return hostport[colon+len(":"):]
+}
+
+// Returns true if the specified URI is using the standard port
+// (i.e. port 80 for HTTP URIs or 443 for HTTPS URIs)
+func isDefaultPort(scheme, port string) bool {
+ if port == "" {
+ return true
+ }
+
+ lowerCaseScheme := strings.ToLower(scheme)
+ if (lowerCaseScheme == "http" && port == "80") || (lowerCaseScheme == "https" && port == "443") {
+ return true
+ }
+
+ return false
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/time.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/time.go
new file mode 100644
index 00000000000..1de06a765d1
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/time.go
@@ -0,0 +1,36 @@
+package v4
+
+import "time"
+
+// SigningTime provides a wrapper around a time.Time which provides cached values for SigV4 signing.
+type SigningTime struct {
+ time.Time
+ timeFormat string
+ shortTimeFormat string
+}
+
+// NewSigningTime creates a new SigningTime given a time.Time
+func NewSigningTime(t time.Time) SigningTime {
+ return SigningTime{
+ Time: t,
+ }
+}
+
+// TimeFormat provides a time formatted in the X-Amz-Date format.
+func (m *SigningTime) TimeFormat() string {
+ return m.format(&m.timeFormat, TimeFormat)
+}
+
+// ShortTimeFormat provides a time formatted of 20060102.
+func (m *SigningTime) ShortTimeFormat() string {
+ return m.format(&m.shortTimeFormat, ShortTimeFormat)
+}
+
+func (m *SigningTime) format(target *string, format string) string {
+ if len(*target) > 0 {
+ return *target
+ }
+ v := m.Time.Format(format)
+ *target = v
+ return v
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/util.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/util.go
new file mode 100644
index 00000000000..741019b5f9d
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/util.go
@@ -0,0 +1,64 @@
+package v4
+
+import (
+ "net/url"
+ "strings"
+)
+
+const doubleSpace = " "
+
+// StripExcessSpaces will rewrite the passed in slice's string values to not
+// contain muliple side-by-side spaces.
+func StripExcessSpaces(str string) string {
+ var j, k, l, m, spaces int
+ // Trim trailing spaces
+ for j = len(str) - 1; j >= 0 && str[j] == ' '; j-- {
+ }
+
+ // Trim leading spaces
+ for k = 0; k < j && str[k] == ' '; k++ {
+ }
+ str = str[k : j+1]
+
+ // Strip multiple spaces.
+ j = strings.Index(str, doubleSpace)
+ if j < 0 {
+ return str
+ }
+
+ buf := []byte(str)
+ for k, m, l = j, j, len(buf); k < l; k++ {
+ if buf[k] == ' ' {
+ if spaces == 0 {
+ // First space.
+ buf[m] = buf[k]
+ m++
+ }
+ spaces++
+ } else {
+ // End of multiple spaces.
+ spaces = 0
+ buf[m] = buf[k]
+ m++
+ }
+ }
+
+ return string(buf[:m])
+}
+
+// GetURIPath returns the escaped URI component from the provided URL
+func GetURIPath(u *url.URL) string {
+ var uri string
+
+ if len(u.Opaque) > 0 {
+ uri = "/" + strings.Join(strings.Split(u.Opaque, "/")[3:], "/")
+ } else {
+ uri = u.EscapedPath()
+ }
+
+ if len(uri) == 0 {
+ uri = "/"
+ }
+
+ return uri
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/middleware.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/middleware.go
new file mode 100644
index 00000000000..64b8b4e330e
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/middleware.go
@@ -0,0 +1,118 @@
+package v4a
+
+import (
+ "context"
+ "fmt"
+ awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
+ v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
+ internalauth "github.com/aws/aws-sdk-go-v2/internal/auth"
+ "github.com/aws/smithy-go/middleware"
+ smithyhttp "github.com/aws/smithy-go/transport/http"
+ "net/http"
+ "time"
+)
+
+// HTTPSigner is SigV4a HTTP signer implementation
+type HTTPSigner interface {
+ SignHTTP(ctx context.Context, credentials Credentials, r *http.Request, payloadHash string, service string, regionSet []string, signingTime time.Time, optfns ...func(*SignerOptions)) error
+}
+
+// SignHTTPRequestMiddlewareOptions is the middleware options for constructing a SignHTTPRequestMiddleware.
+type SignHTTPRequestMiddlewareOptions struct {
+ Credentials CredentialsProvider
+ Signer HTTPSigner
+ LogSigning bool
+}
+
+// SignHTTPRequestMiddleware is a middleware for signing an HTTP request using SigV4a.
+type SignHTTPRequestMiddleware struct {
+ credentials CredentialsProvider
+ signer HTTPSigner
+ logSigning bool
+}
+
+// NewSignHTTPRequestMiddleware constructs a SignHTTPRequestMiddleware using the given SignHTTPRequestMiddlewareOptions.
+func NewSignHTTPRequestMiddleware(options SignHTTPRequestMiddlewareOptions) *SignHTTPRequestMiddleware {
+ return &SignHTTPRequestMiddleware{
+ credentials: options.Credentials,
+ signer: options.Signer,
+ logSigning: options.LogSigning,
+ }
+}
+
+// ID the middleware identifier.
+func (s *SignHTTPRequestMiddleware) ID() string {
+ return "Signing"
+}
+
+// HandleFinalize signs an HTTP request using SigV4a.
+func (s *SignHTTPRequestMiddleware) HandleFinalize(
+ ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
+) (
+ out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
+) {
+ if !hasCredentialProvider(s.credentials) {
+ return next.HandleFinalize(ctx, in)
+ }
+
+ req, ok := in.Request.(*smithyhttp.Request)
+ if !ok {
+ return out, metadata, fmt.Errorf("unexpected request middleware type %T", in.Request)
+ }
+
+ signingName, signingRegion := awsmiddleware.GetSigningName(ctx), awsmiddleware.GetSigningRegion(ctx)
+ payloadHash := v4.GetPayloadHash(ctx)
+ if len(payloadHash) == 0 {
+ return out, metadata, &SigningError{Err: fmt.Errorf("computed payload hash missing from context")}
+ }
+
+ credentials, err := s.credentials.RetrievePrivateKey(ctx)
+ if err != nil {
+ return out, metadata, &SigningError{Err: fmt.Errorf("failed to retrieve credentials: %w", err)}
+ }
+
+ signerOptions := []func(o *SignerOptions){
+ func(o *SignerOptions) {
+ o.Logger = middleware.GetLogger(ctx)
+ o.LogSigning = s.logSigning
+ },
+ }
+
+ // existing DisableURIPathEscaping is equivalent in purpose
+ // to authentication scheme property DisableDoubleEncoding
+ disableDoubleEncoding, overridden := internalauth.GetDisableDoubleEncoding(ctx)
+ if overridden {
+ signerOptions = append(signerOptions, func(o *SignerOptions) {
+ o.DisableURIPathEscaping = disableDoubleEncoding
+ })
+ }
+
+ err = s.signer.SignHTTP(ctx, credentials, req.Request, payloadHash, signingName, []string{signingRegion}, time.Now().UTC(), signerOptions...)
+ if err != nil {
+ return out, metadata, &SigningError{Err: fmt.Errorf("failed to sign http request, %w", err)}
+ }
+
+ return next.HandleFinalize(ctx, in)
+}
+
+func hasCredentialProvider(p CredentialsProvider) bool {
+ if p == nil {
+ return false
+ }
+
+ return true
+}
+
+// RegisterSigningMiddleware registers the SigV4a signing middleware to the stack. If a signing middleware is already
+// present, this provided middleware will be swapped. Otherwise the middleware will be added at the tail of the
+// finalize step.
+func RegisterSigningMiddleware(stack *middleware.Stack, signingMiddleware *SignHTTPRequestMiddleware) (err error) {
+ const signedID = "Signing"
+ _, present := stack.Finalize.Get(signedID)
+ if present {
+ _, err = stack.Finalize.Swap(signedID, signingMiddleware)
+ } else {
+ err = stack.Finalize.Add(signingMiddleware, middleware.After)
+ }
+ return err
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/presign_middleware.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/presign_middleware.go
new file mode 100644
index 00000000000..951fc415d52
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/presign_middleware.go
@@ -0,0 +1,117 @@
+package v4a
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "time"
+
+ awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
+ v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
+ "github.com/aws/aws-sdk-go-v2/internal/sdk"
+ "github.com/aws/smithy-go/middleware"
+ smithyHTTP "github.com/aws/smithy-go/transport/http"
+)
+
+// HTTPPresigner is an interface to a SigV4a signer that can sign create a
+// presigned URL for a HTTP requests.
+type HTTPPresigner interface {
+ PresignHTTP(
+ ctx context.Context, credentials Credentials, r *http.Request,
+ payloadHash string, service string, regionSet []string, signingTime time.Time,
+ optFns ...func(*SignerOptions),
+ ) (url string, signedHeader http.Header, err error)
+}
+
+// PresignHTTPRequestMiddlewareOptions is the options for the PresignHTTPRequestMiddleware middleware.
+type PresignHTTPRequestMiddlewareOptions struct {
+ CredentialsProvider CredentialsProvider
+ Presigner HTTPPresigner
+ LogSigning bool
+}
+
+// PresignHTTPRequestMiddleware provides the Finalize middleware for creating a
+// presigned URL for an HTTP request.
+//
+// Will short circuit the middleware stack and not forward onto the next
+// Finalize handler.
+type PresignHTTPRequestMiddleware struct {
+ credentialsProvider CredentialsProvider
+ presigner HTTPPresigner
+ logSigning bool
+}
+
+// NewPresignHTTPRequestMiddleware returns a new PresignHTTPRequestMiddleware
+// initialized with the presigner.
+func NewPresignHTTPRequestMiddleware(options PresignHTTPRequestMiddlewareOptions) *PresignHTTPRequestMiddleware {
+ return &PresignHTTPRequestMiddleware{
+ credentialsProvider: options.CredentialsProvider,
+ presigner: options.Presigner,
+ logSigning: options.LogSigning,
+ }
+}
+
+// ID provides the middleware ID.
+func (*PresignHTTPRequestMiddleware) ID() string { return "PresignHTTPRequest" }
+
+// HandleFinalize will take the provided input and create a presigned url for
+// the http request using the SigV4 presign authentication scheme.
+func (s *PresignHTTPRequestMiddleware) HandleFinalize(
+ ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
+) (
+ out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
+) {
+ req, ok := in.Request.(*smithyHTTP.Request)
+ if !ok {
+ return out, metadata, &SigningError{
+ Err: fmt.Errorf("unexpected request middleware type %T", in.Request),
+ }
+ }
+
+ httpReq := req.Build(ctx)
+ if !hasCredentialProvider(s.credentialsProvider) {
+ out.Result = &v4.PresignedHTTPRequest{
+ URL: httpReq.URL.String(),
+ Method: httpReq.Method,
+ SignedHeader: http.Header{},
+ }
+
+ return out, metadata, nil
+ }
+
+ signingName := awsmiddleware.GetSigningName(ctx)
+ signingRegion := awsmiddleware.GetSigningRegion(ctx)
+ payloadHash := v4.GetPayloadHash(ctx)
+ if len(payloadHash) == 0 {
+ return out, metadata, &SigningError{
+ Err: fmt.Errorf("computed payload hash missing from context"),
+ }
+ }
+
+ credentials, err := s.credentialsProvider.RetrievePrivateKey(ctx)
+ if err != nil {
+ return out, metadata, &SigningError{
+ Err: fmt.Errorf("failed to retrieve credentials: %w", err),
+ }
+ }
+
+ u, h, err := s.presigner.PresignHTTP(ctx, credentials,
+ httpReq, payloadHash, signingName, []string{signingRegion}, sdk.NowTime(),
+ func(o *SignerOptions) {
+ o.Logger = middleware.GetLogger(ctx)
+ o.LogSigning = s.logSigning
+ })
+ if err != nil {
+ return out, metadata, &SigningError{
+ Err: fmt.Errorf("failed to sign http request, %w", err),
+ }
+ }
+
+ out.Result = &v4.PresignedHTTPRequest{
+ URL: u,
+ Method: httpReq.Method,
+ SignedHeader: h,
+ }
+
+ return out, metadata, nil
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/smithy.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/smithy.go
new file mode 100644
index 00000000000..c3b689bace2
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/smithy.go
@@ -0,0 +1,92 @@
+package v4a
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ internalcontext "github.com/aws/aws-sdk-go-v2/internal/context"
+
+ v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
+ "github.com/aws/aws-sdk-go-v2/internal/sdk"
+ "github.com/aws/smithy-go"
+ "github.com/aws/smithy-go/auth"
+ "github.com/aws/smithy-go/logging"
+ smithyhttp "github.com/aws/smithy-go/transport/http"
+)
+
+// CredentialsAdapter adapts v4a.Credentials to smithy auth.Identity.
+type CredentialsAdapter struct {
+ Credentials Credentials
+}
+
+var _ auth.Identity = (*CredentialsAdapter)(nil)
+
+// Expiration returns the time of expiration for the credentials.
+func (v *CredentialsAdapter) Expiration() time.Time {
+ return v.Credentials.Expires
+}
+
+// CredentialsProviderAdapter adapts v4a.CredentialsProvider to
+// auth.IdentityResolver.
+type CredentialsProviderAdapter struct {
+ Provider CredentialsProvider
+}
+
+var _ (auth.IdentityResolver) = (*CredentialsProviderAdapter)(nil)
+
+// GetIdentity retrieves v4a credentials using the underlying provider.
+func (v *CredentialsProviderAdapter) GetIdentity(ctx context.Context, _ smithy.Properties) (
+ auth.Identity, error,
+) {
+ creds, err := v.Provider.RetrievePrivateKey(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("get credentials: %w", err)
+ }
+
+ return &CredentialsAdapter{Credentials: creds}, nil
+}
+
+// SignerAdapter adapts v4a.HTTPSigner to smithy http.Signer.
+type SignerAdapter struct {
+ Signer HTTPSigner
+ Logger logging.Logger
+ LogSigning bool
+}
+
+var _ (smithyhttp.Signer) = (*SignerAdapter)(nil)
+
+// SignRequest signs the request with the provided identity.
+func (v *SignerAdapter) SignRequest(ctx context.Context, r *smithyhttp.Request, identity auth.Identity, props smithy.Properties) error {
+ ca, ok := identity.(*CredentialsAdapter)
+ if !ok {
+ return fmt.Errorf("unexpected identity type: %T", identity)
+ }
+
+ name, ok := smithyhttp.GetSigV4ASigningName(&props)
+ if !ok {
+ return fmt.Errorf("sigv4a signing name is required")
+ }
+
+ regions, ok := smithyhttp.GetSigV4ASigningRegions(&props)
+ if !ok {
+ return fmt.Errorf("sigv4a signing region is required")
+ }
+
+ hash := v4.GetPayloadHash(ctx)
+ signingTime := sdk.NowTime()
+ if skew := internalcontext.GetAttemptSkewContext(ctx); skew != 0 {
+ signingTime.Add(skew)
+ }
+ err := v.Signer.SignHTTP(ctx, ca.Credentials, r.Request, hash, name, regions, signingTime, func(o *SignerOptions) {
+ o.DisableURIPathEscaping, _ = smithyhttp.GetDisableDoubleEncoding(&props)
+
+ o.Logger = v.Logger
+ o.LogSigning = v.LogSigning
+ })
+ if err != nil {
+ return fmt.Errorf("sign http: %w", err)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/v4a.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/v4a.go
new file mode 100644
index 00000000000..f226bcdced3
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/v4a.go
@@ -0,0 +1,520 @@
+package v4a
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+ "hash"
+ "math/big"
+ "net/http"
+ "net/textproto"
+ "net/url"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+
+ signerCrypto "github.com/aws/aws-sdk-go-v2/internal/v4a/internal/crypto"
+ v4Internal "github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4"
+ "github.com/aws/smithy-go/encoding/httpbinding"
+ "github.com/aws/smithy-go/logging"
+)
+
+const (
+ // AmzRegionSetKey represents the region set header used for sigv4a
+ AmzRegionSetKey = "X-Amz-Region-Set"
+ amzAlgorithmKey = v4Internal.AmzAlgorithmKey
+ amzSecurityTokenKey = v4Internal.AmzSecurityTokenKey
+ amzDateKey = v4Internal.AmzDateKey
+ amzCredentialKey = v4Internal.AmzCredentialKey
+ amzSignedHeadersKey = v4Internal.AmzSignedHeadersKey
+ authorizationHeader = "Authorization"
+
+ signingAlgorithm = "AWS4-ECDSA-P256-SHA256"
+
+ timeFormat = "20060102T150405Z"
+ shortTimeFormat = "20060102"
+
+ // EmptyStringSHA256 is a hex encoded SHA-256 hash of an empty string
+ EmptyStringSHA256 = v4Internal.EmptyStringSHA256
+
+ // Version of signing v4a
+ Version = "SigV4A"
+)
+
+var (
+ p256 elliptic.Curve
+ nMinusTwoP256 *big.Int
+
+ one = new(big.Int).SetInt64(1)
+)
+
+func init() {
+ // Ensure the elliptic curve parameters are initialized on package import rather then on first usage
+ p256 = elliptic.P256()
+
+ nMinusTwoP256 = new(big.Int).SetBytes(p256.Params().N.Bytes())
+ nMinusTwoP256 = nMinusTwoP256.Sub(nMinusTwoP256, new(big.Int).SetInt64(2))
+}
+
+// SignerOptions is the SigV4a signing options for constructing a Signer.
+type SignerOptions struct {
+ Logger logging.Logger
+ LogSigning bool
+
+ // Disables the Signer's moving HTTP header key/value pairs from the HTTP
+ // request header to the request's query string. This is most commonly used
+ // with pre-signed requests preventing headers from being added to the
+ // request's query string.
+ DisableHeaderHoisting bool
+
+ // Disables the automatic escaping of the URI path of the request for the
+ // siganture's canonical string's path. For services that do not need additional
+ // escaping then use this to disable the signer escaping the path.
+ //
+ // S3 is an example of a service that does not need additional escaping.
+ //
+ // http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
+ DisableURIPathEscaping bool
+}
+
+// Signer is a SigV4a HTTP signing implementation
+type Signer struct {
+ options SignerOptions
+}
+
+// NewSigner constructs a SigV4a Signer.
+func NewSigner(optFns ...func(*SignerOptions)) *Signer {
+ options := SignerOptions{}
+
+ for _, fn := range optFns {
+ fn(&options)
+ }
+
+ return &Signer{options: options}
+}
+
+// deriveKeyFromAccessKeyPair derives a NIST P-256 PrivateKey from the given
+// IAM AccessKey and SecretKey pair.
+//
+// Based on FIPS.186-4 Appendix B.4.2
+func deriveKeyFromAccessKeyPair(accessKey, secretKey string) (*ecdsa.PrivateKey, error) {
+ params := p256.Params()
+ bitLen := params.BitSize // Testing random candidates does not require an additional 64 bits
+ counter := 0x01
+
+ buffer := make([]byte, 1+len(accessKey)) // 1 byte counter + len(accessKey)
+ kdfContext := bytes.NewBuffer(buffer)
+
+ inputKey := append([]byte("AWS4A"), []byte(secretKey)...)
+
+ d := new(big.Int)
+ for {
+ kdfContext.Reset()
+ kdfContext.WriteString(accessKey)
+ kdfContext.WriteByte(byte(counter))
+
+ key, err := signerCrypto.HMACKeyDerivation(sha256.New, bitLen, inputKey, []byte(signingAlgorithm), kdfContext.Bytes())
+ if err != nil {
+ return nil, err
+ }
+
+ // Check key first before calling SetBytes if key key is in fact a valid candidate.
+ // This ensures the byte slice is the correct length (32-bytes) to compare in constant-time
+ cmp, err := signerCrypto.ConstantTimeByteCompare(key, nMinusTwoP256.Bytes())
+ if err != nil {
+ return nil, err
+ }
+ if cmp == -1 {
+ d.SetBytes(key)
+ break
+ }
+
+ counter++
+ if counter > 0xFF {
+ return nil, fmt.Errorf("exhausted single byte external counter")
+ }
+ }
+ d = d.Add(d, one)
+
+ priv := new(ecdsa.PrivateKey)
+ priv.PublicKey.Curve = p256
+ priv.D = d
+ priv.PublicKey.X, priv.PublicKey.Y = p256.ScalarBaseMult(d.Bytes())
+
+ return priv, nil
+}
+
+type httpSigner struct {
+ Request *http.Request
+ ServiceName string
+ RegionSet []string
+ Time time.Time
+ Credentials Credentials
+ IsPreSign bool
+
+ Logger logging.Logger
+ Debug bool
+
+ // PayloadHash is the hex encoded SHA-256 hash of the request payload
+ // If len(PayloadHash) == 0 the signer will attempt to send the request
+ // as an unsigned payload. Note: Unsigned payloads only work for a subset of services.
+ PayloadHash string
+
+ DisableHeaderHoisting bool
+ DisableURIPathEscaping bool
+}
+
+// SignHTTP takes the provided http.Request, payload hash, service, regionSet, and time and signs using SigV4a.
+// The passed in request will be modified in place.
+func (s *Signer) SignHTTP(ctx context.Context, credentials Credentials, r *http.Request, payloadHash string, service string, regionSet []string, signingTime time.Time, optFns ...func(*SignerOptions)) error {
+ options := s.options
+ for _, fn := range optFns {
+ fn(&options)
+ }
+
+ signer := &httpSigner{
+ Request: r,
+ PayloadHash: payloadHash,
+ ServiceName: service,
+ RegionSet: regionSet,
+ Credentials: credentials,
+ Time: signingTime.UTC(),
+ DisableHeaderHoisting: options.DisableHeaderHoisting,
+ DisableURIPathEscaping: options.DisableURIPathEscaping,
+ }
+
+ signedRequest, err := signer.Build()
+ if err != nil {
+ return err
+ }
+
+ logHTTPSigningInfo(ctx, options, signedRequest)
+
+ return nil
+}
+
+// PresignHTTP takes the provided http.Request, payload hash, service, regionSet, and time and presigns using SigV4a
+// Returns the presigned URL along with the headers that were signed with the request.
+//
+// PresignHTTP will not set the expires time of the presigned request
+// automatically. To specify the expire duration for a request add the
+// "X-Amz-Expires" query parameter on the request with the value as the
+// duration in seconds the presigned URL should be considered valid for. This
+// parameter is not used by all AWS services, and is most notable used by
+// Amazon S3 APIs.
+func (s *Signer) PresignHTTP(ctx context.Context, credentials Credentials, r *http.Request, payloadHash string, service string, regionSet []string, signingTime time.Time, optFns ...func(*SignerOptions)) (signedURI string, signedHeaders http.Header, err error) {
+ options := s.options
+ for _, fn := range optFns {
+ fn(&options)
+ }
+
+ signer := &httpSigner{
+ Request: r,
+ PayloadHash: payloadHash,
+ ServiceName: service,
+ RegionSet: regionSet,
+ Credentials: credentials,
+ Time: signingTime.UTC(),
+ IsPreSign: true,
+ DisableHeaderHoisting: options.DisableHeaderHoisting,
+ DisableURIPathEscaping: options.DisableURIPathEscaping,
+ }
+
+ signedRequest, err := signer.Build()
+ if err != nil {
+ return "", nil, err
+ }
+
+ logHTTPSigningInfo(ctx, options, signedRequest)
+
+ signedHeaders = make(http.Header)
+
+ // For the signed headers we canonicalize the header keys in the returned map.
+ // This avoids situations where can standard library double headers like host header. For example the standard
+ // library will set the Host header, even if it is present in lower-case form.
+ for k, v := range signedRequest.SignedHeaders {
+ key := textproto.CanonicalMIMEHeaderKey(k)
+ signedHeaders[key] = append(signedHeaders[key], v...)
+ }
+
+ return signedRequest.Request.URL.String(), signedHeaders, nil
+}
+
+func (s *httpSigner) setRequiredSigningFields(headers http.Header, query url.Values) {
+ amzDate := s.Time.Format(timeFormat)
+
+ if s.IsPreSign {
+ query.Set(AmzRegionSetKey, strings.Join(s.RegionSet, ","))
+ query.Set(amzDateKey, amzDate)
+ query.Set(amzAlgorithmKey, signingAlgorithm)
+ if len(s.Credentials.SessionToken) > 0 {
+ query.Set(amzSecurityTokenKey, s.Credentials.SessionToken)
+ }
+ return
+ }
+
+ headers.Set(AmzRegionSetKey, strings.Join(s.RegionSet, ","))
+ headers.Set(amzDateKey, amzDate)
+ if len(s.Credentials.SessionToken) > 0 {
+ headers.Set(amzSecurityTokenKey, s.Credentials.SessionToken)
+ }
+}
+
+func (s *httpSigner) Build() (signedRequest, error) {
+ req := s.Request
+
+ query := req.URL.Query()
+ headers := req.Header
+
+ s.setRequiredSigningFields(headers, query)
+
+ // Sort Each Query Key's Values
+ for key := range query {
+ sort.Strings(query[key])
+ }
+
+ v4Internal.SanitizeHostForHeader(req)
+
+ credentialScope := s.buildCredentialScope()
+ credentialStr := s.Credentials.Context + "/" + credentialScope
+ if s.IsPreSign {
+ query.Set(amzCredentialKey, credentialStr)
+ }
+
+ unsignedHeaders := headers
+ if s.IsPreSign && !s.DisableHeaderHoisting {
+ urlValues := url.Values{}
+ urlValues, unsignedHeaders = buildQuery(v4Internal.AllowedQueryHoisting, unsignedHeaders)
+ for k := range urlValues {
+ query[k] = urlValues[k]
+ }
+ }
+
+ host := req.URL.Host
+ if len(req.Host) > 0 {
+ host = req.Host
+ }
+
+ signedHeaders, signedHeadersStr, canonicalHeaderStr := s.buildCanonicalHeaders(host, v4Internal.IgnoredHeaders, unsignedHeaders, s.Request.ContentLength)
+
+ if s.IsPreSign {
+ query.Set(amzSignedHeadersKey, signedHeadersStr)
+ }
+
+ rawQuery := strings.Replace(query.Encode(), "+", "%20", -1)
+
+ canonicalURI := v4Internal.GetURIPath(req.URL)
+ if !s.DisableURIPathEscaping {
+ canonicalURI = httpbinding.EscapePath(canonicalURI, false)
+ }
+
+ canonicalString := s.buildCanonicalString(
+ req.Method,
+ canonicalURI,
+ rawQuery,
+ signedHeadersStr,
+ canonicalHeaderStr,
+ )
+
+ strToSign := s.buildStringToSign(credentialScope, canonicalString)
+ signingSignature, err := s.buildSignature(strToSign)
+ if err != nil {
+ return signedRequest{}, err
+ }
+
+ if s.IsPreSign {
+ rawQuery += "&X-Amz-Signature=" + signingSignature
+ } else {
+ headers[authorizationHeader] = append(headers[authorizationHeader][:0], buildAuthorizationHeader(credentialStr, signedHeadersStr, signingSignature))
+ }
+
+ req.URL.RawQuery = rawQuery
+
+ return signedRequest{
+ Request: req,
+ SignedHeaders: signedHeaders,
+ CanonicalString: canonicalString,
+ StringToSign: strToSign,
+ PreSigned: s.IsPreSign,
+ }, nil
+}
+
+func buildAuthorizationHeader(credentialStr, signedHeadersStr, signingSignature string) string {
+ const credential = "Credential="
+ const signedHeaders = "SignedHeaders="
+ const signature = "Signature="
+ const commaSpace = ", "
+
+ var parts strings.Builder
+ parts.Grow(len(signingAlgorithm) + 1 +
+ len(credential) + len(credentialStr) + len(commaSpace) +
+ len(signedHeaders) + len(signedHeadersStr) + len(commaSpace) +
+ len(signature) + len(signingSignature),
+ )
+ parts.WriteString(signingAlgorithm)
+ parts.WriteRune(' ')
+ parts.WriteString(credential)
+ parts.WriteString(credentialStr)
+ parts.WriteString(commaSpace)
+ parts.WriteString(signedHeaders)
+ parts.WriteString(signedHeadersStr)
+ parts.WriteString(commaSpace)
+ parts.WriteString(signature)
+ parts.WriteString(signingSignature)
+ return parts.String()
+}
+
+func (s *httpSigner) buildCredentialScope() string {
+ return strings.Join([]string{
+ s.Time.Format(shortTimeFormat),
+ s.ServiceName,
+ "aws4_request",
+ }, "/")
+
+}
+
+func buildQuery(r v4Internal.Rule, header http.Header) (url.Values, http.Header) {
+ query := url.Values{}
+ unsignedHeaders := http.Header{}
+ for k, h := range header {
+ if r.IsValid(k) {
+ query[k] = h
+ } else {
+ unsignedHeaders[k] = h
+ }
+ }
+
+ return query, unsignedHeaders
+}
+
+func (s *httpSigner) buildCanonicalHeaders(host string, rule v4Internal.Rule, header http.Header, length int64) (signed http.Header, signedHeaders, canonicalHeadersStr string) {
+ signed = make(http.Header)
+
+ var headers []string
+ const hostHeader = "host"
+ headers = append(headers, hostHeader)
+ signed[hostHeader] = append(signed[hostHeader], host)
+
+ if length > 0 {
+ const contentLengthHeader = "content-length"
+ headers = append(headers, contentLengthHeader)
+ signed[contentLengthHeader] = append(signed[contentLengthHeader], strconv.FormatInt(length, 10))
+ }
+
+ for k, v := range header {
+ if !rule.IsValid(k) {
+ continue // ignored header
+ }
+
+ lowerCaseKey := strings.ToLower(k)
+ if _, ok := signed[lowerCaseKey]; ok {
+ // include additional values
+ signed[lowerCaseKey] = append(signed[lowerCaseKey], v...)
+ continue
+ }
+
+ headers = append(headers, lowerCaseKey)
+ signed[lowerCaseKey] = v
+ }
+ sort.Strings(headers)
+
+ signedHeaders = strings.Join(headers, ";")
+
+ var canonicalHeaders strings.Builder
+ n := len(headers)
+ const colon = ':'
+ for i := range n {
+ if headers[i] == hostHeader {
+ canonicalHeaders.WriteString(hostHeader)
+ canonicalHeaders.WriteRune(colon)
+ canonicalHeaders.WriteString(v4Internal.StripExcessSpaces(host))
+ } else {
+ canonicalHeaders.WriteString(headers[i])
+ canonicalHeaders.WriteRune(colon)
+ // Trim out leading, trailing, and dedup inner spaces from signed header values.
+ values := signed[headers[i]]
+ for j, v := range values {
+ cleanedValue := strings.TrimSpace(v4Internal.StripExcessSpaces(v))
+ canonicalHeaders.WriteString(cleanedValue)
+ if j < len(values)-1 {
+ canonicalHeaders.WriteRune(',')
+ }
+ }
+ }
+ canonicalHeaders.WriteRune('\n')
+ }
+ canonicalHeadersStr = canonicalHeaders.String()
+
+ return signed, signedHeaders, canonicalHeadersStr
+}
+
+func (s *httpSigner) buildCanonicalString(method, uri, query, signedHeaders, canonicalHeaders string) string {
+ return strings.Join([]string{
+ method,
+ uri,
+ query,
+ canonicalHeaders,
+ signedHeaders,
+ s.PayloadHash,
+ }, "\n")
+}
+
+func (s *httpSigner) buildStringToSign(credentialScope, canonicalRequestString string) string {
+ return strings.Join([]string{
+ signingAlgorithm,
+ s.Time.Format(timeFormat),
+ credentialScope,
+ hex.EncodeToString(makeHash(sha256.New(), []byte(canonicalRequestString))),
+ }, "\n")
+}
+
+func makeHash(hash hash.Hash, b []byte) []byte {
+ hash.Reset()
+ hash.Write(b)
+ return hash.Sum(nil)
+}
+
+func (s *httpSigner) buildSignature(strToSign string) (string, error) {
+ sig, err := s.Credentials.PrivateKey.Sign(rand.Reader, makeHash(sha256.New(), []byte(strToSign)), crypto.SHA256)
+ if err != nil {
+ return "", err
+ }
+ return hex.EncodeToString(sig), nil
+}
+
+const logSignInfoMsg = `Request Signature:
+---[ CANONICAL STRING ]-----------------------------
+%s
+---[ STRING TO SIGN ]--------------------------------
+%s%s
+-----------------------------------------------------`
+const logSignedURLMsg = `
+---[ SIGNED URL ]------------------------------------
+%s`
+
+func logHTTPSigningInfo(ctx context.Context, options SignerOptions, r signedRequest) {
+ if !options.LogSigning {
+ return
+ }
+ signedURLMsg := ""
+ if r.PreSigned {
+ signedURLMsg = fmt.Sprintf(logSignedURLMsg, r.Request.URL.String())
+ }
+ logger := logging.WithContext(ctx, options.Logger)
+ logger.Logf(logging.Debug, logSignInfoMsg, r.CanonicalString, r.StringToSign, signedURLMsg)
+}
+
+type signedRequest struct {
+ Request *http.Request
+ SignedHeaders http.Header
+ CanonicalString string
+ StringToSign string
+ PreSigned bool
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md
index 497d3723041..cf6c5e09116 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md
@@ -1,3 +1,11 @@
+# v1.13.9 (2026-04-29)
+
+* **Dependency Update**: Update to smithy-go v1.25.1.
+
+# v1.13.8 (2026-04-17)
+
+* **Dependency Update**: Bump smithy-go to 1.25.0 to support endpointBdd trait
+
# v1.13.7 (2026-03-13)
* **Bug Fix**: Replace usages of the old ioutil/ package throughout the SDK.
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go
index 5679a2b2b17..e145070706f 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go
@@ -3,4 +3,4 @@
package acceptencoding
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.13.7"
+const goModuleVersion = "1.13.9"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md
index 7c5e13816e8..96adad52610 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md
@@ -1,3 +1,13 @@
+# v1.13.23 (2026-04-29)
+
+* **Dependency Update**: Update to smithy-go v1.25.1.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.13.22 (2026-04-17)
+
+* **Dependency Update**: Bump smithy-go to 1.25.0 to support endpointBdd trait
+* **Dependency Update**: Updated to the latest SDK module versions
+
# v1.13.21 (2026-03-26)
* **Dependency Update**: Updated to the latest SDK module versions
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go
index 456855e8852..5737e9c0c1b 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go
@@ -3,4 +3,4 @@
package presignedurl
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.13.21"
+const goModuleVersion = "1.13.23"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/CHANGELOG.md
index d93bf5e7cc4..253e0359678 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/CHANGELOG.md
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/CHANGELOG.md
@@ -1,3 +1,13 @@
+# v1.0.11 (2026-04-29)
+
+* **Dependency Update**: Update to smithy-go v1.25.1.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.0.10 (2026-04-17)
+
+* **Dependency Update**: Bump smithy-go to 1.25.0 to support endpointBdd trait
+* **Dependency Update**: Updated to the latest SDK module versions
+
# v1.0.9 (2026-03-26)
* **Bug Fix**: Fix a bug where a recorded clock skew could persist on the client even if the client and server clock ended up realigning.
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/go_module_metadata.go
index c922e7adfbe..eba7ad77743 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/go_module_metadata.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/go_module_metadata.go
@@ -3,4 +3,4 @@
package signin
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.0.9"
+const goModuleVersion = "1.0.11"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md
index 697dce1a2e6..26c80a2c233 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md
@@ -1,3 +1,17 @@
+# v1.30.17 (2026-04-29)
+
+* **Dependency Update**: Update to smithy-go v1.25.1.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.30.16 (2026-04-17)
+
+* **Dependency Update**: Bump smithy-go to 1.25.0 to support endpointBdd trait
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.30.15 (2026-04-02)
+
+* No change notes available for this release.
+
# v1.30.14 (2026-03-26)
* **Bug Fix**: Fix a bug where a recorded clock skew could persist on the client even if the client and server clock ended up realigning.
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go
index 9674e4957b1..9d12dd55bc3 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go
@@ -3,4 +3,4 @@
package sso
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.30.14"
+const goModuleVersion = "1.30.17"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go
index 9f550c3f1bb..871275a6bfc 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go
@@ -482,6 +482,11 @@ var defaultPartitions = endpoints.Partitions{
},
RegionRegex: partitionRegexp.AwsEusc,
IsRegionalized: true,
+ Endpoints: endpoints.Endpoints{
+ endpoints.EndpointKey{
+ Region: "eusc-de-east-1",
+ }: endpoints.Endpoint{},
+ },
},
{
ID: "aws-iso",
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md
index 2bb4cd8fbb7..33082c0e541 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md
@@ -1,3 +1,21 @@
+# v1.36.0 (2026-05-22)
+
+* **Feature**: Adding new BDD representation of endpoint ruleset
+
+# v1.35.21 (2026-04-29)
+
+* **Dependency Update**: Update to smithy-go v1.25.1.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.35.20 (2026-04-17)
+
+* **Dependency Update**: Bump smithy-go to 1.25.0 to support endpointBdd trait
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.35.19 (2026-04-02)
+
+* No change notes available for this release.
+
# v1.35.18 (2026-03-26)
* **Bug Fix**: Fix a bug where a recorded clock skew could persist on the client even if the client and server clock ended up realigning.
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go
index 884983eb4d0..0834533561e 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go
@@ -14,6 +14,7 @@ import (
internalendpoints "github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints"
smithyauth "github.com/aws/smithy-go/auth"
smithyendpoints "github.com/aws/smithy-go/endpoints"
+ "github.com/aws/smithy-go/endpoints/private/bdd"
"github.com/aws/smithy-go/endpoints/private/rulesfn"
"github.com/aws/smithy-go/middleware"
"github.com/aws/smithy-go/ptr"
@@ -294,21 +295,157 @@ func (p EndpointParameters) WithDefaults() EndpointParameters {
return p
}
-type stringSlice []string
+const bddRoot int32 = 2
-func (s stringSlice) Get(i int) *string {
- if i < 0 || i >= len(s) {
- return nil
- }
+var bddNodes = [42]int32{
+ -1, 1, -1, 0, 13, 3, 1, 4, 100000012, 2, 5, 100000012, 3, 8, 6, 4, 7, 100000011, 5, 100000009, 100000010, 4, 11, 9, 6, 10, 100000008, 7, 100000006, 100000007, 5, 12, 100000005, 6, 100000004, 100000005, 3, 100000001, 14, 4, 100000002, 100000003}
+
+type conditionContext struct {
+ PartitionResult *awsrulesfn.PartitionConfig
+}
- v := s[i]
- return &v
+func evalCondition(idx int, params *EndpointParameters, c *conditionContext) bool {
+ switch idx {
+ case 0:
+ return params.Endpoint != nil
+ case 1:
+ return params.Region != nil
+ case 2:
+ if v := awsrulesfn.GetPartition(*params.Region); v != nil {
+ c.PartitionResult = v
+ return true
+ }
+ return false
+ case 3:
+ return *params.UseFIPS == true
+ case 4:
+ return *params.UseDualStack == true
+ case 5:
+ return c.PartitionResult.SupportsDualStack == true
+ case 6:
+ return c.PartitionResult.SupportsFIPS == true
+ case 7:
+ return c.PartitionResult.Name == "aws-us-gov"
+ }
+ return false
+}
+
+func resolveResult(idx int32, params *EndpointParameters, c *conditionContext) (smithyendpoints.Endpoint, error) {
+ switch idx {
+ case 0:
+ return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint resolution failed: no matching rule")
+ case 1:
+ return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: FIPS and custom endpoint are not supported")
+ case 2:
+ return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Dualstack and custom endpoint are not supported")
+ case 3:
+ uriString := *params.Endpoint
+ uri, err := url.Parse(uriString)
+ if err != nil {
+ return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
+ }
+ return smithyendpoints.Endpoint{
+ URI: *uri,
+ Headers: http.Header{},
+ }, nil
+ case 4:
+ uriString := func() string {
+ var out strings.Builder
+ out.WriteString("https://oidc-fips.")
+ out.WriteString(*params.Region)
+ out.WriteString(".")
+ out.WriteString(c.PartitionResult.DualStackDnsSuffix)
+ return out.String()
+ }()
+ uri, err := url.Parse(uriString)
+ if err != nil {
+ return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
+ }
+ return smithyendpoints.Endpoint{
+ URI: *uri,
+ Headers: http.Header{},
+ }, nil
+ case 5:
+ return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "FIPS and DualStack are enabled, but this partition does not support one or both")
+ case 6:
+ uriString := func() string {
+ var out strings.Builder
+ out.WriteString("https://oidc.")
+ out.WriteString(*params.Region)
+ out.WriteString(".amazonaws.com")
+ return out.String()
+ }()
+ uri, err := url.Parse(uriString)
+ if err != nil {
+ return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
+ }
+ return smithyendpoints.Endpoint{
+ URI: *uri,
+ Headers: http.Header{},
+ }, nil
+ case 7:
+ uriString := func() string {
+ var out strings.Builder
+ out.WriteString("https://oidc-fips.")
+ out.WriteString(*params.Region)
+ out.WriteString(".")
+ out.WriteString(c.PartitionResult.DnsSuffix)
+ return out.String()
+ }()
+ uri, err := url.Parse(uriString)
+ if err != nil {
+ return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
+ }
+ return smithyendpoints.Endpoint{
+ URI: *uri,
+ Headers: http.Header{},
+ }, nil
+ case 8:
+ return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "FIPS is enabled but this partition does not support FIPS")
+ case 9:
+ uriString := func() string {
+ var out strings.Builder
+ out.WriteString("https://oidc.")
+ out.WriteString(*params.Region)
+ out.WriteString(".")
+ out.WriteString(c.PartitionResult.DualStackDnsSuffix)
+ return out.String()
+ }()
+ uri, err := url.Parse(uriString)
+ if err != nil {
+ return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
+ }
+ return smithyendpoints.Endpoint{
+ URI: *uri,
+ Headers: http.Header{},
+ }, nil
+ case 10:
+ return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "DualStack is enabled but this partition does not support DualStack")
+ case 11:
+ uriString := func() string {
+ var out strings.Builder
+ out.WriteString("https://oidc.")
+ out.WriteString(*params.Region)
+ out.WriteString(".")
+ out.WriteString(c.PartitionResult.DnsSuffix)
+ return out.String()
+ }()
+ uri, err := url.Parse(uriString)
+ if err != nil {
+ return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
+ }
+ return smithyendpoints.Endpoint{
+ URI: *uri,
+ Headers: http.Header{},
+ }, nil
+ case 12:
+ return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Missing Region")
+ }
+ return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, invalid result index: %d", idx)
}
// EndpointResolverV2 provides the interface for resolving service endpoints.
type EndpointResolverV2 interface {
- // ResolveEndpoint attempts to resolve the endpoint with the provided options,
- // returning the endpoint if found. Otherwise an error is returned.
ResolveEndpoint(ctx context.Context, params EndpointParameters) (
smithyendpoints.Endpoint, error,
)
@@ -332,152 +469,12 @@ func (r *resolver) ResolveEndpoint(
if err = params.ValidateRequired(); err != nil {
return endpoint, fmt.Errorf("endpoint parameters are not valid, %w", err)
}
- _UseDualStack := *params.UseDualStack
- _ = _UseDualStack
- _UseFIPS := *params.UseFIPS
- _ = _UseFIPS
-
- if exprVal := params.Endpoint; exprVal != nil {
- _Endpoint := *exprVal
- _ = _Endpoint
- if _UseFIPS == true {
- return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: FIPS and custom endpoint are not supported")
- }
- if _UseDualStack == true {
- return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Dualstack and custom endpoint are not supported")
- }
- uriString := _Endpoint
-
- uri, err := url.Parse(uriString)
- if err != nil {
- return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
- }
-
- return smithyendpoints.Endpoint{
- URI: *uri,
- Headers: http.Header{},
- }, nil
- }
- if exprVal := params.Region; exprVal != nil {
- _Region := *exprVal
- _ = _Region
- if exprVal := awsrulesfn.GetPartition(_Region); exprVal != nil {
- _PartitionResult := *exprVal
- _ = _PartitionResult
- if _UseFIPS == true {
- if _UseDualStack == true {
- if true == _PartitionResult.SupportsFIPS {
- if true == _PartitionResult.SupportsDualStack {
- uriString := func() string {
- var out strings.Builder
- out.WriteString("https://oidc-fips.")
- out.WriteString(_Region)
- out.WriteString(".")
- out.WriteString(_PartitionResult.DualStackDnsSuffix)
- return out.String()
- }()
-
- uri, err := url.Parse(uriString)
- if err != nil {
- return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
- }
-
- return smithyendpoints.Endpoint{
- URI: *uri,
- Headers: http.Header{},
- }, nil
- }
- }
- return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS and DualStack are enabled, but this partition does not support one or both")
- }
- }
- if _UseFIPS == true {
- if _PartitionResult.SupportsFIPS == true {
- if _PartitionResult.Name == "aws-us-gov" {
- uriString := func() string {
- var out strings.Builder
- out.WriteString("https://oidc.")
- out.WriteString(_Region)
- out.WriteString(".amazonaws.com")
- return out.String()
- }()
-
- uri, err := url.Parse(uriString)
- if err != nil {
- return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
- }
-
- return smithyendpoints.Endpoint{
- URI: *uri,
- Headers: http.Header{},
- }, nil
- }
- uriString := func() string {
- var out strings.Builder
- out.WriteString("https://oidc-fips.")
- out.WriteString(_Region)
- out.WriteString(".")
- out.WriteString(_PartitionResult.DnsSuffix)
- return out.String()
- }()
-
- uri, err := url.Parse(uriString)
- if err != nil {
- return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
- }
-
- return smithyendpoints.Endpoint{
- URI: *uri,
- Headers: http.Header{},
- }, nil
- }
- return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS is enabled but this partition does not support FIPS")
- }
- if _UseDualStack == true {
- if true == _PartitionResult.SupportsDualStack {
- uriString := func() string {
- var out strings.Builder
- out.WriteString("https://oidc.")
- out.WriteString(_Region)
- out.WriteString(".")
- out.WriteString(_PartitionResult.DualStackDnsSuffix)
- return out.String()
- }()
-
- uri, err := url.Parse(uriString)
- if err != nil {
- return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
- }
-
- return smithyendpoints.Endpoint{
- URI: *uri,
- Headers: http.Header{},
- }, nil
- }
- return endpoint, fmt.Errorf("endpoint rule error, %s", "DualStack is enabled but this partition does not support DualStack")
- }
- uriString := func() string {
- var out strings.Builder
- out.WriteString("https://oidc.")
- out.WriteString(_Region)
- out.WriteString(".")
- out.WriteString(_PartitionResult.DnsSuffix)
- return out.String()
- }()
-
- uri, err := url.Parse(uriString)
- if err != nil {
- return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
- }
- return smithyendpoints.Endpoint{
- URI: *uri,
- Headers: http.Header{},
- }, nil
- }
- return endpoint, fmt.Errorf("Endpoint resolution failed. Invalid operation or environment input.")
- }
- return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Missing Region")
+ c := &conditionContext{}
+ ref := bdd.Evaluate(bddNodes[:], bddRoot, func(idx int) bool {
+ return evalCondition(idx, ¶ms, c)
+ })
+ return resolveResult(ref, ¶ms, c)
}
type endpointParamsBinder interface {
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go
index 2ae8e4e3b8d..f94dbeb9b58 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go
@@ -3,4 +3,4 @@
package ssooidc
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.35.18"
+const goModuleVersion = "1.36.0"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go
index b7c58e2f24e..4ab58f60bd6 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go
@@ -482,6 +482,11 @@ var defaultPartitions = endpoints.Partitions{
},
RegionRegex: partitionRegexp.AwsEusc,
IsRegionalized: true,
+ Endpoints: endpoints.Endpoints{
+ endpoints.EndpointKey{
+ Region: "eusc-de-east-1",
+ }: endpoints.Endpoint{},
+ },
},
{
ID: "aws-iso",
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md
index c0090863816..199f7a79ce8 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md
@@ -1,3 +1,14 @@
+# v1.42.1 (2026-04-29)
+
+* **Dependency Update**: Update to smithy-go v1.25.1.
+* **Dependency Update**: Updated to the latest SDK module versions
+
+# v1.42.0 (2026-04-17)
+
+* **Feature**: The STS client now supports configuring SigV4a through the auth scheme preference setting. SigV4a uses asymmetric cryptography, enabling customers using long-term IAM credentials to continue making STS API calls even when a region is isolated from the partition leader.
+* **Dependency Update**: Bump smithy-go to 1.25.0 to support endpointBdd trait
+* **Dependency Update**: Updated to the latest SDK module versions
+
# v1.41.10 (2026-03-26)
* **Bug Fix**: Fix a bug where a recorded clock skew could persist on the client even if the client and server clock ended up realigning.
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_client.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_client.go
index c0c6af3a15f..958c83c1a89 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_client.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_client.go
@@ -16,6 +16,7 @@ import (
internalauth "github.com/aws/aws-sdk-go-v2/internal/auth"
internalauthsmithy "github.com/aws/aws-sdk-go-v2/internal/auth/smithy"
internalConfig "github.com/aws/aws-sdk-go-v2/internal/configsources"
+ "github.com/aws/aws-sdk-go-v2/internal/v4a"
acceptencodingcust "github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding"
presignedurlcust "github.com/aws/aws-sdk-go-v2/service/internal/presigned-url"
smithy "github.com/aws/smithy-go"
@@ -207,6 +208,8 @@ func New(options Options, optFns ...func(*Options)) *Client {
resolveEndpointResolverV2(&options)
+ resolveHTTPSignerV4a(&options)
+
resolveTracerProvider(&options)
resolveMeterProvider(&options)
@@ -381,6 +384,11 @@ func resolveAuthSchemes(options *Options) {
Logger: options.Logger,
LogSigning: options.ClientLogMode.IsSigning(),
}),
+ internalauth.NewHTTPAuthScheme("aws.auth#sigv4a", &v4a.SignerAdapter{
+ Signer: options.httpSignerV4a,
+ Logger: options.Logger,
+ LogSigning: options.ClientLogMode.IsSigning(),
+ }),
}
}
}
@@ -758,6 +766,26 @@ func resolveUseFIPSEndpoint(cfg aws.Config, o *Options) error {
return nil
}
+type httpSignerV4a interface {
+ SignHTTP(ctx context.Context, credentials v4a.Credentials, r *http.Request, payloadHash,
+ service string, regionSet []string, signingTime time.Time,
+ optFns ...func(*v4a.SignerOptions)) error
+}
+
+func resolveHTTPSignerV4a(o *Options) {
+ if o.httpSignerV4a != nil {
+ return
+ }
+ o.httpSignerV4a = newDefaultV4aSigner(*o)
+}
+
+func newDefaultV4aSigner(o Options) *v4a.Signer {
+ return v4a.NewSigner(func(so *v4a.SignerOptions) {
+ so.Logger = o.Logger
+ so.LogSigning = o.ClientLogMode.IsSigning()
+ })
+}
+
func initializeTimeOffsetResolver(c *Client) {
c.timeOffset = new(atomic.Int64)
}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go
index 4db5a51f938..71c5db38b76 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go
@@ -149,6 +149,16 @@ func serviceAuthOptions(params *AuthResolverParameters) []*smithyauth.Option {
return props
}(),
},
+
+ {
+ SchemeID: smithyauth.SchemeIDSigV4A,
+ SignerProperties: func() smithy.Properties {
+ var props smithy.Properties
+ smithyhttp.SetSigV4ASigningName(&props, "sts")
+ smithyhttp.SetSigV4ASigningRegions(&props, []string{params.Region})
+ return props
+ }(),
+ },
}
}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/generated.json b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/generated.json
index b5556cbfbfe..2fc7b400f7c 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/generated.json
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/generated.json
@@ -3,6 +3,7 @@
"github.com/aws/aws-sdk-go-v2": "v1.4.0",
"github.com/aws/aws-sdk-go-v2/internal/configsources": "v0.0.0-00010101000000-000000000000",
"github.com/aws/aws-sdk-go-v2/internal/endpoints/v2": "v2.0.0-00010101000000-000000000000",
+ "github.com/aws/aws-sdk-go-v2/internal/v4a": "v0.0.0-00010101000000-000000000000",
"github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding": "v1.0.5",
"github.com/aws/aws-sdk-go-v2/service/internal/presigned-url": "v1.0.7",
"github.com/aws/smithy-go": "v1.4.0"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go
index 317746f0fd8..bdd6a15d8f0 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go
@@ -3,4 +3,4 @@
package sts
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.41.10"
+const goModuleVersion = "1.42.1"
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/options.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/options.go
index c66e69a8d94..a9f2361fd32 100644
--- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/options.go
+++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/options.go
@@ -4,9 +4,11 @@ package sts
import (
"context"
+ "fmt"
"github.com/aws/aws-sdk-go-v2/aws"
awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
internalauthsmithy "github.com/aws/aws-sdk-go-v2/internal/auth/smithy"
+ "github.com/aws/aws-sdk-go-v2/internal/v4a"
smithyauth "github.com/aws/smithy-go/auth"
"github.com/aws/smithy-go/logging"
"github.com/aws/smithy-go/metrics"
@@ -107,6 +109,9 @@ type Options struct {
// The client tracer provider.
TracerProvider tracing.TracerProvider
+ // Signature Version 4a (SigV4a) Signer
+ httpSignerV4a httpSignerV4a
+
// The initial DefaultsMode used when the client options were constructed. If the
// DefaultsMode was set to aws.DefaultsModeAuto this will store what the resolved
// value was at that point in time.
@@ -146,6 +151,9 @@ func (o Options) GetIdentityResolver(schemeID string) smithyauth.IdentityResolve
if schemeID == "aws.auth#sigv4" {
return getSigV4IdentityResolver(o)
}
+ if schemeID == "aws.auth#sigv4a" {
+ return getSigV4AIdentityResolver(o)
+ }
if schemeID == "smithy.api#noAuth" {
return &smithyauth.AnonymousIdentityResolver{}
}
@@ -231,6 +239,46 @@ func WithSigV4SigningRegion(region string) func(*Options) {
}
}
+func getSigV4AIdentityResolver(o Options) smithyauth.IdentityResolver {
+ if o.Credentials != nil {
+ return &v4a.CredentialsProviderAdapter{
+ Provider: &v4a.SymmetricCredentialAdaptor{
+ SymmetricProvider: o.Credentials,
+ },
+ }
+ }
+ return nil
+}
+
+// WithSigV4ASigningRegions applies an override to the authentication workflow to
+// use the given signing region set for SigV4A-authenticated operations.
+//
+// This is an advanced setting. The value here is FINAL, taking precedence over
+// the resolved signing region set from both auth scheme resolution and endpoint
+// resolution.
+func WithSigV4ASigningRegions(regions []string) func(*Options) {
+ fn := func(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (
+ out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
+ ) {
+ rscheme := getResolvedAuthScheme(ctx)
+ if rscheme == nil {
+ return out, metadata, fmt.Errorf("no resolved auth scheme")
+ }
+
+ smithyhttp.SetSigV4ASigningRegions(&rscheme.SignerProperties, regions)
+ return next.HandleFinalize(ctx, in)
+ }
+ return func(o *Options) {
+ o.APIOptions = append(o.APIOptions, func(s *middleware.Stack) error {
+ return s.Finalize.Insert(
+ middleware.FinalizeMiddlewareFunc("withSigV4ASigningRegions", fn),
+ "Signing",
+ middleware.Before,
+ )
+ })
+ }
+}
+
func ignoreAnonymousAuth(options *Options) {
if aws.IsCredentialsProvider(options.Credentials, (*aws.AnonymousCredentials)(nil)) {
options.Credentials = nil
diff --git a/vendor/github.com/aws/smithy-go/AGENTS.md b/vendor/github.com/aws/smithy-go/AGENTS.md
new file mode 100644
index 00000000000..e2a75b8ea19
--- /dev/null
+++ b/vendor/github.com/aws/smithy-go/AGENTS.md
@@ -0,0 +1,172 @@
+# AGENTS.md
+
+## Project overview
+
+smithy-go is the Go code generator and runtime for [Smithy](https://smithy.io/).
+It has two major components:
+
+1. **Codegen** (`codegen/`) — A Smithy build plugin written in Java that
+ generates Go client/server/shape code from Smithy models.
+2. **Runtime** (`./`, top-level Go module) — The Go packages that generated
+ code depends on at runtime.
+
+The primary downstream consumer is
+[aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2).
+
+## Repository layout
+
+```
+. # Root Go module (github.com/aws/smithy-go)
+├── auth/ # Auth identity + scheme interfaces
+│ └── bearer/ # Bearer token auth
+├── aws-http-auth/ # Separate module: AWS SigV4/SigV4A HTTP signing
+├── codegen/ # Java/Gradle: Smithy code generator
+│ ├── smithy-go-codegen/ # Main codegen source (Java)
+│ └── smithy-go-codegen-test/ # Codegen integration tests
+├── container/ # Generic container types
+├── context/ # Context helpers
+├── document/ # Smithy document type abstraction
+│ └── json/ # JSON document codec
+├── encoding/ # Wire format encoders/decoders
+│ ├── cbor/ # CBOR (used by rpcv2Cbor)
+│ ├── httpbinding/ # HTTP binding serde helpers
+│ ├── json/ # JSON encoder/decoder
+│ └── xml/ # XML encoder/decoder
+├── endpoints/ # Endpoint resolution types
+├── internal/ # Internal utilities (singleflight, etc.)
+├── io/ # I/O helpers
+├── logging/ # Logging interfaces
+├── metrics/ # Metrics interfaces
+│ └── smithyotelmetrics/ # Separate module: OpenTelemetry metrics adapter
+├── middleware/ # Middleware stack (the core of the operation pipeline)
+├── ptr/ # Pointer-to/from-value helpers
+├── testing/ # Test assertion helpers for generated protocol tests
+│ └── xml/ # XML comparison utilities
+├── time/ # Smithy timestamp format helpers
+├── tracing/ # Tracing interfaces
+│ └── smithyoteltracing/ # Separate module: OpenTelemetry tracing adapter
+└── transport/
+ └── http/ # HTTP request/response types and middleware
+```
+
+## Building and testing
+
+### Runtime (Go)
+
+```bash
+# Run unit tests
+make unit
+```
+
+### Codegen (Java)
+
+```bash
+# Build and test codegen
+cd codegen && ./gradlew build
+
+# Publish to local Maven for downstream use
+cd codegen && ./gradlew publishToMavenLocal
+```
+
+The codegen artifact version is fixed at `0.1.0` and is not published to
+Maven Central — you **MUST** `publishToMavenLocal`.
+
+## Runtime architecture
+
+### Middleware stack
+
+The operation pipeline is built on a middleware stack defined in `middleware/`.
+Steps execute in order: Initialize → Serialize → Build → Finalize →
+Deserialize. Each step is a `middleware.Step` that holds an ordered list of
+middleware. The codegen generates middleware registrations for each operation.
+
+### Encoding packages
+
+Each wire format has its own encoder/decoder under `encoding/`. These are
+low-level — they produce/consume raw tokens or values, not full Smithy shapes.
+Generated serde code calls into these packages.
+
+## Codegen: GoWriter and template system
+
+GoWriter extends Smithy's `SymbolWriter` and is the primary mechanism for
+generating Go source. It has **two distinct writing styles** that must not be
+confused.
+
+### Style 1: Positional args (`writer.write` / `writer.openBlock`)
+
+Inherited from `SymbolWriter`. Arguments are positional and referenced with
+`$`-prefixed format characters. Each `$X` consumes the next argument in order.
+
+Format characters:
+- `$L` — Literal (toString). Strings, names, anything that should be inserted
+ verbatim.
+- `$S` — String, quoted. Wraps the value in Go double-quotes.
+- `$T` — Type (Symbol). Inserts the symbol name and auto-adds its import.
+- `$P` — Pointable type (Symbol). Like `$T` but prepends `*` if the symbol is
+ marked pointable.
+- `$W` — Writable. Evaluates a `Writable` (lambda/closure) inline.
+- `$D` — Dependency. Adds a `GoDependency` import, expands to empty string.
+
+Numbered variants (`$1L`, `$2T`, etc.) allow reusing the same argument
+multiple times. The number is 1-indexed and refers to the position in the
+argument list:
+
+```java
+// $1L is used twice, $2L once — only 2 args needed
+writer.write("type $1L struct{}\nvar _ $2L = (*$1L)(nil)",
+ DEFAULT_NAME, INTERFACE_NAME);
+```
+
+`openBlock`/`closeBlock` manage indentation for braced blocks. Arguments are
+positional:
+
+```java
+writer.openBlock("func (c $P) $T(ctx $T) ($P, error) {", "}",
+ serviceSymbol, operationSymbol, contextSymbol, outputSymbol,
+ () -> {
+ writer.write("return nil, nil");
+ });
+```
+
+### Style 2: Named template args (`goTemplate` / `writeGoTemplate`)
+
+Uses `$name:X` syntax where `name` is a key in a `Map` and `X`
+is the format character. Arguments are passed as one or more maps. This is the
+**preferred style for new code** — it is more readable and less error-prone
+than positional args.
+
+```java
+return goTemplate("""
+ func $name:L(v $cborValue:T) ($type:T, error) {
+ return $coercer:T(v)
+ }
+ """,
+ Map.of(
+ "name", getDeserializerName(shape),
+ "cborValue", SmithyGoTypes.Encoding.Cbor.Value,
+ "type", symbolProvider.toSymbol(shape),
+ "coercer", coercer
+ ));
+```
+
+Rules:
+- `goTemplate(String, Map...)` is a **static** method that returns a
+ `Writable` (a `Consumer` lambda). It does NOT write immediately.
+- `writeGoTemplate(String, Map...)` is an **instance** method that writes
+ immediately to the writer.
+- Maps are merged into the writer's context scope for the duration of the
+ template. Multiple maps can be passed and are applied in order.
+- The writer pre-populates common symbols in context: `fmt.Sprintf`,
+ `fmt.Errorf`, `errors.As`, `context.Context`, `time.Now`.
+
+### Composing writables
+
+- `ChainWritable` — Collects multiple `Writable`s and composes them with
+ newlines between each. Use `.compose()` (with newlines) or
+ `.compose(false)` (without).
+
+### Symbol constants
+
+For symbols, use `SmithyGoDependency.*.valueSymbol("Name")` or
+`SmithyGoDependency.*.pointableSymbol("Name")`.
+
diff --git a/vendor/github.com/aws/smithy-go/CHANGELOG.md b/vendor/github.com/aws/smithy-go/CHANGELOG.md
index 27fc881232a..7fc37ff89ee 100644
--- a/vendor/github.com/aws/smithy-go/CHANGELOG.md
+++ b/vendor/github.com/aws/smithy-go/CHANGELOG.md
@@ -1,8 +1,46 @@
-# Release (2026-02-27)
+# Release (2026-05-27)
+
+## General Highlights
+* **Dependency Update**: Updated to the latest SDK module versions
+
+## Module Highlights
+* `github.com/aws/smithy-go`: v1.26.0
+ * **Feature**: Add StringSlice to endpoint rulesfn.
+
+# Release (2026-04-23)
+
+## General Highlights
+* **Dependency Update**: Updated to the latest SDK module versions
+
+## Module Highlights
+* `github.com/aws/smithy-go`: v1.25.1
+ * **Bug Fix**: Fixed a memory leak in the LRU cache implementation used by some AWS services.
+
+# Release (2026-04-15)
## General Highlights
* **Dependency Update**: Updated to the latest SDK module versions
+## Module Highlights
+* `github.com/aws/smithy-go`: v1.25.0
+ * **Feature**: Add support for endpointBdd trait
+
+# Release (2026-04-02)
+
+## General Highlights
+* **Dependency Update**: Updated to the latest SDK module versions
+
+## Module Highlights
+* `github.com/aws/smithy-go`: v1.24.3
+ * **Bug Fix**: Add additional sigv4 configuration.
+* `github.com/aws/smithy-go/aws-http-auth`: [v1.1.3](aws-http-auth/CHANGELOG.md#v113-2026-04-02)
+ * **Bug Fix**: Add additional sigv4 configuration.
+
+# Release (2026-02-27)
+
+## General Highlights
+* **Dependency Update**: Bump minimum go version to 1.24.
+
# Release (2026-02-20)
## General Highlights
diff --git a/vendor/github.com/aws/smithy-go/endpoints/private/bdd/evaluate.go b/vendor/github.com/aws/smithy-go/endpoints/private/bdd/evaluate.go
new file mode 100644
index 00000000000..ae0fb7fdad7
--- /dev/null
+++ b/vendor/github.com/aws/smithy-go/endpoints/private/bdd/evaluate.go
@@ -0,0 +1,35 @@
+package bdd
+
+const resultOffset int32 = 100_000_000
+const intsPerNode = 3
+
+// Evaluate traverses a compiled BDD node array and returns the result index.
+// nodes is a flat array of [condIdx, hi, lo] triples (1-indexed).
+// root is the root node reference. evalCond returns true/false for condition index.
+func Evaluate(nodes []int32, root int32, evalCond func(int) bool) int32 {
+ ref := root
+ for {
+ if ref >= resultOffset {
+ return ref - resultOffset
+ }
+ if ref == 1 || ref == -1 {
+ return 0 // NoMatchRule
+ }
+
+ complement := ref < 0
+ nodeIdx := ref
+ if complement {
+ nodeIdx = -ref
+ }
+ base := (nodeIdx - 1) * intsPerNode
+ condIdx := nodes[base]
+ hi := nodes[base+1]
+ lo := nodes[base+2]
+
+ if complement != evalCond(int(condIdx)) {
+ ref = hi
+ } else {
+ ref = lo
+ }
+ }
+}
diff --git a/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/split.go b/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/split.go
new file mode 100644
index 00000000000..f8b30789a01
--- /dev/null
+++ b/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/split.go
@@ -0,0 +1,16 @@
+package rulesfn
+
+import "strings"
+
+// Split splits the input string by the delimiter and returns the resulting
+// parts. If limit is > 0, at most limit substrings are returned.
+// Returns a slice with a single empty string if the input is empty.
+func Split(input, delimiter string, limit int) []string {
+ if len(input) == 0 {
+ return []string{""}
+ }
+ if limit > 0 {
+ return strings.SplitN(input, delimiter, limit)
+ }
+ return strings.Split(input, delimiter)
+}
diff --git a/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/string_slice.go b/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/string_slice.go
new file mode 100644
index 00000000000..7a82fcd94ed
--- /dev/null
+++ b/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/string_slice.go
@@ -0,0 +1,18 @@
+package rulesfn
+
+// StringSlice is a string slice with a negative-index-aware Get method for use
+// in endpoint rule evaluation.
+type StringSlice []string
+
+// Get returns a pointer to the string at index i, or nil if the index is out
+// of bounds. Negative indices count from the end of the slice.
+func (s StringSlice) Get(i int) *string {
+ if i < 0 {
+ i = len(s) + i
+ }
+ if i < 0 || i >= len(s) {
+ return nil
+ }
+ v := s[i]
+ return &v
+}
diff --git a/vendor/github.com/aws/smithy-go/go_module_metadata.go b/vendor/github.com/aws/smithy-go/go_module_metadata.go
index dc9dfd0d86d..bf309b96ccb 100644
--- a/vendor/github.com/aws/smithy-go/go_module_metadata.go
+++ b/vendor/github.com/aws/smithy-go/go_module_metadata.go
@@ -3,4 +3,4 @@
package smithy
// goModuleVersion is the tagged release for this module
-const goModuleVersion = "1.24.2"
+const goModuleVersion = "1.26.0"
diff --git a/vendor/github.com/cenkalti/backoff/v4/.gitignore b/vendor/github.com/cenkalti/backoff/v4/.gitignore
new file mode 100644
index 00000000000..50d95c548b6
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/.gitignore
@@ -0,0 +1,25 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+# IDEs
+.idea/
diff --git a/vendor/github.com/cenkalti/backoff/v4/LICENSE b/vendor/github.com/cenkalti/backoff/v4/LICENSE
new file mode 100644
index 00000000000..89b81799655
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Cenk Altı
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/cenkalti/backoff/v4/README.md b/vendor/github.com/cenkalti/backoff/v4/README.md
new file mode 100644
index 00000000000..9433004a280
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/README.md
@@ -0,0 +1,30 @@
+# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Coverage Status][coveralls image]][coveralls]
+
+This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
+
+[Exponential backoff][exponential backoff wiki]
+is an algorithm that uses feedback to multiplicatively decrease the rate of some process,
+in order to gradually find an acceptable rate.
+The retries exponentially increase and stop increasing when a certain threshold is met.
+
+## Usage
+
+Import path is `github.com/cenkalti/backoff/v4`. Please note the version part at the end.
+
+Use https://pkg.go.dev/github.com/cenkalti/backoff/v4 to view the documentation.
+
+## Contributing
+
+* I would like to keep this library as small as possible.
+* Please don't send a PR without opening an issue and discussing it first.
+* If proposed change is not a common use case, I will probably not accept it.
+
+[godoc]: https://pkg.go.dev/github.com/cenkalti/backoff/v4
+[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
+[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
+[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
+
+[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java
+[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff
+
+[advanced example]: https://pkg.go.dev/github.com/cenkalti/backoff/v4?tab=doc#pkg-examples
diff --git a/vendor/github.com/cenkalti/backoff/v4/backoff.go b/vendor/github.com/cenkalti/backoff/v4/backoff.go
new file mode 100644
index 00000000000..3676ee405d8
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/backoff.go
@@ -0,0 +1,66 @@
+// Package backoff implements backoff algorithms for retrying operations.
+//
+// Use Retry function for retrying operations that may fail.
+// If Retry does not meet your needs,
+// copy/paste the function into your project and modify as you wish.
+//
+// There is also Ticker type similar to time.Ticker.
+// You can use it if you need to work with channels.
+//
+// See Examples section below for usage examples.
+package backoff
+
+import "time"
+
+// BackOff is a backoff policy for retrying an operation.
+type BackOff interface {
+ // NextBackOff returns the duration to wait before retrying the operation,
+ // or backoff. Stop to indicate that no more retries should be made.
+ //
+ // Example usage:
+ //
+ // duration := backoff.NextBackOff();
+ // if (duration == backoff.Stop) {
+ // // Do not retry operation.
+ // } else {
+ // // Sleep for duration and retry operation.
+ // }
+ //
+ NextBackOff() time.Duration
+
+ // Reset to initial state.
+ Reset()
+}
+
+// Stop indicates that no more retries should be made for use in NextBackOff().
+const Stop time.Duration = -1
+
+// ZeroBackOff is a fixed backoff policy whose backoff time is always zero,
+// meaning that the operation is retried immediately without waiting, indefinitely.
+type ZeroBackOff struct{}
+
+func (b *ZeroBackOff) Reset() {}
+
+func (b *ZeroBackOff) NextBackOff() time.Duration { return 0 }
+
+// StopBackOff is a fixed backoff policy that always returns backoff.Stop for
+// NextBackOff(), meaning that the operation should never be retried.
+type StopBackOff struct{}
+
+func (b *StopBackOff) Reset() {}
+
+func (b *StopBackOff) NextBackOff() time.Duration { return Stop }
+
+// ConstantBackOff is a backoff policy that always returns the same backoff delay.
+// This is in contrast to an exponential backoff policy,
+// which returns a delay that grows longer as you call NextBackOff() over and over again.
+type ConstantBackOff struct {
+ Interval time.Duration
+}
+
+func (b *ConstantBackOff) Reset() {}
+func (b *ConstantBackOff) NextBackOff() time.Duration { return b.Interval }
+
+func NewConstantBackOff(d time.Duration) *ConstantBackOff {
+ return &ConstantBackOff{Interval: d}
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/context.go b/vendor/github.com/cenkalti/backoff/v4/context.go
new file mode 100644
index 00000000000..48482330eb7
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/context.go
@@ -0,0 +1,62 @@
+package backoff
+
+import (
+ "context"
+ "time"
+)
+
+// BackOffContext is a backoff policy that stops retrying after the context
+// is canceled.
+type BackOffContext interface { // nolint: golint
+ BackOff
+ Context() context.Context
+}
+
+type backOffContext struct {
+ BackOff
+ ctx context.Context
+}
+
+// WithContext returns a BackOffContext with context ctx
+//
+// ctx must not be nil
+func WithContext(b BackOff, ctx context.Context) BackOffContext { // nolint: golint
+ if ctx == nil {
+ panic("nil context")
+ }
+
+ if b, ok := b.(*backOffContext); ok {
+ return &backOffContext{
+ BackOff: b.BackOff,
+ ctx: ctx,
+ }
+ }
+
+ return &backOffContext{
+ BackOff: b,
+ ctx: ctx,
+ }
+}
+
+func getContext(b BackOff) context.Context {
+ if cb, ok := b.(BackOffContext); ok {
+ return cb.Context()
+ }
+ if tb, ok := b.(*backOffTries); ok {
+ return getContext(tb.delegate)
+ }
+ return context.Background()
+}
+
+func (b *backOffContext) Context() context.Context {
+ return b.ctx
+}
+
+func (b *backOffContext) NextBackOff() time.Duration {
+ select {
+ case <-b.ctx.Done():
+ return Stop
+ default:
+ return b.BackOff.NextBackOff()
+ }
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/exponential.go b/vendor/github.com/cenkalti/backoff/v4/exponential.go
new file mode 100644
index 00000000000..aac99f196ad
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/exponential.go
@@ -0,0 +1,216 @@
+package backoff
+
+import (
+ "math/rand"
+ "time"
+)
+
+/*
+ExponentialBackOff is a backoff implementation that increases the backoff
+period for each retry attempt using a randomization function that grows exponentially.
+
+NextBackOff() is calculated using the following formula:
+
+ randomized interval =
+ RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])
+
+In other words NextBackOff() will range between the randomization factor
+percentage below and above the retry interval.
+
+For example, given the following parameters:
+
+ RetryInterval = 2
+ RandomizationFactor = 0.5
+ Multiplier = 2
+
+the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
+multiplied by the exponential, that is, between 2 and 6 seconds.
+
+Note: MaxInterval caps the RetryInterval and not the randomized interval.
+
+If the time elapsed since an ExponentialBackOff instance is created goes past the
+MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop.
+
+The elapsed time can be reset by calling Reset().
+
+Example: Given the following default arguments, for 10 tries the sequence will be,
+and assuming we go over the MaxElapsedTime on the 10th try:
+
+ Request # RetryInterval (seconds) Randomized Interval (seconds)
+
+ 1 0.5 [0.25, 0.75]
+ 2 0.75 [0.375, 1.125]
+ 3 1.125 [0.562, 1.687]
+ 4 1.687 [0.8435, 2.53]
+ 5 2.53 [1.265, 3.795]
+ 6 3.795 [1.897, 5.692]
+ 7 5.692 [2.846, 8.538]
+ 8 8.538 [4.269, 12.807]
+ 9 12.807 [6.403, 19.210]
+ 10 19.210 backoff.Stop
+
+Note: Implementation is not thread-safe.
+*/
+type ExponentialBackOff struct {
+ InitialInterval time.Duration
+ RandomizationFactor float64
+ Multiplier float64
+ MaxInterval time.Duration
+ // After MaxElapsedTime the ExponentialBackOff returns Stop.
+ // It never stops if MaxElapsedTime == 0.
+ MaxElapsedTime time.Duration
+ Stop time.Duration
+ Clock Clock
+
+ currentInterval time.Duration
+ startTime time.Time
+}
+
+// Clock is an interface that returns current time for BackOff.
+type Clock interface {
+ Now() time.Time
+}
+
+// ExponentialBackOffOpts is a function type used to configure ExponentialBackOff options.
+type ExponentialBackOffOpts func(*ExponentialBackOff)
+
+// Default values for ExponentialBackOff.
+const (
+ DefaultInitialInterval = 500 * time.Millisecond
+ DefaultRandomizationFactor = 0.5
+ DefaultMultiplier = 1.5
+ DefaultMaxInterval = 60 * time.Second
+ DefaultMaxElapsedTime = 15 * time.Minute
+)
+
+// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
+func NewExponentialBackOff(opts ...ExponentialBackOffOpts) *ExponentialBackOff {
+ b := &ExponentialBackOff{
+ InitialInterval: DefaultInitialInterval,
+ RandomizationFactor: DefaultRandomizationFactor,
+ Multiplier: DefaultMultiplier,
+ MaxInterval: DefaultMaxInterval,
+ MaxElapsedTime: DefaultMaxElapsedTime,
+ Stop: Stop,
+ Clock: SystemClock,
+ }
+ for _, fn := range opts {
+ fn(b)
+ }
+ b.Reset()
+ return b
+}
+
+// WithInitialInterval sets the initial interval between retries.
+func WithInitialInterval(duration time.Duration) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.InitialInterval = duration
+ }
+}
+
+// WithRandomizationFactor sets the randomization factor to add jitter to intervals.
+func WithRandomizationFactor(randomizationFactor float64) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.RandomizationFactor = randomizationFactor
+ }
+}
+
+// WithMultiplier sets the multiplier for increasing the interval after each retry.
+func WithMultiplier(multiplier float64) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.Multiplier = multiplier
+ }
+}
+
+// WithMaxInterval sets the maximum interval between retries.
+func WithMaxInterval(duration time.Duration) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.MaxInterval = duration
+ }
+}
+
+// WithMaxElapsedTime sets the maximum total time for retries.
+func WithMaxElapsedTime(duration time.Duration) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.MaxElapsedTime = duration
+ }
+}
+
+// WithRetryStopDuration sets the duration after which retries should stop.
+func WithRetryStopDuration(duration time.Duration) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.Stop = duration
+ }
+}
+
+// WithClockProvider sets the clock used to measure time.
+func WithClockProvider(clock Clock) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.Clock = clock
+ }
+}
+
+type systemClock struct{}
+
+func (t systemClock) Now() time.Time {
+ return time.Now()
+}
+
+// SystemClock implements Clock interface that uses time.Now().
+var SystemClock = systemClock{}
+
+// Reset the interval back to the initial retry interval and restarts the timer.
+// Reset must be called before using b.
+func (b *ExponentialBackOff) Reset() {
+ b.currentInterval = b.InitialInterval
+ b.startTime = b.Clock.Now()
+}
+
+// NextBackOff calculates the next backoff interval using the formula:
+// Randomized interval = RetryInterval * (1 ± RandomizationFactor)
+func (b *ExponentialBackOff) NextBackOff() time.Duration {
+ // Make sure we have not gone over the maximum elapsed time.
+ elapsed := b.GetElapsedTime()
+ next := getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
+ b.incrementCurrentInterval()
+ if b.MaxElapsedTime != 0 && elapsed+next > b.MaxElapsedTime {
+ return b.Stop
+ }
+ return next
+}
+
+// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
+// is created and is reset when Reset() is called.
+//
+// The elapsed time is computed using time.Now().UnixNano(). It is
+// safe to call even while the backoff policy is used by a running
+// ticker.
+func (b *ExponentialBackOff) GetElapsedTime() time.Duration {
+ return b.Clock.Now().Sub(b.startTime)
+}
+
+// Increments the current interval by multiplying it with the multiplier.
+func (b *ExponentialBackOff) incrementCurrentInterval() {
+ // Check for overflow, if overflow is detected set the current interval to the max interval.
+ if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {
+ b.currentInterval = b.MaxInterval
+ } else {
+ b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)
+ }
+}
+
+// Returns a random value from the following interval:
+// [currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].
+func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
+ if randomizationFactor == 0 {
+ return currentInterval // make sure no randomness is used when randomizationFactor is 0.
+ }
+ var delta = randomizationFactor * float64(currentInterval)
+ var minInterval = float64(currentInterval) - delta
+ var maxInterval = float64(currentInterval) + delta
+
+ // Get a random value from the range [minInterval, maxInterval].
+ // The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
+ // we want a 33% chance for selecting either 1, 2 or 3.
+ return time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/retry.go b/vendor/github.com/cenkalti/backoff/v4/retry.go
new file mode 100644
index 00000000000..b9c0c51cd75
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/retry.go
@@ -0,0 +1,146 @@
+package backoff
+
+import (
+ "errors"
+ "time"
+)
+
+// An OperationWithData is executing by RetryWithData() or RetryNotifyWithData().
+// The operation will be retried using a backoff policy if it returns an error.
+type OperationWithData[T any] func() (T, error)
+
+// An Operation is executing by Retry() or RetryNotify().
+// The operation will be retried using a backoff policy if it returns an error.
+type Operation func() error
+
+func (o Operation) withEmptyData() OperationWithData[struct{}] {
+ return func() (struct{}, error) {
+ return struct{}{}, o()
+ }
+}
+
+// Notify is a notify-on-error function. It receives an operation error and
+// backoff delay if the operation failed (with an error).
+//
+// NOTE that if the backoff policy stated to stop retrying,
+// the notify function isn't called.
+type Notify func(error, time.Duration)
+
+// Retry the operation o until it does not return error or BackOff stops.
+// o is guaranteed to be run at least once.
+//
+// If o returns a *PermanentError, the operation is not retried, and the
+// wrapped error is returned.
+//
+// Retry sleeps the goroutine for the duration returned by BackOff after a
+// failed operation returns.
+func Retry(o Operation, b BackOff) error {
+ return RetryNotify(o, b, nil)
+}
+
+// RetryWithData is like Retry but returns data in the response too.
+func RetryWithData[T any](o OperationWithData[T], b BackOff) (T, error) {
+ return RetryNotifyWithData(o, b, nil)
+}
+
+// RetryNotify calls notify function with the error and wait duration
+// for each failed attempt before sleep.
+func RetryNotify(operation Operation, b BackOff, notify Notify) error {
+ return RetryNotifyWithTimer(operation, b, notify, nil)
+}
+
+// RetryNotifyWithData is like RetryNotify but returns data in the response too.
+func RetryNotifyWithData[T any](operation OperationWithData[T], b BackOff, notify Notify) (T, error) {
+ return doRetryNotify(operation, b, notify, nil)
+}
+
+// RetryNotifyWithTimer calls notify function with the error and wait duration using the given Timer
+// for each failed attempt before sleep.
+// A default timer that uses system timer is used when nil is passed.
+func RetryNotifyWithTimer(operation Operation, b BackOff, notify Notify, t Timer) error {
+ _, err := doRetryNotify(operation.withEmptyData(), b, notify, t)
+ return err
+}
+
+// RetryNotifyWithTimerAndData is like RetryNotifyWithTimer but returns data in the response too.
+func RetryNotifyWithTimerAndData[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
+ return doRetryNotify(operation, b, notify, t)
+}
+
+func doRetryNotify[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
+ var (
+ err error
+ next time.Duration
+ res T
+ )
+ if t == nil {
+ t = &defaultTimer{}
+ }
+
+ defer func() {
+ t.Stop()
+ }()
+
+ ctx := getContext(b)
+
+ b.Reset()
+ for {
+ res, err = operation()
+ if err == nil {
+ return res, nil
+ }
+
+ var permanent *PermanentError
+ if errors.As(err, &permanent) {
+ return res, permanent.Err
+ }
+
+ if next = b.NextBackOff(); next == Stop {
+ if cerr := ctx.Err(); cerr != nil {
+ return res, cerr
+ }
+
+ return res, err
+ }
+
+ if notify != nil {
+ notify(err, next)
+ }
+
+ t.Start(next)
+
+ select {
+ case <-ctx.Done():
+ return res, ctx.Err()
+ case <-t.C():
+ }
+ }
+}
+
+// PermanentError signals that the operation should not be retried.
+type PermanentError struct {
+ Err error
+}
+
+func (e *PermanentError) Error() string {
+ return e.Err.Error()
+}
+
+func (e *PermanentError) Unwrap() error {
+ return e.Err
+}
+
+func (e *PermanentError) Is(target error) bool {
+ _, ok := target.(*PermanentError)
+ return ok
+}
+
+// Permanent wraps the given err in a *PermanentError.
+func Permanent(err error) error {
+ if err == nil {
+ return nil
+ }
+ return &PermanentError{
+ Err: err,
+ }
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/ticker.go b/vendor/github.com/cenkalti/backoff/v4/ticker.go
new file mode 100644
index 00000000000..df9d68bce52
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/ticker.go
@@ -0,0 +1,97 @@
+package backoff
+
+import (
+ "context"
+ "sync"
+ "time"
+)
+
+// Ticker holds a channel that delivers `ticks' of a clock at times reported by a BackOff.
+//
+// Ticks will continue to arrive when the previous operation is still running,
+// so operations that take a while to fail could run in quick succession.
+type Ticker struct {
+ C <-chan time.Time
+ c chan time.Time
+ b BackOff
+ ctx context.Context
+ timer Timer
+ stop chan struct{}
+ stopOnce sync.Once
+}
+
+// NewTicker returns a new Ticker containing a channel that will send
+// the time at times specified by the BackOff argument. Ticker is
+// guaranteed to tick at least once. The channel is closed when Stop
+// method is called or BackOff stops. It is not safe to manipulate the
+// provided backoff policy (notably calling NextBackOff or Reset)
+// while the ticker is running.
+func NewTicker(b BackOff) *Ticker {
+ return NewTickerWithTimer(b, &defaultTimer{})
+}
+
+// NewTickerWithTimer returns a new Ticker with a custom timer.
+// A default timer that uses system timer is used when nil is passed.
+func NewTickerWithTimer(b BackOff, timer Timer) *Ticker {
+ if timer == nil {
+ timer = &defaultTimer{}
+ }
+ c := make(chan time.Time)
+ t := &Ticker{
+ C: c,
+ c: c,
+ b: b,
+ ctx: getContext(b),
+ timer: timer,
+ stop: make(chan struct{}),
+ }
+ t.b.Reset()
+ go t.run()
+ return t
+}
+
+// Stop turns off a ticker. After Stop, no more ticks will be sent.
+func (t *Ticker) Stop() {
+ t.stopOnce.Do(func() { close(t.stop) })
+}
+
+func (t *Ticker) run() {
+ c := t.c
+ defer close(c)
+
+ // Ticker is guaranteed to tick at least once.
+ afterC := t.send(time.Now())
+
+ for {
+ if afterC == nil {
+ return
+ }
+
+ select {
+ case tick := <-afterC:
+ afterC = t.send(tick)
+ case <-t.stop:
+ t.c = nil // Prevent future ticks from being sent to the channel.
+ return
+ case <-t.ctx.Done():
+ return
+ }
+ }
+}
+
+func (t *Ticker) send(tick time.Time) <-chan time.Time {
+ select {
+ case t.c <- tick:
+ case <-t.stop:
+ return nil
+ }
+
+ next := t.b.NextBackOff()
+ if next == Stop {
+ t.Stop()
+ return nil
+ }
+
+ t.timer.Start(next)
+ return t.timer.C()
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/timer.go b/vendor/github.com/cenkalti/backoff/v4/timer.go
new file mode 100644
index 00000000000..8120d0213c5
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/timer.go
@@ -0,0 +1,35 @@
+package backoff
+
+import "time"
+
+type Timer interface {
+ Start(duration time.Duration)
+ Stop()
+ C() <-chan time.Time
+}
+
+// defaultTimer implements Timer interface using time.Timer
+type defaultTimer struct {
+ timer *time.Timer
+}
+
+// C returns the timers channel which receives the current time when the timer fires.
+func (t *defaultTimer) C() <-chan time.Time {
+ return t.timer.C
+}
+
+// Start starts the timer to fire after the given duration
+func (t *defaultTimer) Start(duration time.Duration) {
+ if t.timer == nil {
+ t.timer = time.NewTimer(duration)
+ } else {
+ t.timer.Reset(duration)
+ }
+}
+
+// Stop is called when the timer is not used anymore and resources may be freed.
+func (t *defaultTimer) Stop() {
+ if t.timer != nil {
+ t.timer.Stop()
+ }
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/tries.go b/vendor/github.com/cenkalti/backoff/v4/tries.go
new file mode 100644
index 00000000000..28d58ca37c6
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/tries.go
@@ -0,0 +1,38 @@
+package backoff
+
+import "time"
+
+/*
+WithMaxRetries creates a wrapper around another BackOff, which will
+return Stop if NextBackOff() has been called too many times since
+the last time Reset() was called
+
+Note: Implementation is not thread-safe.
+*/
+func WithMaxRetries(b BackOff, max uint64) BackOff {
+ return &backOffTries{delegate: b, maxTries: max}
+}
+
+type backOffTries struct {
+ delegate BackOff
+ maxTries uint64
+ numTries uint64
+}
+
+func (b *backOffTries) NextBackOff() time.Duration {
+ if b.maxTries == 0 {
+ return Stop
+ }
+ if b.maxTries > 0 {
+ if b.maxTries <= b.numTries {
+ return Stop
+ }
+ b.numTries++
+ }
+ return b.delegate.NextBackOff()
+}
+
+func (b *backOffTries) Reset() {
+ b.numTries = 0
+ b.delegate.Reset()
+}
diff --git a/vendor/github.com/coder/quartz/.gitignore b/vendor/github.com/coder/quartz/.gitignore
new file mode 100644
index 00000000000..62c893550ad
--- /dev/null
+++ b/vendor/github.com/coder/quartz/.gitignore
@@ -0,0 +1 @@
+.idea/
\ No newline at end of file
diff --git a/vendor/github.com/coder/quartz/LICENSE b/vendor/github.com/coder/quartz/LICENSE
new file mode 100644
index 00000000000..aee8c1d627f
--- /dev/null
+++ b/vendor/github.com/coder/quartz/LICENSE
@@ -0,0 +1,18 @@
+MIT No Attribution
+
+Copyright (c) Coder Technologies, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/coder/quartz/README.md b/vendor/github.com/coder/quartz/README.md
new file mode 100644
index 00000000000..b0da401ec4f
--- /dev/null
+++ b/vendor/github.com/coder/quartz/README.md
@@ -0,0 +1,632 @@
+# Quartz
+
+A Go time testing library for writing deterministic unit tests
+
+Our high level goal is to write unit tests that
+
+1. execute quickly
+2. don't flake
+3. are straightforward to write and understand
+
+For tests to execute quickly without flakes, we want to focus on _determinism_: the test should run
+the same each time, and it should be easy to force the system into a known state (no races) before
+executing test assertions. `time.Sleep`, `runtime.Gosched()`, and
+polling/[Eventually](https://pkg.go.dev/github.com/stretchr/testify/assert#Eventually) are all
+symptoms of an inability to do this easily.
+
+## Usage
+
+### `Clock` interface
+
+In your application code, maintain a reference to a `quartz.Clock` instance to start timers and
+tickers, instead of the bare `time` standard library.
+
+```go
+import "github.com/coder/quartz"
+
+type Component struct {
+ ...
+
+ // for testing
+ clock quartz.Clock
+}
+```
+
+Whenever you would call into `time` to start a timer or ticker, call `Component`'s `clock` instead.
+
+In production, set this clock to `quartz.NewReal()` to create a clock that just transparently passes
+through to the standard `time` library.
+
+### Mocking
+
+In your tests, you can use a `*Mock` to control the tickers and timers your code under test gets.
+
+```go
+import (
+ "testing"
+ "github.com/coder/quartz"
+)
+
+func TestComponent(t *testing.T) {
+ mClock := quartz.NewMock(t)
+ comp := &Component{
+ ...
+ clock: mClock,
+ }
+}
+```
+
+The `*Mock` clock starts at Jan 1, 2024, 00:00 UTC by default, but you can set any start time you'd like prior to your test.
+
+```go
+mClock := quartz.NewMock(t)
+mClock.Set(time.Date(2021, 6, 18, 12, 0, 0, 0, time.UTC)) // June 18, 2021 @ 12pm UTC
+```
+
+#### Advancing the clock
+
+Once you begin setting timers or tickers, you cannot change the time backward, only advance it
+forward. You may continue to use `Set()`, but it is often easier and clearer to use `Advance()`.
+
+For example, with a timer:
+
+```go
+fired := false
+
+tmr := mClock.AfterFunc(time.Second, func() {
+ fired = true
+})
+mClock.Advance(time.Second)
+```
+
+When you call `Advance()` it immediately moves the clock forward the given amount, and triggers any
+tickers or timers that are scheduled to happen at that time. Any triggered events happen on separate
+goroutines, so _do not_ immediately assert the results:
+
+```go
+fired := false
+
+tmr := mClock.AfterFunc(time.Second, func() {
+ fired = true
+})
+mClock.Advance(time.Second)
+
+// RACE CONDITION, DO NOT DO THIS!
+if !fired {
+ t.Fatal("didn't fire")
+}
+```
+
+`Advance()` (and `Set()` for that matter) return an `AdvanceWaiter` object you can use to wait for
+all triggered events to complete.
+
+```go
+fired := false
+// set a test timeout so we don't wait the default `go test` timeout for a failure
+ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+
+tmr := mClock.AfterFunc(time.Second, func() {
+ fired = true
+})
+
+w := mClock.Advance(time.Second)
+err := w.Wait(ctx)
+if err != nil {
+ t.Fatal("AfterFunc f never completed")
+}
+if !fired {
+ t.Fatal("didn't fire")
+}
+```
+
+The construction of waiting for the triggered events and failing the test if they don't complete is
+very common, so there is a shorthand:
+
+```go
+w := mClock.Advance(time.Second)
+err := w.Wait(ctx)
+if err != nil {
+ t.Fatal("AfterFunc f never completed")
+}
+```
+
+is equivalent to:
+
+```go
+w := mClock.Advance(time.Second)
+w.MustWait(ctx)
+```
+
+or even more briefly:
+
+```go
+mClock.Advance(time.Second).MustWait(ctx)
+```
+
+### Advance only to the next event
+
+One important restriction on advancing the clock is that you may only advance forward to the next
+timer or ticker event and no further. The following will result in a test failure:
+
+```go
+func TestAdvanceTooFar(t *testing.T) {
+ ctx, cancel := context.WithTimeout(10*time.Second)
+ defer cancel()
+ mClock := quartz.NewMock(t)
+ var firedAt time.Time
+ mClock.AfterFunc(time.Second, func() {
+ firedAt := mClock.Now()
+ })
+ mClock.Advance(2*time.Second).MustWait(ctx)
+}
+```
+
+This is a deliberate design decision to allow `Advance()` to immediately and synchronously move the
+clock forward (even without calling `Wait()` on returned waiter). This helps meet Quartz's design
+goals of writing deterministic and easy to understand unit tests. It also allows the clock to be
+advanced, deterministically _during_ the execution of a tick or timer function, as explained in the
+next sections on Traps.
+
+Advancing multiple events can be accomplished via looping. E.g. if you have a 1-second ticker
+
+```go
+for i := 0; i < 10; i++ {
+ mClock.Advance(time.Second).MustWait(ctx)
+}
+```
+
+will advance 10 ticks.
+
+If you don't know or don't want to compute the time to the next event, you can use `AdvanceNext()`.
+
+```go
+d, w := mClock.AdvanceNext()
+w.MustWait(ctx)
+// d contains the duration we advanced
+```
+
+`d, ok := Peek()` returns the duration until the next event, if any (`ok` is `true`). You can use
+this to advance a specific time, regardless of the tickers and timer events:
+
+```go
+desired := time.Minute // time to advance
+for desired > 0 {
+ p, ok := mClock.Peek()
+ if !ok || p > desired {
+ mClock.Advance(desired).MustWait(ctx)
+ break
+ }
+ mClock.Advance(p).MustWait(ctx)
+ desired -= p
+}
+```
+
+### Traps
+
+A trap allows you to match specific calls into the library while mocking, block their return,
+inspect their arguments, then release them to allow them to return. They help you write
+deterministic unit tests even when the code under test executes asynchronously from the test.
+
+You set your traps prior to executing code under test, and then wait for them to be triggered.
+
+```go
+func TestTrap(t *testing.T) {
+ ctx, cancel := context.WithTimeout(10*time.Second)
+ defer cancel()
+ mClock := quartz.NewMock(t)
+ trap := mClock.Trap().AfterFunc()
+ defer trap.Close() // stop trapping AfterFunc calls
+
+ count := 0
+ go mClock.AfterFunc(time.Hour, func(){
+ count++
+ })
+ call := trap.MustWait(ctx)
+ call.MustRelease(ctx)
+ if call.Duration != time.Hour {
+ t.Fatal("wrong duration")
+ }
+
+ // Now that the async call to AfterFunc has occurred, we can advance the clock to trigger it
+ mClock.Advance(call.Duration).MustWait(ctx)
+ if count != 1 {
+ t.Fatal("wrong count")
+ }
+}
+```
+
+In this test, the trap serves 2 purposes. Firstly, it allows us to capture and assert the duration
+passed to the `AfterFunc` call. Secondly, it prevents a race between setting the timer and advancing
+it. Since these things happen on different goroutines, if `Advance()` completes before
+`AfterFunc()` is called, then the timer never pops in this test.
+
+Any untrapped calls immediately complete using the current time, and calling `Close()` on a trap
+causes the mock clock to stop trapping those calls.
+
+You may also `Advance()` the clock between trapping a call and releasing it. The call uses the
+current (mocked) time at the moment it is released.
+
+```go
+func TestTrap2(t *testing.T) {
+ ctx, cancel := context.WithTimeout(10*time.Second)
+ defer cancel()
+ mClock := quartz.NewMock(t)
+ trap := mClock.Trap().Now()
+ defer trap.Close() // stop trapping AfterFunc calls
+
+ var logs []string
+ done := make(chan struct{})
+ go func(clk quartz.Clock){
+ defer close(done)
+ start := clk.Now()
+ phase1()
+ p1end := clk.Now()
+ logs = append(fmt.Sprintf("Phase 1 took %s", p1end.Sub(start).String()))
+ phase2()
+ p2end := clk.Now()
+ logs = append(fmt.Sprintf("Phase 2 took %s", p2end.Sub(p1end).String()))
+ }(mClock)
+
+ // start
+ trap.MustWait(ctx).MustRelease(ctx)
+ // phase 1
+ call := trap.MustWait(ctx)
+ mClock.Advance(3*time.Second).MustWait(ctx)
+ call.MustRelease(ctx)
+ // phase 2
+ call = trap.MustWait(ctx)
+ mClock.Advance(5*time.Second).MustWait(ctx)
+ call.MustRelease(ctx)
+
+ <-done
+ // Now logs contains []string{"Phase 1 took 3s", "Phase 2 took 5s"}
+}
+```
+
+### Tags
+
+When multiple goroutines in the code under test call into the Clock, you can use `tags` to
+distinguish them in your traps.
+
+```go
+trap := mClock.Trap.Now("foo") // traps any calls that contain "foo"
+defer trap.Close()
+
+foo := make(chan time.Time)
+go func(){
+ foo <- mClock.Now("foo", "bar")
+}()
+baz := make(chan time.Time)
+go func(){
+ baz <- mClock.Now("baz")
+}()
+call := trap.MustWait(ctx)
+mClock.Advance(time.Second).MustWait(ctx)
+call.MustRelease(ctx)
+// call.Tags contains []string{"foo", "bar"}
+
+gotFoo := <-foo // 1s after start
+gotBaz := <-baz // ?? never trapped, so races with Advance()
+```
+
+Tags appear as an optional suffix on all `Clock` methods (type `...string`) and are ignored entirely
+by the real clock. They also appear on all methods on returned timers and tickers.
+
+## Recommended Patterns
+
+### Options
+
+We use the Option pattern to inject the mock clock for testing, keeping the call signature in
+production clean. The option pattern is compatible with other optional fields as well.
+
+```go
+type Option func(*Thing)
+
+// WithTestClock is used in tests to inject a mock Clock
+func WithTestClock(clk quartz.Clock) Option {
+ return func(t *Thing) {
+ t.clock = clk
+ }
+}
+
+func NewThing(, opts ...Option) *Thing {
+ t := &Thing{
+ ...
+ clock: quartz.NewReal()
+ }
+ for _, o := range opts {
+ o(t)
+ }
+ return t
+}
+```
+
+In tests, this becomes
+
+```go
+func TestThing(t *testing.T) {
+ mClock := quartz.NewMock(t)
+ thing := NewThing(, WithTestClock(mClock))
+ ...
+}
+```
+
+### Tagging convention
+
+Tag your `Clock` method calls as:
+
+```go
+func (c *Component) Method() {
+ now := c.clock.Now("Component", "Method")
+}
+```
+
+or
+
+```go
+func (c *Component) Method() {
+ start := c.clock.Now("Component", "Method", "start")
+ ...
+ end := c.clock.Now("Component", "Method", "end")
+}
+```
+
+This makes it much less likely that code changes that introduce new components or methods will spoil
+existing unit tests.
+
+## Why another time testing library?
+
+Writing good unit tests for components and functions that use the `time` package is difficult, even
+though several open source libraries exist. In building Quartz, we took some inspiration from
+
+- [github.com/benbjohnson/clock](https://github.com/benbjohnson/clock)
+- Tailscale's [tstest.Clock](https://github.com/coder/tailscale/blob/main/tstest/clock.go)
+- [github.com/aspenmesh/tock](https://github.com/aspenmesh/tock)
+
+Quartz shares the high level design of a `Clock` interface that closely resembles the functions in
+the `time` standard library, and a "real" clock passes thru to the standard library in production,
+while a mock clock gives precise control in testing.
+
+As mentioned in our introduction, our high level goal is to write unit tests that
+
+1. execute quickly
+2. don't flake
+3. are straightforward to write and understand
+
+For several reasons, this is a tall order when it comes to code that depends on time, and we found
+the existing libraries insufficient for our goals.
+
+### Preventing test flakes
+
+The following example comes from the README from benbjohnson/clock:
+
+```go
+mock := clock.NewMock()
+count := 0
+
+// Kick off a timer to increment every 1 mock second.
+go func() {
+ ticker := mock.Ticker(1 * time.Second)
+ for {
+ <-ticker.C
+ count++
+ }
+}()
+runtime.Gosched()
+
+// Move the clock forward 10 seconds.
+mock.Add(10 * time.Second)
+
+// This prints 10.
+fmt.Println(count)
+```
+
+The first race condition is fairly obvious: moving the clock forward 10 seconds may generate 10
+ticks on the `ticker.C` channel, but there is no guarantee that `count++` executes before
+`fmt.Println(count)`.
+
+The second race condition is more subtle, but `runtime.Gosched()` is the tell. Since the ticker
+is started on a separate goroutine, there is no guarantee that `mock.Ticker()` executes before
+`mock.Add()`. `runtime.Gosched()` is an attempt to get this to happen, but it makes no hard
+promises. On a busy system, especially when running tests in parallel, this can flake, advance the
+time 10 seconds first, then start the ticker and never generate a tick.
+
+Let's talk about how Quartz tackles these problems.
+
+In our experience, an extremely common use case is creating a ticker then doing a 2-arm `select`
+with ticks in one and context expiring in another, i.e.
+
+```go
+t := time.NewTicker(duration)
+for {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-t.C:
+ err := do()
+ if err != nil {
+ return err
+ }
+ }
+}
+```
+
+In Quartz, we refactor this to be more compact and testing friendly:
+
+```go
+t := clock.TickerFunc(ctx, duration, do)
+return t.Wait()
+```
+
+This affords the mock `Clock` the ability to explicitly know when processing of a tick is finished
+because it's wrapped in the function passed to `TickerFunc` (`do()` in this example).
+
+In Quartz, when you advance the clock, you are returned an object you can `Wait()` on to ensure all
+ticks and timers triggered are finished. This solves the first race condition in the example.
+
+(As an aside, we still support a traditional standard library-style `Ticker`. You may find it useful
+if you want to keep your code as close as possible to the standard library, or if you need to use
+the channel in a larger `select` block. In that case, you'll have to find some other mechanism to
+sync tick processing to your test code.)
+
+To prevent race conditions related to the starting of the ticker, Quartz allows you to set "traps"
+for calls that access the clock.
+
+```go
+func TestTicker(t *testing.T) {
+ mClock := quartz.NewMock(t)
+ trap := mClock.Trap().TickerFunc()
+ defer trap.Close() // stop trapping at end
+ go runMyTicker(mClock) // async calls TickerFunc()
+ call := trap.MustWait(context.Background()) // waits for a call and blocks its return
+ call.MustRelease(ctx) // allow the TickerFunc() call to return
+ // optionally check the duration using call.Duration
+ // Move the clock forward 1 tick
+ mClock.Advance(time.Second).MustWait(context.Background())
+ // assert results of the tick
+}
+```
+
+Trapping and then releasing the call to `TickerFunc()` ensures the ticker is started at a
+deterministic time, so our calls to `Advance()` will have a predictable effect.
+
+Take a look at `TestExampleTickerFunc` in `example_test.go` for a complete worked example.
+
+### Complex time dependence
+
+Another difficult issue to handle when unit testing is when some code under test makes multiple
+calls that depend on the time, and you want to simulate some time passing between them.
+
+A very basic example is measuring how long something took:
+
+```go
+var measurement time.Duration
+go func(clock quartz.Clock) {
+ start := clock.Now()
+ doSomething()
+ measurement = clock.Since(start)
+}(mClock)
+
+// how to get measurement to be, say, 5 seconds?
+```
+
+The two calls into the clock happen asynchronously, so we need to be able to advance the clock after
+the first call to `Now()` but before the call to `Since()`. Doing this with the libraries we
+mentioned above means that you have to be able to mock out or otherwise block the completion of
+`doSomething()`.
+
+But, with the trap functionality we mentioned in the previous section, you can deterministically
+control the time each call sees.
+
+```go
+trap := mClock.Trap().Since()
+var measurement time.Duration
+go func(clock quartz.Clock) {
+ start := clock.Now()
+ doSomething()
+ measurement = clock.Since(start)
+}(mClock)
+
+c := trap.MustWait(ctx)
+mClock.Advance(5*time.Second)
+c.MustRelease(ctx)
+```
+
+We wait until we trap the `clock.Since()` call, which implies that `clock.Now()` has completed, then
+advance the mock clock 5 seconds. Finally, we release the `clock.Since()` call. Any changes to the
+clock that happen _before_ we release the call will be included in the time used for the
+`clock.Since()` call.
+
+As a more involved example, consider an inactivity timeout: we want something to happen if there is
+no activity recorded for some period, say 10 minutes in the following example:
+
+```go
+type InactivityTimer struct {
+ mu sync.Mutex
+ activity time.Time
+ clock quartz.Clock
+}
+
+func (i *InactivityTimer) Start() {
+ i.mu.Lock()
+ defer i.mu.Unlock()
+ next := i.clock.Until(i.activity.Add(10*time.Minute))
+ t := i.clock.AfterFunc(next, func() {
+ i.mu.Lock()
+ defer i.mu.Unlock()
+ next := i.clock.Until(i.activity.Add(10*time.Minute))
+ if next == 0 {
+ i.timeoutLocked()
+ return
+ }
+ t.Reset(next)
+ })
+}
+```
+
+The actual contents of `timeoutLocked()` doesn't matter for this example, and assume there are other
+functions that record the latest `activity`.
+
+We found that some time testing libraries hold a lock on the mock clock while calling the function
+passed to `AfterFunc`, resulting in a deadlock if you made clock calls from within.
+
+Others allow this sort of thing, but don't have the flexibility to test edge cases. There is a
+subtle bug in our `Start()` function. The timer may pop a little late, and/or some measurable real
+time may elapse before `Until()` gets called inside the `AfterFunc`. If there hasn't been activity,
+`next` might be negative.
+
+To test this in Quartz, we'll use a trap. We only want to trap the inner `Until()` call, not the
+initial one, so to make testing easier we can "tag" the call we want. Like this:
+
+```go
+func (i *InactivityTimer) Start() {
+ i.mu.Lock()
+ defer i.mu.Unlock()
+ next := i.clock.Until(i.activity.Add(10*time.Minute))
+ t := i.clock.AfterFunc(next, func() {
+ i.mu.Lock()
+ defer i.mu.Unlock()
+ next := i.clock.Until(i.activity.Add(10*time.Minute), "inner")
+ if next == 0 {
+ i.timeoutLocked()
+ return
+ }
+ t.Reset(next)
+ })
+}
+```
+
+All Quartz `Clock` functions, and functions on returned timers and tickers support zero or more
+string tags that allow traps to match on them.
+
+```go
+func TestInactivityTimer_Late(t *testing.T) {
+ // set a timeout on the test itself, so that if Wait functions get blocked, we don't have to
+ // wait for the default test timeout of 10 minutes.
+ ctx, cancel := context.WithTimeout(10*time.Second)
+ defer cancel()
+ mClock := quartz.NewMock(t)
+ trap := mClock.Trap.Until("inner")
+ defer trap.Close()
+
+ it := &InactivityTimer{
+ activity: mClock.Now(),
+ clock: mClock,
+ }
+ it.Start()
+
+ // Trigger the AfterFunc
+ w := mClock.Advance(10*time.Minute)
+ c := trap.MustWait(ctx)
+ // Advance the clock a few ms to simulate a busy system
+ mClock.Advance(3*time.Millisecond)
+ c.MustRelease(ctx) // Until() returns
+ w.MustWait(ctx) // Wait for the AfterFunc to wrap up
+
+ // Assert that the timeoutLocked() function was called
+}
+```
+
+This test case will fail with our bugged implementation, since the triggered AfterFunc won't call
+`timeoutLocked()` and instead will reset the timer with a negative number. The fix is easy, use
+`next <= 0` as the comparison.
diff --git a/vendor/github.com/coder/quartz/clock.go b/vendor/github.com/coder/quartz/clock.go
new file mode 100644
index 00000000000..729edfa5623
--- /dev/null
+++ b/vendor/github.com/coder/quartz/clock.go
@@ -0,0 +1,43 @@
+// Package quartz is a library for testing time related code. It exports an interface Clock that
+// mimics the standard library time package functions. In production, an implementation that calls
+// thru to the standard library is used. In testing, a Mock clock is used to precisely control and
+// intercept time functions.
+package quartz
+
+import (
+ "context"
+ "time"
+)
+
+type Clock interface {
+ // NewTicker returns a new Ticker containing a channel that will send the current time on the
+ // channel after each tick. The period of the ticks is specified by the duration argument. The
+ // ticker will adjust the time interval or drop ticks to make up for slow receivers. The
+ // duration d must be greater than zero; if not, NewTicker will panic. Stop the ticker to
+ // release associated resources.
+ NewTicker(d time.Duration, tags ...string) *Ticker
+ // TickerFunc is a convenience function that calls f on the interval d until either the given
+ // context expires or f returns an error. Callers may call Wait() on the returned Waiter to
+ // wait until this happens and obtain the error. The duration d must be greater than zero; if
+ // not, TickerFunc will panic.
+ TickerFunc(ctx context.Context, d time.Duration, f func() error, tags ...string) Waiter
+ // NewTimer creates a new Timer that will send the current time on its channel after at least
+ // duration d.
+ NewTimer(d time.Duration, tags ...string) *Timer
+ // AfterFunc waits for the duration to elapse and then calls f in its own goroutine. It returns
+ // a Timer that can be used to cancel the call using its Stop method. The returned Timer's C
+ // field is not used and will be nil.
+ AfterFunc(d time.Duration, f func(), tags ...string) *Timer
+
+ // Now returns the current local time.
+ Now(tags ...string) time.Time
+ // Since returns the time elapsed since t. It is shorthand for Clock.Now().Sub(t).
+ Since(t time.Time, tags ...string) time.Duration
+ // Until returns the duration until t. It is shorthand for t.Sub(Clock.Now()).
+ Until(t time.Time, tags ...string) time.Duration
+}
+
+// Waiter can be waited on for an error.
+type Waiter interface {
+ Wait(tags ...string) error
+}
diff --git a/vendor/github.com/coder/quartz/mock.go b/vendor/github.com/coder/quartz/mock.go
new file mode 100644
index 00000000000..7255aff99bd
--- /dev/null
+++ b/vendor/github.com/coder/quartz/mock.go
@@ -0,0 +1,851 @@
+package quartz
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "slices"
+ "sync"
+ "time"
+)
+
+// TestingT is the minimal interface required from a testing framework for the Mock.
+type TestingT interface {
+ Helper()
+
+ Log(...any)
+ Logf(string, ...any)
+ Error(...any)
+ Errorf(string, ...any)
+ Fatal(...any)
+ Fatalf(string, ...any)
+
+ Cleanup(func())
+}
+
+// Mock is the testing implementation of Clock. It tracks a time that monotonically increases
+// during a test, triggering any timers or tickers automatically.
+type Mock struct {
+ tb TestingT
+ logger Logger
+ mu sync.Mutex
+ testOver bool
+
+ // cur is the current time
+ cur time.Time
+
+ all []event
+ nextTime time.Time
+ nextEvents []event
+ traps []*Trap
+}
+
+type event interface {
+ next() time.Time
+ fire(t time.Time)
+}
+
+func (m *Mock) TickerFunc(ctx context.Context, d time.Duration, f func() error, tags ...string) Waiter {
+ if d <= 0 {
+ panic("TickerFunc called with negative or zero duration")
+ }
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ c := newCall(clockFunctionTickerFunc, tags, withDuration(d))
+ m.matchCallLocked(c)
+ defer close(c.complete)
+ t := &mockTickerFunc{
+ ctx: ctx,
+ d: d,
+ f: f,
+ nxt: m.cur.Add(d),
+ mock: m,
+ cond: sync.NewCond(&m.mu),
+ }
+ m.all = append(m.all, t)
+ m.recomputeNextLocked()
+ go t.waitForCtx()
+ return t
+}
+
+// NewTicker creates a mocked ticker attached to this Mock. Note that it will cease sending ticks on its channel at the
+// end of the test, to avoid leaking any goroutines. Ticks are suppressed even if the mock clock is advanced after the
+// test completes. Best practice is to only manipulate the mock time in the main goroutine of the test.
+func (m *Mock) NewTicker(d time.Duration, tags ...string) *Ticker {
+ if d <= 0 {
+ panic("NewTicker called with negative or zero duration")
+ }
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ c := newCall(clockFunctionNewTicker, tags, withDuration(d))
+ m.matchCallLocked(c)
+ defer close(c.complete)
+ return newMockTickerLocked(m, d)
+}
+
+func (m *Mock) NewTimer(d time.Duration, tags ...string) *Timer {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ c := newCall(clockFunctionNewTimer, tags, withDuration(d))
+ defer close(c.complete)
+ m.matchCallLocked(c)
+ ch := make(chan time.Time)
+ t := &Timer{
+ C: ch,
+ c: ch,
+ nxt: m.cur.Add(d),
+ mock: m,
+ }
+ if d <= 0 {
+ // zero or negative duration timer means we should immediately fire
+ // it, rather than add it.
+ go t.fire(t.mock.cur)
+ return t
+ }
+ m.addEventLocked(t)
+ return t
+}
+
+func (m *Mock) AfterFunc(d time.Duration, f func(), tags ...string) *Timer {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ c := newCall(clockFunctionAfterFunc, tags, withDuration(d))
+ defer close(c.complete)
+ m.matchCallLocked(c)
+ t := &Timer{
+ nxt: m.cur.Add(d),
+ fn: f,
+ mock: m,
+ }
+ if d <= 0 {
+ // zero or negative duration timer means we should immediately fire
+ // it, rather than add it.
+ go t.fire(t.mock.cur)
+ return t
+ }
+ m.addEventLocked(t)
+ return t
+}
+
+func (m *Mock) Now(tags ...string) time.Time {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ c := newCall(clockFunctionNow, tags)
+ defer close(c.complete)
+ m.matchCallLocked(c)
+ return m.cur
+}
+
+func (m *Mock) Since(t time.Time, tags ...string) time.Duration {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ c := newCall(clockFunctionSince, tags, withTime(t))
+ defer close(c.complete)
+ m.matchCallLocked(c)
+ return m.cur.Sub(t)
+}
+
+func (m *Mock) Until(t time.Time, tags ...string) time.Duration {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ c := newCall(clockFunctionUntil, tags, withTime(t))
+ defer close(c.complete)
+ m.matchCallLocked(c)
+ return t.Sub(m.cur)
+}
+
+func (m *Mock) addEventLocked(e event) {
+ m.all = append(m.all, e)
+ m.recomputeNextLocked()
+}
+
+func (m *Mock) recomputeNextLocked() {
+ var best time.Time
+ var events []event
+ for _, e := range m.all {
+ if best.IsZero() || e.next().Before(best) {
+ best = e.next()
+ events = []event{e}
+ continue
+ }
+ if e.next().Equal(best) {
+ events = append(events, e)
+ continue
+ }
+ }
+ m.nextTime = best
+ m.nextEvents = events
+}
+
+func (m *Mock) removeTimer(t *Timer) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ m.removeTimerLocked(t)
+}
+
+func (m *Mock) removeTimerLocked(t *Timer) {
+ t.stopped = true
+ m.removeEventLocked(t)
+}
+
+func (m *Mock) removeEventLocked(e event) {
+ defer m.recomputeNextLocked()
+ for i := range m.all {
+ if m.all[i] == e {
+ m.all = append(m.all[:i], m.all[i+1:]...)
+ return
+ }
+ }
+}
+
+func (m *Mock) matchCallLocked(c *apiCall) {
+ var traps []*Trap
+ for _, t := range m.traps {
+ if t.matches(c) {
+ traps = append(traps, t)
+ }
+ }
+ if !m.testOver {
+ m.logger.Logf("Mock Clock - %s call, matched %d traps", c, len(traps))
+ }
+ if len(traps) == 0 {
+ return
+ }
+ c.releases.Add(len(traps))
+ m.mu.Unlock()
+ for _, t := range traps {
+ go t.catch(c)
+ }
+ c.releases.Wait()
+ m.mu.Lock()
+}
+
+// AdvanceWaiter is returned from Advance and Set calls and allows you to wait for ticks and timers
+// to complete. In the case of functions passed to AfterFunc or TickerFunc, it waits for the
+// functions to return. For other ticks & timers, it just waits for the tick to be delivered to
+// the channel.
+//
+// If multiple timers or tickers trigger simultaneously, they are all run on separate
+// go routines.
+type AdvanceWaiter struct {
+ tb TestingT
+ ch chan struct{}
+}
+
+// Wait for all timers and ticks to complete, or until context expires.
+func (w AdvanceWaiter) Wait(ctx context.Context) error {
+ select {
+ case <-w.ch:
+ return nil
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+}
+
+// MustWait waits for all timers and ticks to complete, and fails the test immediately if the
+// context completes first. MustWait must be called from the goroutine running the test or
+// benchmark, similar to `t.FailNow()`.
+func (w AdvanceWaiter) MustWait(ctx context.Context) {
+ w.tb.Helper()
+ select {
+ case <-w.ch:
+ return
+ case <-ctx.Done():
+ w.tb.Fatalf("context expired while waiting for clock to advance: %s", ctx.Err())
+ }
+}
+
+// Done returns a channel that is closed when all timers and ticks complete.
+func (w AdvanceWaiter) Done() <-chan struct{} {
+ return w.ch
+}
+
+// Advance moves the clock forward by d, triggering any timers or tickers. The returned value can
+// be used to wait for all timers and ticks to complete. Advance sets the clock forward before
+// returning, and can only advance up to the next timer or tick event. It will fail the test if you
+// attempt to advance beyond.
+//
+// If you need to advance exactly to the next event, and don't know or don't wish to calculate it,
+// consider AdvanceNext().
+func (m *Mock) Advance(d time.Duration) AdvanceWaiter {
+ m.tb.Helper()
+ w := AdvanceWaiter{tb: m.tb, ch: make(chan struct{})}
+ m.mu.Lock()
+ if !m.testOver {
+ m.logger.Logf("Mock Clock - Advance(%s)", d)
+ }
+ fin := m.cur.Add(d)
+ // nextTime.IsZero implies no events scheduled.
+ if m.nextTime.IsZero() || fin.Before(m.nextTime) {
+ m.cur = fin
+ m.mu.Unlock()
+ close(w.ch)
+ return w
+ }
+ if fin.After(m.nextTime) {
+ m.tb.Errorf("cannot advance %s which is beyond next timer/ticker event in %s",
+ d.String(), m.nextTime.Sub(m.cur))
+ m.mu.Unlock()
+ close(w.ch)
+ return w
+ }
+
+ m.cur = m.nextTime
+ go m.advanceLocked(w)
+ return w
+}
+
+func (m *Mock) advanceLocked(w AdvanceWaiter) {
+ defer close(w.ch)
+ wg := sync.WaitGroup{}
+ for i := range m.nextEvents {
+ e := m.nextEvents[i]
+ t := m.cur
+ wg.Add(1)
+ go func() {
+ e.fire(t)
+ wg.Done()
+ }()
+ }
+ // release the lock and let the events resolve. This allows them to call back into the
+ // Mock to query the time or set new timers. Each event should remove or reschedule
+ // itself from nextEvents.
+ m.mu.Unlock()
+ wg.Wait()
+}
+
+// Set the time to t. If the time is after the current mocked time, then this is equivalent to
+// Advance() with the difference. You may only Set the time earlier than the current time before
+// starting tickers and timers (e.g. at the start of your test case).
+func (m *Mock) Set(t time.Time) AdvanceWaiter {
+ m.tb.Helper()
+ w := AdvanceWaiter{tb: m.tb, ch: make(chan struct{})}
+ m.mu.Lock()
+ if !m.testOver {
+ m.logger.Logf("Mock Clock - Set(%s)", t)
+ }
+ if t.Before(m.cur) {
+ defer close(w.ch)
+ defer m.mu.Unlock()
+ // past
+ if !m.nextTime.IsZero() {
+ m.tb.Error("Set mock clock to the past after timers/tickers started")
+ }
+ m.cur = t
+ return w
+ }
+ // future
+ // nextTime.IsZero implies no events scheduled.
+ if m.nextTime.IsZero() || t.Before(m.nextTime) {
+ defer close(w.ch)
+ defer m.mu.Unlock()
+ m.cur = t
+ return w
+ }
+ if t.After(m.nextTime) {
+ defer close(w.ch)
+ defer m.mu.Unlock()
+ m.tb.Errorf("cannot Set time to %s which is beyond next timer/ticker event at %s",
+ t.String(), m.nextTime)
+ return w
+ }
+
+ m.cur = m.nextTime
+ go m.advanceLocked(w)
+ return w
+}
+
+// AdvanceNext advances the clock to the next timer or tick event. It fails the test if there are
+// none scheduled. It returns the duration the clock was advanced and a waiter that can be used to
+// wait for the timer/tick event(s) to finish.
+func (m *Mock) AdvanceNext() (time.Duration, AdvanceWaiter) {
+ m.mu.Lock()
+ if !m.testOver {
+ m.logger.Logf("Mock Clock - AdvanceNext()")
+ }
+ m.tb.Helper()
+ w := AdvanceWaiter{tb: m.tb, ch: make(chan struct{})}
+ if m.nextTime.IsZero() {
+ defer close(w.ch)
+ defer m.mu.Unlock()
+ m.tb.Error("cannot AdvanceNext because there are no timers or tickers running")
+ return 0, w
+ }
+ d := m.nextTime.Sub(m.cur)
+ m.cur = m.nextTime
+ go m.advanceLocked(w)
+ return d, w
+}
+
+// Peek returns the duration until the next ticker or timer event and the value
+// true, or, if there are no running tickers or timers, it returns zero and
+// false.
+func (m *Mock) Peek() (d time.Duration, ok bool) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.nextTime.IsZero() {
+ return 0, false
+ }
+ return m.nextTime.Sub(m.cur), true
+}
+
+// Trapper allows the creation of Traps
+type Trapper struct {
+ // mock is the underlying Mock. This is a thin wrapper around Mock so that
+ // we can have our interface look like mClock.Trap().NewTimer("foo")
+ mock *Mock
+}
+
+func (t Trapper) NewTimer(tags ...string) *Trap {
+ return t.mock.newTrap(clockFunctionNewTimer, tags)
+}
+
+func (t Trapper) AfterFunc(tags ...string) *Trap {
+ return t.mock.newTrap(clockFunctionAfterFunc, tags)
+}
+
+func (t Trapper) TimerStop(tags ...string) *Trap {
+ return t.mock.newTrap(clockFunctionTimerStop, tags)
+}
+
+func (t Trapper) TimerReset(tags ...string) *Trap {
+ return t.mock.newTrap(clockFunctionTimerReset, tags)
+}
+
+func (t Trapper) TickerFunc(tags ...string) *Trap {
+ return t.mock.newTrap(clockFunctionTickerFunc, tags)
+}
+
+func (t Trapper) TickerFuncWait(tags ...string) *Trap {
+ return t.mock.newTrap(clockFunctionTickerFuncWait, tags)
+}
+
+func (t Trapper) NewTicker(tags ...string) *Trap {
+ return t.mock.newTrap(clockFunctionNewTicker, tags)
+}
+
+func (t Trapper) TickerStop(tags ...string) *Trap {
+ return t.mock.newTrap(clockFunctionTickerStop, tags)
+}
+
+func (t Trapper) TickerReset(tags ...string) *Trap {
+ return t.mock.newTrap(clockFunctionTickerReset, tags)
+}
+
+func (t Trapper) Now(tags ...string) *Trap {
+ return t.mock.newTrap(clockFunctionNow, tags)
+}
+
+func (t Trapper) Since(tags ...string) *Trap {
+ return t.mock.newTrap(clockFunctionSince, tags)
+}
+
+func (t Trapper) Until(tags ...string) *Trap {
+ return t.mock.newTrap(clockFunctionUntil, tags)
+}
+
+func (m *Mock) Trap() Trapper {
+ return Trapper{m}
+}
+
+func (m *Mock) newTrap(fn clockFunction, tags []string) *Trap {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if !m.testOver {
+ m.logger.Logf("Mock Clock - Trap %s(..., %v)", fn, tags)
+ }
+ tr := &Trap{
+ fn: fn,
+ tags: tags,
+ mock: m,
+ calls: make(chan *apiCall),
+ done: make(chan struct{}),
+ }
+ m.traps = append(m.traps, tr)
+ return tr
+}
+
+// WithLogger replaces the default testing logger with a custom one.
+//
+// This can be used to discard log messages with:
+//
+// quartz.NewMock(t).WithLogger(quartz.NoOpLogger)
+func (m *Mock) WithLogger(l Logger) *Mock {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ m.logger = l
+ return m
+}
+
+// NewMock creates a new Mock with the time set to midnight UTC on Jan 1, 2024.
+// You may re-set the time earlier than this, but only before timers or tickers
+// are created.
+func NewMock(tb TestingT) *Mock {
+ cur, err := time.Parse(time.RFC3339, "2024-01-01T00:00:00Z")
+ if err != nil {
+ panic(err)
+ }
+ m := &Mock{
+ tb: tb,
+ logger: tb,
+ cur: cur,
+ }
+ tb.Cleanup(func() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ m.testOver = true
+ m.logger.Logf("Mock Clock - test cleanup; will no longer log clock events")
+ })
+ return m
+}
+
+var _ Clock = &Mock{}
+
+type mockTickerFunc struct {
+ ctx context.Context
+ d time.Duration
+ f func() error
+ nxt time.Time
+ mock *Mock
+
+ // cond is a condition Locked on the main Mock.mu
+ cond *sync.Cond
+ // inProgress is true when we are actively calling f
+ inProgress bool
+ // done is true when the ticker exits
+ done bool
+ // err holds the error when the ticker exits
+ err error
+}
+
+func (m *mockTickerFunc) next() time.Time {
+ return m.nxt
+}
+
+func (m *mockTickerFunc) fire(_ time.Time) {
+ m.mock.mu.Lock()
+ if m.done {
+ m.mock.mu.Unlock()
+ return
+ }
+ m.nxt = m.nxt.Add(m.d)
+ m.mock.recomputeNextLocked()
+ // we need this check to happen after we've computed the next tick,
+ // otherwise it will be immediately rescheduled.
+ if m.inProgress {
+ m.mock.mu.Unlock()
+ return
+ }
+
+ m.inProgress = true
+ m.mock.mu.Unlock()
+ err := m.f()
+ m.mock.mu.Lock()
+ defer m.mock.mu.Unlock()
+ m.inProgress = false
+ m.cond.Broadcast() // wake up anything waiting for f to finish
+ if err != nil {
+ m.exitLocked(err)
+ }
+}
+
+func (m *mockTickerFunc) exitLocked(err error) {
+ if m.done {
+ return
+ }
+ m.done = true
+ m.err = err
+ m.mock.removeEventLocked(m)
+ m.cond.Broadcast()
+}
+
+func (m *mockTickerFunc) waitForCtx() {
+ <-m.ctx.Done()
+ m.mock.mu.Lock()
+ defer m.mock.mu.Unlock()
+ for m.inProgress {
+ m.cond.Wait()
+ }
+ m.exitLocked(m.ctx.Err())
+}
+
+func (m *mockTickerFunc) Wait(tags ...string) error {
+ m.mock.mu.Lock()
+ defer m.mock.mu.Unlock()
+ c := newCall(clockFunctionTickerFuncWait, tags)
+ m.mock.matchCallLocked(c)
+ defer close(c.complete)
+ for !m.done {
+ m.cond.Wait()
+ }
+ return m.err
+}
+
+var _ Waiter = &mockTickerFunc{}
+
+type clockFunction int
+
+const (
+ clockFunctionNewTimer clockFunction = iota
+ clockFunctionAfterFunc
+ clockFunctionTimerStop
+ clockFunctionTimerReset
+ clockFunctionTickerFunc
+ clockFunctionTickerFuncWait
+ clockFunctionNewTicker
+ clockFunctionTickerReset
+ clockFunctionTickerStop
+ clockFunctionNow
+ clockFunctionSince
+ clockFunctionUntil
+)
+
+func (c clockFunction) String() string {
+ switch c {
+ case clockFunctionNewTimer:
+ return "NewTimer"
+ case clockFunctionAfterFunc:
+ return "AfterFunc"
+ case clockFunctionTimerStop:
+ return "Timer.Stop"
+ case clockFunctionTimerReset:
+ return "Timer.Reset"
+ case clockFunctionTickerFunc:
+ return "TickerFunc"
+ case clockFunctionTickerFuncWait:
+ return "TickerFunc.Wait"
+ case clockFunctionNewTicker:
+ return "NewTicker"
+ case clockFunctionTickerReset:
+ return "Ticker.Reset"
+ case clockFunctionTickerStop:
+ return "Ticker.Stop"
+ case clockFunctionNow:
+ return "Now"
+ case clockFunctionSince:
+ return "Since"
+ case clockFunctionUntil:
+ return "Until"
+ default:
+ return fmt.Sprintf("Unknown clockFunction(%d)", c)
+ }
+}
+
+type callArg func(c *apiCall)
+
+// apiCall represents a single call to one of the Clock APIs.
+type apiCall struct {
+ Time time.Time
+ Duration time.Duration
+ Tags []string
+
+ fn clockFunction
+ releases sync.WaitGroup
+ complete chan struct{}
+}
+
+func (a *apiCall) String() string {
+ switch a.fn {
+ case clockFunctionNewTimer:
+ return fmt.Sprintf("NewTimer(%s, %v)", a.Duration, a.Tags)
+ case clockFunctionAfterFunc:
+ return fmt.Sprintf("AfterFunc(%s, , %v)", a.Duration, a.Tags)
+ case clockFunctionTimerStop:
+ return fmt.Sprintf("Timer.Stop(%v)", a.Tags)
+ case clockFunctionTimerReset:
+ return fmt.Sprintf("Timer.Reset(%s, %v)", a.Duration, a.Tags)
+ case clockFunctionTickerFunc:
+ return fmt.Sprintf("TickerFunc(, %s, , %s)", a.Duration, a.Tags)
+ case clockFunctionTickerFuncWait:
+ return fmt.Sprintf("TickerFunc.Wait(%v)", a.Tags)
+ case clockFunctionNewTicker:
+ return fmt.Sprintf("NewTicker(%s, %v)", a.Duration, a.Tags)
+ case clockFunctionTickerReset:
+ return fmt.Sprintf("Ticker.Reset(%s, %v)", a.Duration, a.Tags)
+ case clockFunctionTickerStop:
+ return fmt.Sprintf("Ticker.Stop(%v)", a.Tags)
+ case clockFunctionNow:
+ return fmt.Sprintf("Now(%v)", a.Tags)
+ case clockFunctionSince:
+ return fmt.Sprintf("Since(%s, %v)", a.Time, a.Tags)
+ case clockFunctionUntil:
+ return fmt.Sprintf("Until(%s, %v)", a.Time, a.Tags)
+ default:
+ return fmt.Sprintf("Unknown clockFunction(%d)", a.fn)
+ }
+}
+
+// Call represents an apiCall that has been trapped.
+type Call struct {
+ Time time.Time
+ Duration time.Duration
+ Tags []string
+
+ tb TestingT
+ apiCall *apiCall
+ trap *Trap
+}
+
+// Release the call and wait for it to complete. If the provided context expires before the call completes, it returns
+// an error.
+//
+// IMPORTANT: If a call is trapped by more than one trap, they all must release the call before it can complete, and
+// they must do so from different goroutines.
+func (c *Call) Release(ctx context.Context) error {
+ c.apiCall.releases.Done()
+ select {
+ case <-ctx.Done():
+ return fmt.Errorf("timed out waiting for release; did more than one trap capture the call?: %w", ctx.Err())
+ case <-c.apiCall.complete:
+ // OK
+ }
+ c.trap.callReleased()
+ return nil
+}
+
+// MustRelease releases the call and waits for it to complete. If the provided context expires before the call
+// completes, it fails the test.
+//
+// IMPORTANT: If a call is trapped by more than one trap, they all must release the call before it can complete, and
+// they must do so from different goroutines.
+func (c *Call) MustRelease(ctx context.Context) {
+ if err := c.Release(ctx); err != nil {
+ c.tb.Helper()
+ c.tb.Fatal(err.Error())
+ }
+}
+
+func withTime(t time.Time) callArg {
+ return func(c *apiCall) {
+ c.Time = t
+ }
+}
+
+func withDuration(d time.Duration) callArg {
+ return func(c *apiCall) {
+ c.Duration = d
+ }
+}
+
+func newCall(fn clockFunction, tags []string, args ...callArg) *apiCall {
+ c := &apiCall{
+ fn: fn,
+ Tags: tags,
+ complete: make(chan struct{}),
+ }
+ for _, a := range args {
+ a(c)
+ }
+ return c
+}
+
+type Trap struct {
+ fn clockFunction
+ tags []string
+ mock *Mock
+ calls chan *apiCall
+ done chan struct{}
+
+ // mu protects the unreleasedCalls count
+ mu sync.Mutex
+ unreleasedCalls int
+}
+
+func (t *Trap) String() string {
+ return fmt.Sprintf("Trap %s(..., %v)", t.fn.String(), t.tags)
+}
+
+func (t *Trap) catch(c *apiCall) {
+ select {
+ case t.calls <- c:
+ case <-t.done:
+ c.releases.Done()
+ }
+}
+
+func (t *Trap) matches(c *apiCall) bool {
+ if t.fn != c.fn {
+ return false
+ }
+ for _, tag := range t.tags {
+ if !slices.Contains(c.Tags, tag) {
+ return false
+ }
+ }
+ return true
+}
+
+func (t *Trap) Close() {
+ t.mock.mu.Lock()
+ defer t.mock.mu.Unlock()
+ select {
+ case <-t.done:
+ t.mock.tb.Logf("%s already Closed()", t)
+ return // already closed
+ default:
+ }
+ if t.unreleasedCalls != 0 {
+ t.mock.tb.Helper()
+ t.mock.tb.Errorf("%s Closed() with %d unreleased calls", t, t.unreleasedCalls)
+ }
+ for i, tr := range t.mock.traps {
+ if t == tr {
+ t.mock.traps = append(t.mock.traps[:i], t.mock.traps[i+1:]...)
+ }
+ }
+ close(t.done)
+}
+
+func (t *Trap) callReleased() {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ t.unreleasedCalls--
+}
+
+var ErrTrapClosed = errors.New("trap closed")
+
+func (t *Trap) Wait(ctx context.Context) (*Call, error) {
+ select {
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ case <-t.done:
+ return nil, ErrTrapClosed
+ case a := <-t.calls:
+ c := &Call{
+ Time: a.Time,
+ Duration: a.Duration,
+ Tags: a.Tags,
+ apiCall: a,
+ trap: t,
+ tb: t.mock.tb,
+ }
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ t.unreleasedCalls++
+ return c, nil
+ }
+}
+
+// MustWait calls Wait() and then if there is an error, immediately fails the
+// test via tb.Fatalf()
+func (t *Trap) MustWait(ctx context.Context) *Call {
+ t.mock.tb.Helper()
+ c, err := t.Wait(ctx)
+ if err != nil {
+ t.mock.tb.Fatalf("context expired while waiting for %s: %s", t, err.Error())
+ }
+ return c
+}
+
+type Logger interface {
+ Log(args ...any)
+ Logf(format string, args ...any)
+}
+
+// NoOpLogger is a Logger that discards all log messages.
+var NoOpLogger Logger = noOpLogger{}
+
+type noOpLogger struct{}
+
+func (noOpLogger) Log(args ...any) {}
+func (noOpLogger) Logf(format string, args ...any) {}
diff --git a/vendor/github.com/coder/quartz/real.go b/vendor/github.com/coder/quartz/real.go
new file mode 100644
index 00000000000..f39fb1163e8
--- /dev/null
+++ b/vendor/github.com/coder/quartz/real.go
@@ -0,0 +1,80 @@
+package quartz
+
+import (
+ "context"
+ "time"
+)
+
+type realClock struct{}
+
+func NewReal() Clock {
+ return realClock{}
+}
+
+func (realClock) NewTicker(d time.Duration, _ ...string) *Ticker {
+ tkr := time.NewTicker(d)
+ return &Ticker{ticker: tkr, C: tkr.C}
+}
+
+func (realClock) TickerFunc(ctx context.Context, d time.Duration, f func() error, _ ...string) Waiter {
+ ct := &realContextTicker{
+ ctx: ctx,
+ tkr: time.NewTicker(d),
+ f: f,
+ err: make(chan error, 1),
+ }
+ go ct.run()
+ return ct
+}
+
+type realContextTicker struct {
+ ctx context.Context
+ tkr *time.Ticker
+ f func() error
+ err chan error
+}
+
+func (t *realContextTicker) Wait(_ ...string) error {
+ return <-t.err
+}
+
+func (t *realContextTicker) run() {
+ defer t.tkr.Stop()
+ for {
+ select {
+ case <-t.ctx.Done():
+ t.err <- t.ctx.Err()
+ return
+ case <-t.tkr.C:
+ err := t.f()
+ if err != nil {
+ t.err <- err
+ return
+ }
+ }
+ }
+}
+
+func (realClock) NewTimer(d time.Duration, _ ...string) *Timer {
+ rt := time.NewTimer(d)
+ return &Timer{C: rt.C, timer: rt}
+}
+
+func (realClock) AfterFunc(d time.Duration, f func(), _ ...string) *Timer {
+ rt := time.AfterFunc(d, f)
+ return &Timer{C: rt.C, timer: rt}
+}
+
+func (realClock) Now(_ ...string) time.Time {
+ return time.Now()
+}
+
+func (realClock) Since(t time.Time, _ ...string) time.Duration {
+ return time.Since(t)
+}
+
+func (realClock) Until(t time.Time, _ ...string) time.Duration {
+ return time.Until(t)
+}
+
+var _ Clock = realClock{}
diff --git a/vendor/github.com/coder/quartz/ticker.go b/vendor/github.com/coder/quartz/ticker.go
new file mode 100644
index 00000000000..f4a4b066502
--- /dev/null
+++ b/vendor/github.com/coder/quartz/ticker.go
@@ -0,0 +1,151 @@
+package quartz
+
+import "time"
+
+// A Ticker holds a channel that delivers “ticks” of a clock at intervals.
+type Ticker struct {
+ C <-chan time.Time
+ //nolint: revive
+ c chan time.Time
+ ticker *time.Ticker // realtime impl, if set
+ d time.Duration // period, if set
+ nxt time.Time // next tick time
+ mock *Mock // mock clock, if set
+ stopped bool // true if the ticker is not running
+ internalTicks chan time.Time // used to deliver ticks to the runLoop goroutine
+
+ // As of Go 1.23, ticker channels are unbuffered and guaranteed to block forever after a call to stop.
+ //
+ // When a mocked ticker fires, we don't want to block on a channel write, because it's fine for the code under test
+ // not to be reading. That means we need to start a new goroutine to do the channel write (runLoop) if we are a
+ // channel-based ticker.
+ //
+ // They also are not supposed to leak even if they are never read or stopped (Go runtime can garbage collect them).
+ // We can't garbage-collect because we can't check if any other code besides the mock references, but we can ensure
+ // that we don't leak goroutines so that the garbage collector can do its job when the mock is no longer
+ // referenced. The channels below allow us to interrupt the runLoop goroutine.
+ interrupt chan struct{}
+}
+
+func (t *Ticker) fire(tt time.Time) {
+ t.mock.mu.Lock()
+ defer t.mock.mu.Unlock()
+ if t.stopped {
+ return
+ }
+ for !t.nxt.After(t.mock.cur) {
+ t.nxt = t.nxt.Add(t.d)
+ }
+ t.mock.recomputeNextLocked()
+ if t.interrupt != nil { // implies runLoop is still going.
+ t.internalTicks <- tt
+ }
+}
+
+func (t *Ticker) next() time.Time {
+ return t.nxt
+}
+
+// Stop turns off a ticker. After Stop, no more ticks will be sent. Stop does
+// not close the channel, to prevent a concurrent goroutine reading from the
+// channel from seeing an erroneous "tick".
+func (t *Ticker) Stop(tags ...string) {
+ if t.ticker != nil {
+ t.ticker.Stop()
+ return
+ }
+ t.mock.mu.Lock()
+ defer t.mock.mu.Unlock()
+ c := newCall(clockFunctionTickerStop, tags)
+ t.mock.matchCallLocked(c)
+ defer close(c.complete)
+ t.mock.removeEventLocked(t)
+ t.stopped = true
+ // check if we've already fired, and if so, interrupt it.
+ if t.interrupt != nil {
+ <-t.interrupt
+ t.interrupt = nil
+ }
+}
+
+// Reset stops a ticker and resets its period to the specified duration. The
+// next tick will arrive after the new period elapses. The duration d must be
+// greater than zero; if not, Reset will panic.
+func (t *Ticker) Reset(d time.Duration, tags ...string) {
+ if t.ticker != nil {
+ t.ticker.Reset(d)
+ return
+ }
+ t.mock.mu.Lock()
+ defer t.mock.mu.Unlock()
+ c := newCall(clockFunctionTickerReset, tags, withDuration(d))
+ t.mock.matchCallLocked(c)
+ defer close(c.complete)
+ t.nxt = t.mock.cur.Add(d)
+ t.d = d
+ if t.stopped {
+ t.stopped = false
+ t.mock.addEventLocked(t)
+ } else {
+ t.mock.recomputeNextLocked()
+ }
+ if t.interrupt == nil {
+ t.startRunLoopLocked()
+ }
+}
+
+func (t *Ticker) runLoop(interrupt chan struct{}) {
+ defer close(interrupt)
+outer:
+ for {
+ select {
+ case tt := <-t.internalTicks:
+ for {
+ select {
+ case t.c <- tt:
+ continue outer
+ case <-t.internalTicks:
+ // Discard future ticks until we can send this one.
+ case interrupt <- struct{}{}:
+ return
+ }
+ }
+ case interrupt <- struct{}{}:
+ return
+ }
+ }
+}
+
+func (t *Ticker) startRunLoopLocked() {
+ // assert some assumptions. If these fire, it is a bug in Quartz itself.
+ if t.interrupt != nil {
+ t.mock.tb.Error("called startRunLoopLocked when interrupt suggests we are already running")
+ }
+ interrupt := make(chan struct{})
+ t.interrupt = interrupt
+ go t.runLoop(interrupt)
+}
+
+func newMockTickerLocked(m *Mock, d time.Duration) *Ticker {
+ // no buffer follows Go 1.23+ behavior
+ ticks := make(chan time.Time)
+ t := &Ticker{
+ C: ticks,
+ c: ticks,
+ d: d,
+ nxt: m.cur.Add(d),
+ mock: m,
+ internalTicks: make(chan time.Time),
+ }
+ m.addEventLocked(t)
+ m.tb.Cleanup(func() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if t.interrupt != nil {
+ <-t.interrupt
+ t.interrupt = nil
+ }
+ })
+ t.startRunLoopLocked()
+ return t
+}
diff --git a/vendor/github.com/coder/quartz/timer.go b/vendor/github.com/coder/quartz/timer.go
new file mode 100644
index 00000000000..8f571eb0dc6
--- /dev/null
+++ b/vendor/github.com/coder/quartz/timer.go
@@ -0,0 +1,118 @@
+package quartz
+
+import (
+ "time"
+)
+
+// The Timer type represents a single event. When the Timer expires, the current time will be sent
+// on C, unless the Timer was created by AfterFunc. A Timer must be created with NewTimer or
+// AfterFunc.
+type Timer struct {
+ C <-chan time.Time
+ //nolint: revive
+ c chan time.Time
+ timer *time.Timer // realtime impl, if set
+ nxt time.Time // next tick time
+ mock *Mock // mock clock, if set
+ fn func() // AfterFunc function, if set
+ stopped bool // True if stopped, false if running
+
+ // As of Go 1.23, timer channels are unbuffered and guaranteed to block forever after a call to stop.
+ //
+ // When a mocked timer fires, we don't want to block on a channel write, because it's fine for the code under test
+ // not to be reading. That means we need to start a new goroutine to do the channel write if we are a channel-based
+ // timer.
+ //
+ // They also are not supposed to leak even if they are never read or stopped (Go runtime can garbage collect them).
+ // We can't garbage-collect because we can't check if any other code besides the mock references, but we can ensure
+ // that we don't leak goroutines so that the garbage collector can do its job when the mock is no longer
+ // referenced. The channels below allow us to interrupt the channel write goroutine.
+ interrupt chan struct{}
+}
+
+func (t *Timer) fire(tt time.Time) {
+ t.mock.mu.Lock()
+ t.mock.removeTimerLocked(t)
+ if t.fn != nil {
+ t.mock.mu.Unlock()
+ t.fn()
+ return
+ } else {
+ interrupt := make(chan struct{})
+ // Prevents the goroutine from leaking beyond the test. Side effect is that timer channels cannot be read
+ // after the test exits.
+ t.mock.tb.Cleanup(func() {
+ <-interrupt
+ })
+ t.interrupt = interrupt
+ t.mock.mu.Unlock()
+ go func() {
+ defer close(interrupt)
+ select {
+ case t.c <- tt:
+ case interrupt <- struct{}{}:
+ }
+ }()
+ }
+}
+
+func (t *Timer) next() time.Time {
+ return t.nxt
+}
+
+// Stop prevents the Timer from firing. It returns true if the call stops the timer, false if the
+// timer has already expired or been stopped. Stop does not close the channel, to prevent a read
+// from the channel succeeding incorrectly.
+//
+// See https://pkg.go.dev/time#Timer.Stop for more information.
+func (t *Timer) Stop(tags ...string) bool {
+ if t.timer != nil {
+ return t.timer.Stop()
+ }
+ t.mock.mu.Lock()
+ defer t.mock.mu.Unlock()
+ c := newCall(clockFunctionTimerStop, tags)
+ t.mock.matchCallLocked(c)
+ defer close(c.complete)
+ result := !t.stopped
+ t.mock.removeTimerLocked(t)
+ // check if we've already fired, and if so, interrupt it.
+ if t.interrupt != nil {
+ <-t.interrupt
+ t.interrupt = nil
+ }
+ return result
+}
+
+// Reset changes the timer to expire after duration d. It returns true if the timer had been active,
+// false if the timer had expired or been stopped.
+//
+// See https://pkg.go.dev/time#Timer.Reset for more information.
+func (t *Timer) Reset(d time.Duration, tags ...string) bool {
+ if t.timer != nil {
+ return t.timer.Reset(d)
+ }
+ t.mock.mu.Lock()
+ defer t.mock.mu.Unlock()
+ c := newCall(clockFunctionTimerReset, tags, withDuration(d))
+ t.mock.matchCallLocked(c)
+ defer close(c.complete)
+ result := !t.stopped
+ // check if we've already fired, and if so, interrupt it.
+ if t.interrupt != nil {
+ <-t.interrupt
+ t.interrupt = nil
+ }
+ if d <= 0 {
+ // zero or negative duration timer means we should immediately re-fire
+ // it, rather than remove and re-add it.
+ t.stopped = false
+ go t.fire(t.mock.cur)
+ return result
+ }
+ t.mock.removeTimerLocked(t)
+ t.stopped = false
+ t.nxt = t.mock.cur.Add(d)
+ t.mock.addEventLocked(t)
+ return result
+}
diff --git a/vendor/github.com/edsrzf/mmap-go/mmap_unix.go b/vendor/github.com/edsrzf/mmap-go/mmap_unix.go
index 25b13e51fdf..0f956faff92 100644
--- a/vendor/github.com/edsrzf/mmap-go/mmap_unix.go
+++ b/vendor/github.com/edsrzf/mmap-go/mmap_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux openbsd solaris netbsd
+// +build darwin dragonfly freebsd linux openbsd solaris netbsd aix
package mmap
diff --git a/vendor/github.com/felixge/httpsnoop/capture_metrics.go b/vendor/github.com/felixge/httpsnoop/capture_metrics.go
index bec7b71b39c..97f0a51de31 100644
--- a/vendor/github.com/felixge/httpsnoop/capture_metrics.go
+++ b/vendor/github.com/felixge/httpsnoop/capture_metrics.go
@@ -69,6 +69,16 @@ func (m *Metrics) CaptureMetrics(w http.ResponseWriter, fn func(http.ResponseWri
}
},
+ WriteString: func(next WriteStringFunc) WriteStringFunc {
+ return func(s string) (int, error) {
+ n, err := next(s)
+
+ m.Written += int64(n)
+ headerWritten = true
+ return n, err
+ }
+ },
+
ReadFrom: func(next ReadFromFunc) ReadFromFunc {
return func(src io.Reader) (int64, error) {
n, err := next(src)
@@ -81,6 +91,31 @@ func (m *Metrics) CaptureMetrics(w http.ResponseWriter, fn func(http.ResponseWri
}
)
+ // defer to ensure duration is updated even if the handler panics
+ defer func() {
+ m.Duration += time.Since(start)
+ }()
fn(Wrap(w, hooks))
- m.Duration += time.Since(start)
+}
+
+// deadliner defines two methods introduced in go 1.20. The standard library
+// seems not to provide an interface we can import, hence its definition here.
+type deadliner interface {
+ SetReadDeadline(deadline time.Time) error
+ SetWriteDeadline(deadline time.Time) error
+}
+
+// fullDuplexEnabler defines a method introduced in go 1.21. The standard
+// library seems not to provide an interface we can import, hence its definition
+// here.
+type fullDuplexEnabler interface {
+ EnableFullDuplex() error
+}
+
+// httpFlushError defines a method introduced in go 1.20. The standard
+// library seems not to provide an interface we can import, hence its definition
+// here.
+// See https://github.com/golang/go/blob/go1.20/src/net/http/responsecontroller.go#L50
+type httpFlushError interface {
+ FlushError() error
}
diff --git a/vendor/github.com/felixge/httpsnoop/wrap_generated.go b/vendor/github.com/felixge/httpsnoop/wrap_generated.go
new file mode 100644
index 00000000000..b6549ba982b
--- /dev/null
+++ b/vendor/github.com/felixge/httpsnoop/wrap_generated.go
@@ -0,0 +1,16179 @@
+// Code generated by "httpsnoop/codegen"; DO NOT EDIT.
+
+package httpsnoop
+
+import (
+ "bufio"
+ "io"
+ "net"
+ "net/http"
+ "time"
+)
+
+// HeaderFunc is part of the http.ResponseWriter interface.
+type HeaderFunc func() http.Header
+
+// WriteHeaderFunc is part of the http.ResponseWriter interface.
+type WriteHeaderFunc func(code int)
+
+// WriteFunc is part of the http.ResponseWriter interface.
+type WriteFunc func(b []byte) (int, error)
+
+// FlushFunc is part of the http.Flusher interface.
+type FlushFunc func()
+
+// FlushErrorFunc is part of the httpFlushError interface.
+type FlushErrorFunc func() error
+
+// CloseNotifyFunc is part of the http.CloseNotifier interface.
+type CloseNotifyFunc func() <-chan bool
+
+// HijackFunc is part of the http.Hijacker interface.
+type HijackFunc func() (net.Conn, *bufio.ReadWriter, error)
+
+// ReadFromFunc is part of the io.ReaderFrom interface.
+type ReadFromFunc func(src io.Reader) (int64, error)
+
+// SetReadDeadlineFunc is part of the deadliner interface.
+type SetReadDeadlineFunc func(deadline time.Time) error
+
+// SetWriteDeadlineFunc is part of the deadliner interface.
+type SetWriteDeadlineFunc func(deadline time.Time) error
+
+// EnableFullDuplexFunc is part of the fullDuplexEnabler interface.
+type EnableFullDuplexFunc func() error
+
+// PushFunc is part of the http.Pusher interface.
+type PushFunc func(target string, opts *http.PushOptions) error
+
+// WriteStringFunc is part of the io.StringWriter interface.
+type WriteStringFunc func(s string) (int, error)
+
+// Hooks defines a set of method interceptors for methods included in
+// http.ResponseWriter as well as some others. You can think of them as
+// middleware for the function calls they target. See Wrap for more details.
+//
+// For each method, the exact matching hook takes precedence. For example,
+// WriteString calls the WriteString hook when it is configured, even if a
+// Write hook is also configured. If the exact hook is not configured, most
+// methods call through to the underlying ResponseWriter directly.
+//
+// Two compatibility fallbacks preserve the behavior users had before Wrap
+// learned about newer optional interfaces:
+// - If the underlying ResponseWriter implements io.StringWriter and
+// WriteString is called, but only the Write hook is configured, WriteString
+// is routed through the Write hook with []byte(s). If neither hook is
+// configured, WriteString calls the underlying WriteString method directly.
+// - If the underlying ResponseWriter implements both http.Flusher and
+// FlushError, and FlushError is called, but only the Flush hook is
+// configured, FlushError is routed through the Flush hook while preserving
+// the error returned by the underlying FlushError method. If neither hook is
+// configured, FlushError calls the underlying FlushError method directly.
+type Hooks struct {
+ Header func(HeaderFunc) HeaderFunc
+ WriteHeader func(WriteHeaderFunc) WriteHeaderFunc
+ Write func(WriteFunc) WriteFunc
+ Flush func(FlushFunc) FlushFunc
+ FlushError func(FlushErrorFunc) FlushErrorFunc
+ CloseNotify func(CloseNotifyFunc) CloseNotifyFunc
+ Hijack func(HijackFunc) HijackFunc
+ ReadFrom func(ReadFromFunc) ReadFromFunc
+ SetReadDeadline func(SetReadDeadlineFunc) SetReadDeadlineFunc
+ SetWriteDeadline func(SetWriteDeadlineFunc) SetWriteDeadlineFunc
+ EnableFullDuplex func(EnableFullDuplexFunc) EnableFullDuplexFunc
+ Push func(PushFunc) PushFunc
+ WriteString func(WriteStringFunc) WriteStringFunc
+}
+
+// Wrap returns a wrapped version of w that provides the exact same interface
+// as w. Specifically if w implements any combination of:
+//
+// - http.Flusher
+// - httpFlushError
+// - http.CloseNotifier
+// - http.Hijacker
+// - io.ReaderFrom
+// - deadliner
+// - fullDuplexEnabler
+// - http.Pusher
+// - io.StringWriter
+//
+// The wrapped version will implement the exact same combination. If no hooks
+// are set, the wrapped version also behaves exactly as w. Hooks targeting
+// methods not supported by w are ignored. Any other hooks will intercept the
+// method they target and may modify the call's arguments and/or return values.
+// The CaptureMetrics implementation serves as a working example for how the
+// hooks can be used.
+func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter {
+ state := &rwState{w: w}
+ var combo uint16
+ if hooks.Header != nil {
+ state.header = hooks.Header(w.Header)
+ }
+ if hooks.WriteHeader != nil {
+ state.writeHeader = hooks.WriteHeader(w.WriteHeader)
+ }
+ if hooks.Write != nil {
+ state.write = hooks.Write(w.Write)
+ }
+ if t0, i0 := w.(http.Flusher); i0 {
+ combo |= 1 << 8
+ if hooks.Flush != nil {
+ state.flush = hooks.Flush(t0.Flush)
+ }
+ }
+ if t1, i1 := w.(httpFlushError); i1 {
+ combo |= 1 << 7
+ if hooks.FlushError != nil {
+ state.flushError = hooks.FlushError(t1.FlushError)
+ } else if state.flush != nil {
+ state.flushError = func() (err error) { hooks.Flush(func() { err = t1.FlushError() })(); return err }
+ }
+ }
+ if t2, i2 := w.(http.CloseNotifier); i2 {
+ combo |= 1 << 6
+ if hooks.CloseNotify != nil {
+ state.closeNotify = hooks.CloseNotify(t2.CloseNotify)
+ }
+ }
+ if t3, i3 := w.(http.Hijacker); i3 {
+ combo |= 1 << 5
+ if hooks.Hijack != nil {
+ state.hijack = hooks.Hijack(t3.Hijack)
+ }
+ }
+ if t4, i4 := w.(io.ReaderFrom); i4 {
+ combo |= 1 << 4
+ if hooks.ReadFrom != nil {
+ state.readFrom = hooks.ReadFrom(t4.ReadFrom)
+ }
+ }
+ if t5, i5 := w.(deadliner); i5 {
+ combo |= 1 << 3
+ if hooks.SetReadDeadline != nil {
+ state.setReadDeadline = hooks.SetReadDeadline(t5.SetReadDeadline)
+ }
+ if hooks.SetWriteDeadline != nil {
+ state.setWriteDeadline = hooks.SetWriteDeadline(t5.SetWriteDeadline)
+ }
+ }
+ if t6, i6 := w.(fullDuplexEnabler); i6 {
+ combo |= 1 << 2
+ if hooks.EnableFullDuplex != nil {
+ state.enableFullDuplex = hooks.EnableFullDuplex(t6.EnableFullDuplex)
+ }
+ }
+ if t7, i7 := w.(http.Pusher); i7 {
+ combo |= 1 << 1
+ if hooks.Push != nil {
+ state.push = hooks.Push(t7.Push)
+ }
+ }
+ if t8, i8 := w.(io.StringWriter); i8 {
+ combo |= 1 << 0
+ if hooks.WriteString != nil {
+ state.writeString = hooks.WriteString(t8.WriteString)
+ } else if state.write != nil {
+ state.writeString = func(s string) (int, error) { return state.write([]byte(s)) }
+ }
+ }
+ switch combo {
+ case 0:
+ return (*rw0)(state)
+ case 1:
+ return (*rw1)(state)
+ case 2:
+ return (*rw2)(state)
+ case 3:
+ return (*rw3)(state)
+ case 4:
+ return (*rw4)(state)
+ case 5:
+ return (*rw5)(state)
+ case 6:
+ return (*rw6)(state)
+ case 7:
+ return (*rw7)(state)
+ case 8:
+ return (*rw8)(state)
+ case 9:
+ return (*rw9)(state)
+ case 10:
+ return (*rw10)(state)
+ case 11:
+ return (*rw11)(state)
+ case 12:
+ return (*rw12)(state)
+ case 13:
+ return (*rw13)(state)
+ case 14:
+ return (*rw14)(state)
+ case 15:
+ return (*rw15)(state)
+ case 16:
+ return (*rw16)(state)
+ case 17:
+ return (*rw17)(state)
+ case 18:
+ return (*rw18)(state)
+ case 19:
+ return (*rw19)(state)
+ case 20:
+ return (*rw20)(state)
+ case 21:
+ return (*rw21)(state)
+ case 22:
+ return (*rw22)(state)
+ case 23:
+ return (*rw23)(state)
+ case 24:
+ return (*rw24)(state)
+ case 25:
+ return (*rw25)(state)
+ case 26:
+ return (*rw26)(state)
+ case 27:
+ return (*rw27)(state)
+ case 28:
+ return (*rw28)(state)
+ case 29:
+ return (*rw29)(state)
+ case 30:
+ return (*rw30)(state)
+ case 31:
+ return (*rw31)(state)
+ case 32:
+ return (*rw32)(state)
+ case 33:
+ return (*rw33)(state)
+ case 34:
+ return (*rw34)(state)
+ case 35:
+ return (*rw35)(state)
+ case 36:
+ return (*rw36)(state)
+ case 37:
+ return (*rw37)(state)
+ case 38:
+ return (*rw38)(state)
+ case 39:
+ return (*rw39)(state)
+ case 40:
+ return (*rw40)(state)
+ case 41:
+ return (*rw41)(state)
+ case 42:
+ return (*rw42)(state)
+ case 43:
+ return (*rw43)(state)
+ case 44:
+ return (*rw44)(state)
+ case 45:
+ return (*rw45)(state)
+ case 46:
+ return (*rw46)(state)
+ case 47:
+ return (*rw47)(state)
+ case 48:
+ return (*rw48)(state)
+ case 49:
+ return (*rw49)(state)
+ case 50:
+ return (*rw50)(state)
+ case 51:
+ return (*rw51)(state)
+ case 52:
+ return (*rw52)(state)
+ case 53:
+ return (*rw53)(state)
+ case 54:
+ return (*rw54)(state)
+ case 55:
+ return (*rw55)(state)
+ case 56:
+ return (*rw56)(state)
+ case 57:
+ return (*rw57)(state)
+ case 58:
+ return (*rw58)(state)
+ case 59:
+ return (*rw59)(state)
+ case 60:
+ return (*rw60)(state)
+ case 61:
+ return (*rw61)(state)
+ case 62:
+ return (*rw62)(state)
+ case 63:
+ return (*rw63)(state)
+ case 64:
+ return (*rw64)(state)
+ case 65:
+ return (*rw65)(state)
+ case 66:
+ return (*rw66)(state)
+ case 67:
+ return (*rw67)(state)
+ case 68:
+ return (*rw68)(state)
+ case 69:
+ return (*rw69)(state)
+ case 70:
+ return (*rw70)(state)
+ case 71:
+ return (*rw71)(state)
+ case 72:
+ return (*rw72)(state)
+ case 73:
+ return (*rw73)(state)
+ case 74:
+ return (*rw74)(state)
+ case 75:
+ return (*rw75)(state)
+ case 76:
+ return (*rw76)(state)
+ case 77:
+ return (*rw77)(state)
+ case 78:
+ return (*rw78)(state)
+ case 79:
+ return (*rw79)(state)
+ case 80:
+ return (*rw80)(state)
+ case 81:
+ return (*rw81)(state)
+ case 82:
+ return (*rw82)(state)
+ case 83:
+ return (*rw83)(state)
+ case 84:
+ return (*rw84)(state)
+ case 85:
+ return (*rw85)(state)
+ case 86:
+ return (*rw86)(state)
+ case 87:
+ return (*rw87)(state)
+ case 88:
+ return (*rw88)(state)
+ case 89:
+ return (*rw89)(state)
+ case 90:
+ return (*rw90)(state)
+ case 91:
+ return (*rw91)(state)
+ case 92:
+ return (*rw92)(state)
+ case 93:
+ return (*rw93)(state)
+ case 94:
+ return (*rw94)(state)
+ case 95:
+ return (*rw95)(state)
+ case 96:
+ return (*rw96)(state)
+ case 97:
+ return (*rw97)(state)
+ case 98:
+ return (*rw98)(state)
+ case 99:
+ return (*rw99)(state)
+ case 100:
+ return (*rw100)(state)
+ case 101:
+ return (*rw101)(state)
+ case 102:
+ return (*rw102)(state)
+ case 103:
+ return (*rw103)(state)
+ case 104:
+ return (*rw104)(state)
+ case 105:
+ return (*rw105)(state)
+ case 106:
+ return (*rw106)(state)
+ case 107:
+ return (*rw107)(state)
+ case 108:
+ return (*rw108)(state)
+ case 109:
+ return (*rw109)(state)
+ case 110:
+ return (*rw110)(state)
+ case 111:
+ return (*rw111)(state)
+ case 112:
+ return (*rw112)(state)
+ case 113:
+ return (*rw113)(state)
+ case 114:
+ return (*rw114)(state)
+ case 115:
+ return (*rw115)(state)
+ case 116:
+ return (*rw116)(state)
+ case 117:
+ return (*rw117)(state)
+ case 118:
+ return (*rw118)(state)
+ case 119:
+ return (*rw119)(state)
+ case 120:
+ return (*rw120)(state)
+ case 121:
+ return (*rw121)(state)
+ case 122:
+ return (*rw122)(state)
+ case 123:
+ return (*rw123)(state)
+ case 124:
+ return (*rw124)(state)
+ case 125:
+ return (*rw125)(state)
+ case 126:
+ return (*rw126)(state)
+ case 127:
+ return (*rw127)(state)
+ case 128:
+ return (*rw128)(state)
+ case 129:
+ return (*rw129)(state)
+ case 130:
+ return (*rw130)(state)
+ case 131:
+ return (*rw131)(state)
+ case 132:
+ return (*rw132)(state)
+ case 133:
+ return (*rw133)(state)
+ case 134:
+ return (*rw134)(state)
+ case 135:
+ return (*rw135)(state)
+ case 136:
+ return (*rw136)(state)
+ case 137:
+ return (*rw137)(state)
+ case 138:
+ return (*rw138)(state)
+ case 139:
+ return (*rw139)(state)
+ case 140:
+ return (*rw140)(state)
+ case 141:
+ return (*rw141)(state)
+ case 142:
+ return (*rw142)(state)
+ case 143:
+ return (*rw143)(state)
+ case 144:
+ return (*rw144)(state)
+ case 145:
+ return (*rw145)(state)
+ case 146:
+ return (*rw146)(state)
+ case 147:
+ return (*rw147)(state)
+ case 148:
+ return (*rw148)(state)
+ case 149:
+ return (*rw149)(state)
+ case 150:
+ return (*rw150)(state)
+ case 151:
+ return (*rw151)(state)
+ case 152:
+ return (*rw152)(state)
+ case 153:
+ return (*rw153)(state)
+ case 154:
+ return (*rw154)(state)
+ case 155:
+ return (*rw155)(state)
+ case 156:
+ return (*rw156)(state)
+ case 157:
+ return (*rw157)(state)
+ case 158:
+ return (*rw158)(state)
+ case 159:
+ return (*rw159)(state)
+ case 160:
+ return (*rw160)(state)
+ case 161:
+ return (*rw161)(state)
+ case 162:
+ return (*rw162)(state)
+ case 163:
+ return (*rw163)(state)
+ case 164:
+ return (*rw164)(state)
+ case 165:
+ return (*rw165)(state)
+ case 166:
+ return (*rw166)(state)
+ case 167:
+ return (*rw167)(state)
+ case 168:
+ return (*rw168)(state)
+ case 169:
+ return (*rw169)(state)
+ case 170:
+ return (*rw170)(state)
+ case 171:
+ return (*rw171)(state)
+ case 172:
+ return (*rw172)(state)
+ case 173:
+ return (*rw173)(state)
+ case 174:
+ return (*rw174)(state)
+ case 175:
+ return (*rw175)(state)
+ case 176:
+ return (*rw176)(state)
+ case 177:
+ return (*rw177)(state)
+ case 178:
+ return (*rw178)(state)
+ case 179:
+ return (*rw179)(state)
+ case 180:
+ return (*rw180)(state)
+ case 181:
+ return (*rw181)(state)
+ case 182:
+ return (*rw182)(state)
+ case 183:
+ return (*rw183)(state)
+ case 184:
+ return (*rw184)(state)
+ case 185:
+ return (*rw185)(state)
+ case 186:
+ return (*rw186)(state)
+ case 187:
+ return (*rw187)(state)
+ case 188:
+ return (*rw188)(state)
+ case 189:
+ return (*rw189)(state)
+ case 190:
+ return (*rw190)(state)
+ case 191:
+ return (*rw191)(state)
+ case 192:
+ return (*rw192)(state)
+ case 193:
+ return (*rw193)(state)
+ case 194:
+ return (*rw194)(state)
+ case 195:
+ return (*rw195)(state)
+ case 196:
+ return (*rw196)(state)
+ case 197:
+ return (*rw197)(state)
+ case 198:
+ return (*rw198)(state)
+ case 199:
+ return (*rw199)(state)
+ case 200:
+ return (*rw200)(state)
+ case 201:
+ return (*rw201)(state)
+ case 202:
+ return (*rw202)(state)
+ case 203:
+ return (*rw203)(state)
+ case 204:
+ return (*rw204)(state)
+ case 205:
+ return (*rw205)(state)
+ case 206:
+ return (*rw206)(state)
+ case 207:
+ return (*rw207)(state)
+ case 208:
+ return (*rw208)(state)
+ case 209:
+ return (*rw209)(state)
+ case 210:
+ return (*rw210)(state)
+ case 211:
+ return (*rw211)(state)
+ case 212:
+ return (*rw212)(state)
+ case 213:
+ return (*rw213)(state)
+ case 214:
+ return (*rw214)(state)
+ case 215:
+ return (*rw215)(state)
+ case 216:
+ return (*rw216)(state)
+ case 217:
+ return (*rw217)(state)
+ case 218:
+ return (*rw218)(state)
+ case 219:
+ return (*rw219)(state)
+ case 220:
+ return (*rw220)(state)
+ case 221:
+ return (*rw221)(state)
+ case 222:
+ return (*rw222)(state)
+ case 223:
+ return (*rw223)(state)
+ case 224:
+ return (*rw224)(state)
+ case 225:
+ return (*rw225)(state)
+ case 226:
+ return (*rw226)(state)
+ case 227:
+ return (*rw227)(state)
+ case 228:
+ return (*rw228)(state)
+ case 229:
+ return (*rw229)(state)
+ case 230:
+ return (*rw230)(state)
+ case 231:
+ return (*rw231)(state)
+ case 232:
+ return (*rw232)(state)
+ case 233:
+ return (*rw233)(state)
+ case 234:
+ return (*rw234)(state)
+ case 235:
+ return (*rw235)(state)
+ case 236:
+ return (*rw236)(state)
+ case 237:
+ return (*rw237)(state)
+ case 238:
+ return (*rw238)(state)
+ case 239:
+ return (*rw239)(state)
+ case 240:
+ return (*rw240)(state)
+ case 241:
+ return (*rw241)(state)
+ case 242:
+ return (*rw242)(state)
+ case 243:
+ return (*rw243)(state)
+ case 244:
+ return (*rw244)(state)
+ case 245:
+ return (*rw245)(state)
+ case 246:
+ return (*rw246)(state)
+ case 247:
+ return (*rw247)(state)
+ case 248:
+ return (*rw248)(state)
+ case 249:
+ return (*rw249)(state)
+ case 250:
+ return (*rw250)(state)
+ case 251:
+ return (*rw251)(state)
+ case 252:
+ return (*rw252)(state)
+ case 253:
+ return (*rw253)(state)
+ case 254:
+ return (*rw254)(state)
+ case 255:
+ return (*rw255)(state)
+ case 256:
+ return (*rw256)(state)
+ case 257:
+ return (*rw257)(state)
+ case 258:
+ return (*rw258)(state)
+ case 259:
+ return (*rw259)(state)
+ case 260:
+ return (*rw260)(state)
+ case 261:
+ return (*rw261)(state)
+ case 262:
+ return (*rw262)(state)
+ case 263:
+ return (*rw263)(state)
+ case 264:
+ return (*rw264)(state)
+ case 265:
+ return (*rw265)(state)
+ case 266:
+ return (*rw266)(state)
+ case 267:
+ return (*rw267)(state)
+ case 268:
+ return (*rw268)(state)
+ case 269:
+ return (*rw269)(state)
+ case 270:
+ return (*rw270)(state)
+ case 271:
+ return (*rw271)(state)
+ case 272:
+ return (*rw272)(state)
+ case 273:
+ return (*rw273)(state)
+ case 274:
+ return (*rw274)(state)
+ case 275:
+ return (*rw275)(state)
+ case 276:
+ return (*rw276)(state)
+ case 277:
+ return (*rw277)(state)
+ case 278:
+ return (*rw278)(state)
+ case 279:
+ return (*rw279)(state)
+ case 280:
+ return (*rw280)(state)
+ case 281:
+ return (*rw281)(state)
+ case 282:
+ return (*rw282)(state)
+ case 283:
+ return (*rw283)(state)
+ case 284:
+ return (*rw284)(state)
+ case 285:
+ return (*rw285)(state)
+ case 286:
+ return (*rw286)(state)
+ case 287:
+ return (*rw287)(state)
+ case 288:
+ return (*rw288)(state)
+ case 289:
+ return (*rw289)(state)
+ case 290:
+ return (*rw290)(state)
+ case 291:
+ return (*rw291)(state)
+ case 292:
+ return (*rw292)(state)
+ case 293:
+ return (*rw293)(state)
+ case 294:
+ return (*rw294)(state)
+ case 295:
+ return (*rw295)(state)
+ case 296:
+ return (*rw296)(state)
+ case 297:
+ return (*rw297)(state)
+ case 298:
+ return (*rw298)(state)
+ case 299:
+ return (*rw299)(state)
+ case 300:
+ return (*rw300)(state)
+ case 301:
+ return (*rw301)(state)
+ case 302:
+ return (*rw302)(state)
+ case 303:
+ return (*rw303)(state)
+ case 304:
+ return (*rw304)(state)
+ case 305:
+ return (*rw305)(state)
+ case 306:
+ return (*rw306)(state)
+ case 307:
+ return (*rw307)(state)
+ case 308:
+ return (*rw308)(state)
+ case 309:
+ return (*rw309)(state)
+ case 310:
+ return (*rw310)(state)
+ case 311:
+ return (*rw311)(state)
+ case 312:
+ return (*rw312)(state)
+ case 313:
+ return (*rw313)(state)
+ case 314:
+ return (*rw314)(state)
+ case 315:
+ return (*rw315)(state)
+ case 316:
+ return (*rw316)(state)
+ case 317:
+ return (*rw317)(state)
+ case 318:
+ return (*rw318)(state)
+ case 319:
+ return (*rw319)(state)
+ case 320:
+ return (*rw320)(state)
+ case 321:
+ return (*rw321)(state)
+ case 322:
+ return (*rw322)(state)
+ case 323:
+ return (*rw323)(state)
+ case 324:
+ return (*rw324)(state)
+ case 325:
+ return (*rw325)(state)
+ case 326:
+ return (*rw326)(state)
+ case 327:
+ return (*rw327)(state)
+ case 328:
+ return (*rw328)(state)
+ case 329:
+ return (*rw329)(state)
+ case 330:
+ return (*rw330)(state)
+ case 331:
+ return (*rw331)(state)
+ case 332:
+ return (*rw332)(state)
+ case 333:
+ return (*rw333)(state)
+ case 334:
+ return (*rw334)(state)
+ case 335:
+ return (*rw335)(state)
+ case 336:
+ return (*rw336)(state)
+ case 337:
+ return (*rw337)(state)
+ case 338:
+ return (*rw338)(state)
+ case 339:
+ return (*rw339)(state)
+ case 340:
+ return (*rw340)(state)
+ case 341:
+ return (*rw341)(state)
+ case 342:
+ return (*rw342)(state)
+ case 343:
+ return (*rw343)(state)
+ case 344:
+ return (*rw344)(state)
+ case 345:
+ return (*rw345)(state)
+ case 346:
+ return (*rw346)(state)
+ case 347:
+ return (*rw347)(state)
+ case 348:
+ return (*rw348)(state)
+ case 349:
+ return (*rw349)(state)
+ case 350:
+ return (*rw350)(state)
+ case 351:
+ return (*rw351)(state)
+ case 352:
+ return (*rw352)(state)
+ case 353:
+ return (*rw353)(state)
+ case 354:
+ return (*rw354)(state)
+ case 355:
+ return (*rw355)(state)
+ case 356:
+ return (*rw356)(state)
+ case 357:
+ return (*rw357)(state)
+ case 358:
+ return (*rw358)(state)
+ case 359:
+ return (*rw359)(state)
+ case 360:
+ return (*rw360)(state)
+ case 361:
+ return (*rw361)(state)
+ case 362:
+ return (*rw362)(state)
+ case 363:
+ return (*rw363)(state)
+ case 364:
+ return (*rw364)(state)
+ case 365:
+ return (*rw365)(state)
+ case 366:
+ return (*rw366)(state)
+ case 367:
+ return (*rw367)(state)
+ case 368:
+ return (*rw368)(state)
+ case 369:
+ return (*rw369)(state)
+ case 370:
+ return (*rw370)(state)
+ case 371:
+ return (*rw371)(state)
+ case 372:
+ return (*rw372)(state)
+ case 373:
+ return (*rw373)(state)
+ case 374:
+ return (*rw374)(state)
+ case 375:
+ return (*rw375)(state)
+ case 376:
+ return (*rw376)(state)
+ case 377:
+ return (*rw377)(state)
+ case 378:
+ return (*rw378)(state)
+ case 379:
+ return (*rw379)(state)
+ case 380:
+ return (*rw380)(state)
+ case 381:
+ return (*rw381)(state)
+ case 382:
+ return (*rw382)(state)
+ case 383:
+ return (*rw383)(state)
+ case 384:
+ return (*rw384)(state)
+ case 385:
+ return (*rw385)(state)
+ case 386:
+ return (*rw386)(state)
+ case 387:
+ return (*rw387)(state)
+ case 388:
+ return (*rw388)(state)
+ case 389:
+ return (*rw389)(state)
+ case 390:
+ return (*rw390)(state)
+ case 391:
+ return (*rw391)(state)
+ case 392:
+ return (*rw392)(state)
+ case 393:
+ return (*rw393)(state)
+ case 394:
+ return (*rw394)(state)
+ case 395:
+ return (*rw395)(state)
+ case 396:
+ return (*rw396)(state)
+ case 397:
+ return (*rw397)(state)
+ case 398:
+ return (*rw398)(state)
+ case 399:
+ return (*rw399)(state)
+ case 400:
+ return (*rw400)(state)
+ case 401:
+ return (*rw401)(state)
+ case 402:
+ return (*rw402)(state)
+ case 403:
+ return (*rw403)(state)
+ case 404:
+ return (*rw404)(state)
+ case 405:
+ return (*rw405)(state)
+ case 406:
+ return (*rw406)(state)
+ case 407:
+ return (*rw407)(state)
+ case 408:
+ return (*rw408)(state)
+ case 409:
+ return (*rw409)(state)
+ case 410:
+ return (*rw410)(state)
+ case 411:
+ return (*rw411)(state)
+ case 412:
+ return (*rw412)(state)
+ case 413:
+ return (*rw413)(state)
+ case 414:
+ return (*rw414)(state)
+ case 415:
+ return (*rw415)(state)
+ case 416:
+ return (*rw416)(state)
+ case 417:
+ return (*rw417)(state)
+ case 418:
+ return (*rw418)(state)
+ case 419:
+ return (*rw419)(state)
+ case 420:
+ return (*rw420)(state)
+ case 421:
+ return (*rw421)(state)
+ case 422:
+ return (*rw422)(state)
+ case 423:
+ return (*rw423)(state)
+ case 424:
+ return (*rw424)(state)
+ case 425:
+ return (*rw425)(state)
+ case 426:
+ return (*rw426)(state)
+ case 427:
+ return (*rw427)(state)
+ case 428:
+ return (*rw428)(state)
+ case 429:
+ return (*rw429)(state)
+ case 430:
+ return (*rw430)(state)
+ case 431:
+ return (*rw431)(state)
+ case 432:
+ return (*rw432)(state)
+ case 433:
+ return (*rw433)(state)
+ case 434:
+ return (*rw434)(state)
+ case 435:
+ return (*rw435)(state)
+ case 436:
+ return (*rw436)(state)
+ case 437:
+ return (*rw437)(state)
+ case 438:
+ return (*rw438)(state)
+ case 439:
+ return (*rw439)(state)
+ case 440:
+ return (*rw440)(state)
+ case 441:
+ return (*rw441)(state)
+ case 442:
+ return (*rw442)(state)
+ case 443:
+ return (*rw443)(state)
+ case 444:
+ return (*rw444)(state)
+ case 445:
+ return (*rw445)(state)
+ case 446:
+ return (*rw446)(state)
+ case 447:
+ return (*rw447)(state)
+ case 448:
+ return (*rw448)(state)
+ case 449:
+ return (*rw449)(state)
+ case 450:
+ return (*rw450)(state)
+ case 451:
+ return (*rw451)(state)
+ case 452:
+ return (*rw452)(state)
+ case 453:
+ return (*rw453)(state)
+ case 454:
+ return (*rw454)(state)
+ case 455:
+ return (*rw455)(state)
+ case 456:
+ return (*rw456)(state)
+ case 457:
+ return (*rw457)(state)
+ case 458:
+ return (*rw458)(state)
+ case 459:
+ return (*rw459)(state)
+ case 460:
+ return (*rw460)(state)
+ case 461:
+ return (*rw461)(state)
+ case 462:
+ return (*rw462)(state)
+ case 463:
+ return (*rw463)(state)
+ case 464:
+ return (*rw464)(state)
+ case 465:
+ return (*rw465)(state)
+ case 466:
+ return (*rw466)(state)
+ case 467:
+ return (*rw467)(state)
+ case 468:
+ return (*rw468)(state)
+ case 469:
+ return (*rw469)(state)
+ case 470:
+ return (*rw470)(state)
+ case 471:
+ return (*rw471)(state)
+ case 472:
+ return (*rw472)(state)
+ case 473:
+ return (*rw473)(state)
+ case 474:
+ return (*rw474)(state)
+ case 475:
+ return (*rw475)(state)
+ case 476:
+ return (*rw476)(state)
+ case 477:
+ return (*rw477)(state)
+ case 478:
+ return (*rw478)(state)
+ case 479:
+ return (*rw479)(state)
+ case 480:
+ return (*rw480)(state)
+ case 481:
+ return (*rw481)(state)
+ case 482:
+ return (*rw482)(state)
+ case 483:
+ return (*rw483)(state)
+ case 484:
+ return (*rw484)(state)
+ case 485:
+ return (*rw485)(state)
+ case 486:
+ return (*rw486)(state)
+ case 487:
+ return (*rw487)(state)
+ case 488:
+ return (*rw488)(state)
+ case 489:
+ return (*rw489)(state)
+ case 490:
+ return (*rw490)(state)
+ case 491:
+ return (*rw491)(state)
+ case 492:
+ return (*rw492)(state)
+ case 493:
+ return (*rw493)(state)
+ case 494:
+ return (*rw494)(state)
+ case 495:
+ return (*rw495)(state)
+ case 496:
+ return (*rw496)(state)
+ case 497:
+ return (*rw497)(state)
+ case 498:
+ return (*rw498)(state)
+ case 499:
+ return (*rw499)(state)
+ case 500:
+ return (*rw500)(state)
+ case 501:
+ return (*rw501)(state)
+ case 502:
+ return (*rw502)(state)
+ case 503:
+ return (*rw503)(state)
+ case 504:
+ return (*rw504)(state)
+ case 505:
+ return (*rw505)(state)
+ case 506:
+ return (*rw506)(state)
+ case 507:
+ return (*rw507)(state)
+ case 508:
+ return (*rw508)(state)
+ case 509:
+ return (*rw509)(state)
+ case 510:
+ return (*rw510)(state)
+ case 511:
+ return (*rw511)(state)
+ }
+ panic("unreachable")
+}
+
+type rwState struct {
+ w http.ResponseWriter
+ header HeaderFunc
+ writeHeader WriteHeaderFunc
+ write WriteFunc
+ flush FlushFunc
+ flushError FlushErrorFunc
+ closeNotify CloseNotifyFunc
+ hijack HijackFunc
+ readFrom ReadFromFunc
+ setReadDeadline SetReadDeadlineFunc
+ setWriteDeadline SetWriteDeadlineFunc
+ enableFullDuplex EnableFullDuplexFunc
+ push PushFunc
+ writeString WriteStringFunc
+}
+
+func (r *rwState) doHeader() http.Header {
+ if r.header != nil {
+ return r.header()
+ }
+ return r.w.Header()
+}
+
+func (r *rwState) doWriteHeader(code int) {
+ if r.writeHeader != nil {
+ r.writeHeader(code)
+ return
+ }
+ r.w.WriteHeader(code)
+}
+
+func (r *rwState) doWrite(b []byte) (int, error) {
+ if r.write != nil {
+ return r.write(b)
+ }
+ return r.w.Write(b)
+}
+
+func (r *rwState) doFlush() {
+ if r.flush != nil {
+ r.flush()
+ return
+ }
+ r.w.(http.Flusher).Flush()
+}
+
+func (r *rwState) doFlushError() error {
+ if r.flushError != nil {
+ return r.flushError()
+ }
+ return r.w.(httpFlushError).FlushError()
+}
+
+func (r *rwState) doCloseNotify() <-chan bool {
+ if r.closeNotify != nil {
+ return r.closeNotify()
+ }
+ return r.w.(http.CloseNotifier).CloseNotify()
+}
+
+func (r *rwState) doHijack() (net.Conn, *bufio.ReadWriter, error) {
+ if r.hijack != nil {
+ return r.hijack()
+ }
+ return r.w.(http.Hijacker).Hijack()
+}
+
+func (r *rwState) doReadFrom(src io.Reader) (int64, error) {
+ if r.readFrom != nil {
+ return r.readFrom(src)
+ }
+ return r.w.(io.ReaderFrom).ReadFrom(src)
+}
+
+func (r *rwState) doSetReadDeadline(deadline time.Time) error {
+ if r.setReadDeadline != nil {
+ return r.setReadDeadline(deadline)
+ }
+ return r.w.(deadliner).SetReadDeadline(deadline)
+}
+
+func (r *rwState) doSetWriteDeadline(deadline time.Time) error {
+ if r.setWriteDeadline != nil {
+ return r.setWriteDeadline(deadline)
+ }
+ return r.w.(deadliner).SetWriteDeadline(deadline)
+}
+
+func (r *rwState) doEnableFullDuplex() error {
+ if r.enableFullDuplex != nil {
+ return r.enableFullDuplex()
+ }
+ return r.w.(fullDuplexEnabler).EnableFullDuplex()
+}
+
+func (r *rwState) doPush(target string, opts *http.PushOptions) error {
+ if r.push != nil {
+ return r.push(target, opts)
+ }
+ return r.w.(http.Pusher).Push(target, opts)
+}
+
+func (r *rwState) doWriteString(s string) (int, error) {
+ if r.writeString != nil {
+ return r.writeString(s)
+ }
+ return r.w.(io.StringWriter).WriteString(s)
+}
+
+// combination 1/512: http.ResponseWriter
+type rw0 rwState
+
+func (w *rw0) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw0) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw0) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw0) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+
+// combination 2/512: http.ResponseWriter, io.StringWriter
+type rw1 rwState
+
+func (w *rw1) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw1) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw1) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw1) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw1) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 3/512: http.ResponseWriter, http.Pusher
+type rw2 rwState
+
+func (w *rw2) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw2) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw2) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw2) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw2) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 4/512: http.ResponseWriter, http.Pusher, io.StringWriter
+type rw3 rwState
+
+func (w *rw3) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw3) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw3) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw3) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw3) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw3) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 5/512: http.ResponseWriter, fullDuplexEnabler
+type rw4 rwState
+
+func (w *rw4) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw4) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw4) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw4) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw4) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 6/512: http.ResponseWriter, fullDuplexEnabler, io.StringWriter
+type rw5 rwState
+
+func (w *rw5) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw5) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw5) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw5) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw5) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw5) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 7/512: http.ResponseWriter, fullDuplexEnabler, http.Pusher
+type rw6 rwState
+
+func (w *rw6) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw6) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw6) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw6) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw6) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw6) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 8/512: http.ResponseWriter, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw7 rwState
+
+func (w *rw7) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw7) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw7) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw7) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw7) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw7) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw7) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 9/512: http.ResponseWriter, deadliner
+type rw8 rwState
+
+func (w *rw8) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw8) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw8) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw8) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw8) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw8) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 10/512: http.ResponseWriter, deadliner, io.StringWriter
+type rw9 rwState
+
+func (w *rw9) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw9) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw9) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw9) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw9) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw9) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw9) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 11/512: http.ResponseWriter, deadliner, http.Pusher
+type rw10 rwState
+
+func (w *rw10) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw10) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw10) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw10) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw10) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw10) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw10) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 12/512: http.ResponseWriter, deadliner, http.Pusher, io.StringWriter
+type rw11 rwState
+
+func (w *rw11) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw11) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw11) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw11) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw11) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw11) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw11) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw11) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 13/512: http.ResponseWriter, deadliner, fullDuplexEnabler
+type rw12 rwState
+
+func (w *rw12) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw12) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw12) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw12) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw12) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw12) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw12) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 14/512: http.ResponseWriter, deadliner, fullDuplexEnabler, io.StringWriter
+type rw13 rwState
+
+func (w *rw13) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw13) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw13) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw13) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw13) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw13) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw13) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw13) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 15/512: http.ResponseWriter, deadliner, fullDuplexEnabler, http.Pusher
+type rw14 rwState
+
+func (w *rw14) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw14) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw14) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw14) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw14) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw14) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw14) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw14) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 16/512: http.ResponseWriter, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw15 rwState
+
+func (w *rw15) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw15) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw15) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw15) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw15) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw15) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw15) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw15) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw15) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 17/512: http.ResponseWriter, io.ReaderFrom
+type rw16 rwState
+
+func (w *rw16) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw16) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw16) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw16) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw16) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 18/512: http.ResponseWriter, io.ReaderFrom, io.StringWriter
+type rw17 rwState
+
+func (w *rw17) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw17) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw17) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw17) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw17) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw17) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 19/512: http.ResponseWriter, io.ReaderFrom, http.Pusher
+type rw18 rwState
+
+func (w *rw18) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw18) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw18) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw18) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw18) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw18) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 20/512: http.ResponseWriter, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw19 rwState
+
+func (w *rw19) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw19) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw19) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw19) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw19) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw19) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw19) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 21/512: http.ResponseWriter, io.ReaderFrom, fullDuplexEnabler
+type rw20 rwState
+
+func (w *rw20) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw20) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw20) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw20) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw20) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw20) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 22/512: http.ResponseWriter, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw21 rwState
+
+func (w *rw21) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw21) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw21) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw21) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw21) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw21) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw21) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 23/512: http.ResponseWriter, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw22 rwState
+
+func (w *rw22) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw22) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw22) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw22) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw22) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw22) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw22) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 24/512: http.ResponseWriter, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw23 rwState
+
+func (w *rw23) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw23) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw23) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw23) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw23) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw23) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw23) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw23) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 25/512: http.ResponseWriter, io.ReaderFrom, deadliner
+type rw24 rwState
+
+func (w *rw24) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw24) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw24) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw24) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw24) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw24) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw24) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 26/512: http.ResponseWriter, io.ReaderFrom, deadliner, io.StringWriter
+type rw25 rwState
+
+func (w *rw25) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw25) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw25) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw25) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw25) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw25) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw25) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw25) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 27/512: http.ResponseWriter, io.ReaderFrom, deadliner, http.Pusher
+type rw26 rwState
+
+func (w *rw26) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw26) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw26) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw26) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw26) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw26) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw26) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw26) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 28/512: http.ResponseWriter, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw27 rwState
+
+func (w *rw27) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw27) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw27) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw27) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw27) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw27) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw27) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw27) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw27) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 29/512: http.ResponseWriter, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw28 rwState
+
+func (w *rw28) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw28) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw28) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw28) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw28) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw28) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw28) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw28) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 30/512: http.ResponseWriter, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw29 rwState
+
+func (w *rw29) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw29) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw29) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw29) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw29) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw29) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw29) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw29) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw29) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 31/512: http.ResponseWriter, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw30 rwState
+
+func (w *rw30) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw30) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw30) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw30) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw30) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw30) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw30) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw30) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw30) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 32/512: http.ResponseWriter, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw31 rwState
+
+func (w *rw31) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw31) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw31) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw31) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw31) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw31) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw31) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw31) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw31) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw31) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 33/512: http.ResponseWriter, http.Hijacker
+type rw32 rwState
+
+func (w *rw32) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw32) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw32) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw32) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw32) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+
+// combination 34/512: http.ResponseWriter, http.Hijacker, io.StringWriter
+type rw33 rwState
+
+func (w *rw33) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw33) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw33) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw33) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw33) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw33) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 35/512: http.ResponseWriter, http.Hijacker, http.Pusher
+type rw34 rwState
+
+func (w *rw34) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw34) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw34) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw34) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw34) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw34) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 36/512: http.ResponseWriter, http.Hijacker, http.Pusher, io.StringWriter
+type rw35 rwState
+
+func (w *rw35) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw35) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw35) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw35) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw35) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw35) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw35) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 37/512: http.ResponseWriter, http.Hijacker, fullDuplexEnabler
+type rw36 rwState
+
+func (w *rw36) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw36) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw36) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw36) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw36) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw36) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 38/512: http.ResponseWriter, http.Hijacker, fullDuplexEnabler, io.StringWriter
+type rw37 rwState
+
+func (w *rw37) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw37) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw37) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw37) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw37) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw37) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw37) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 39/512: http.ResponseWriter, http.Hijacker, fullDuplexEnabler, http.Pusher
+type rw38 rwState
+
+func (w *rw38) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw38) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw38) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw38) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw38) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw38) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw38) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 40/512: http.ResponseWriter, http.Hijacker, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw39 rwState
+
+func (w *rw39) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw39) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw39) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw39) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw39) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw39) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw39) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw39) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 41/512: http.ResponseWriter, http.Hijacker, deadliner
+type rw40 rwState
+
+func (w *rw40) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw40) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw40) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw40) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw40) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw40) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw40) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 42/512: http.ResponseWriter, http.Hijacker, deadliner, io.StringWriter
+type rw41 rwState
+
+func (w *rw41) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw41) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw41) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw41) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw41) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw41) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw41) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw41) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 43/512: http.ResponseWriter, http.Hijacker, deadliner, http.Pusher
+type rw42 rwState
+
+func (w *rw42) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw42) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw42) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw42) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw42) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw42) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw42) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw42) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 44/512: http.ResponseWriter, http.Hijacker, deadliner, http.Pusher, io.StringWriter
+type rw43 rwState
+
+func (w *rw43) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw43) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw43) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw43) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw43) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw43) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw43) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw43) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw43) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 45/512: http.ResponseWriter, http.Hijacker, deadliner, fullDuplexEnabler
+type rw44 rwState
+
+func (w *rw44) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw44) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw44) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw44) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw44) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw44) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw44) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw44) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 46/512: http.ResponseWriter, http.Hijacker, deadliner, fullDuplexEnabler, io.StringWriter
+type rw45 rwState
+
+func (w *rw45) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw45) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw45) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw45) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw45) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw45) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw45) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw45) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw45) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 47/512: http.ResponseWriter, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher
+type rw46 rwState
+
+func (w *rw46) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw46) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw46) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw46) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw46) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw46) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw46) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw46) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw46) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 48/512: http.ResponseWriter, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw47 rwState
+
+func (w *rw47) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw47) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw47) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw47) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw47) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw47) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw47) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw47) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw47) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw47) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 49/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom
+type rw48 rwState
+
+func (w *rw48) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw48) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw48) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw48) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw48) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw48) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 50/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, io.StringWriter
+type rw49 rwState
+
+func (w *rw49) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw49) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw49) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw49) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw49) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw49) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw49) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 51/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, http.Pusher
+type rw50 rwState
+
+func (w *rw50) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw50) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw50) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw50) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw50) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw50) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw50) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 52/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw51 rwState
+
+func (w *rw51) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw51) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw51) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw51) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw51) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw51) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw51) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw51) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 53/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, fullDuplexEnabler
+type rw52 rwState
+
+func (w *rw52) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw52) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw52) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw52) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw52) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw52) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw52) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 54/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw53 rwState
+
+func (w *rw53) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw53) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw53) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw53) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw53) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw53) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw53) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw53) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 55/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw54 rwState
+
+func (w *rw54) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw54) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw54) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw54) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw54) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw54) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw54) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw54) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 56/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw55 rwState
+
+func (w *rw55) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw55) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw55) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw55) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw55) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw55) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw55) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw55) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw55) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 57/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, deadliner
+type rw56 rwState
+
+func (w *rw56) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw56) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw56) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw56) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw56) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw56) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw56) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw56) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 58/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, deadliner, io.StringWriter
+type rw57 rwState
+
+func (w *rw57) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw57) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw57) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw57) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw57) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw57) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw57) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw57) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw57) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 59/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher
+type rw58 rwState
+
+func (w *rw58) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw58) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw58) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw58) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw58) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw58) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw58) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw58) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw58) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 60/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw59 rwState
+
+func (w *rw59) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw59) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw59) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw59) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw59) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw59) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw59) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw59) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw59) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw59) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 61/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw60 rwState
+
+func (w *rw60) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw60) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw60) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw60) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw60) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw60) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw60) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw60) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw60) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 62/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw61 rwState
+
+func (w *rw61) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw61) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw61) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw61) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw61) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw61) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw61) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw61) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw61) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw61) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 63/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw62 rwState
+
+func (w *rw62) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw62) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw62) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw62) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw62) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw62) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw62) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw62) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw62) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw62) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 64/512: http.ResponseWriter, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw63 rwState
+
+func (w *rw63) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw63) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw63) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw63) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw63) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw63) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw63) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw63) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw63) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw63) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw63) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 65/512: http.ResponseWriter, http.CloseNotifier
+type rw64 rwState
+
+func (w *rw64) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw64) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw64) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw64) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw64) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+
+// combination 66/512: http.ResponseWriter, http.CloseNotifier, io.StringWriter
+type rw65 rwState
+
+func (w *rw65) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw65) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw65) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw65) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw65) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw65) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 67/512: http.ResponseWriter, http.CloseNotifier, http.Pusher
+type rw66 rwState
+
+func (w *rw66) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw66) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw66) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw66) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw66) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw66) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 68/512: http.ResponseWriter, http.CloseNotifier, http.Pusher, io.StringWriter
+type rw67 rwState
+
+func (w *rw67) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw67) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw67) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw67) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw67) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw67) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw67) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 69/512: http.ResponseWriter, http.CloseNotifier, fullDuplexEnabler
+type rw68 rwState
+
+func (w *rw68) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw68) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw68) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw68) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw68) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw68) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 70/512: http.ResponseWriter, http.CloseNotifier, fullDuplexEnabler, io.StringWriter
+type rw69 rwState
+
+func (w *rw69) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw69) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw69) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw69) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw69) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw69) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw69) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 71/512: http.ResponseWriter, http.CloseNotifier, fullDuplexEnabler, http.Pusher
+type rw70 rwState
+
+func (w *rw70) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw70) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw70) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw70) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw70) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw70) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw70) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 72/512: http.ResponseWriter, http.CloseNotifier, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw71 rwState
+
+func (w *rw71) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw71) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw71) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw71) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw71) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw71) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw71) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw71) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 73/512: http.ResponseWriter, http.CloseNotifier, deadliner
+type rw72 rwState
+
+func (w *rw72) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw72) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw72) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw72) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw72) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw72) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw72) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 74/512: http.ResponseWriter, http.CloseNotifier, deadliner, io.StringWriter
+type rw73 rwState
+
+func (w *rw73) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw73) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw73) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw73) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw73) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw73) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw73) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw73) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 75/512: http.ResponseWriter, http.CloseNotifier, deadliner, http.Pusher
+type rw74 rwState
+
+func (w *rw74) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw74) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw74) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw74) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw74) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw74) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw74) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw74) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 76/512: http.ResponseWriter, http.CloseNotifier, deadliner, http.Pusher, io.StringWriter
+type rw75 rwState
+
+func (w *rw75) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw75) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw75) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw75) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw75) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw75) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw75) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw75) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw75) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 77/512: http.ResponseWriter, http.CloseNotifier, deadliner, fullDuplexEnabler
+type rw76 rwState
+
+func (w *rw76) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw76) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw76) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw76) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw76) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw76) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw76) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw76) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 78/512: http.ResponseWriter, http.CloseNotifier, deadliner, fullDuplexEnabler, io.StringWriter
+type rw77 rwState
+
+func (w *rw77) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw77) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw77) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw77) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw77) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw77) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw77) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw77) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw77) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 79/512: http.ResponseWriter, http.CloseNotifier, deadliner, fullDuplexEnabler, http.Pusher
+type rw78 rwState
+
+func (w *rw78) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw78) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw78) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw78) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw78) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw78) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw78) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw78) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw78) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 80/512: http.ResponseWriter, http.CloseNotifier, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw79 rwState
+
+func (w *rw79) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw79) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw79) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw79) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw79) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw79) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw79) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw79) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw79) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw79) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 81/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom
+type rw80 rwState
+
+func (w *rw80) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw80) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw80) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw80) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw80) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw80) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 82/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, io.StringWriter
+type rw81 rwState
+
+func (w *rw81) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw81) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw81) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw81) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw81) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw81) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw81) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 83/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, http.Pusher
+type rw82 rwState
+
+func (w *rw82) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw82) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw82) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw82) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw82) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw82) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw82) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 84/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw83 rwState
+
+func (w *rw83) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw83) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw83) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw83) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw83) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw83) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw83) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw83) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 85/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler
+type rw84 rwState
+
+func (w *rw84) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw84) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw84) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw84) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw84) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw84) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw84) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 86/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw85 rwState
+
+func (w *rw85) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw85) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw85) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw85) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw85) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw85) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw85) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw85) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 87/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw86 rwState
+
+func (w *rw86) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw86) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw86) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw86) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw86) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw86) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw86) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw86) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 88/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw87 rwState
+
+func (w *rw87) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw87) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw87) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw87) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw87) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw87) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw87) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw87) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw87) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 89/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, deadliner
+type rw88 rwState
+
+func (w *rw88) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw88) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw88) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw88) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw88) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw88) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw88) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw88) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 90/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, deadliner, io.StringWriter
+type rw89 rwState
+
+func (w *rw89) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw89) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw89) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw89) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw89) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw89) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw89) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw89) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw89) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 91/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, deadliner, http.Pusher
+type rw90 rwState
+
+func (w *rw90) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw90) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw90) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw90) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw90) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw90) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw90) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw90) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw90) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 92/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw91 rwState
+
+func (w *rw91) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw91) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw91) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw91) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw91) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw91) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw91) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw91) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw91) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw91) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 93/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw92 rwState
+
+func (w *rw92) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw92) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw92) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw92) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw92) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw92) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw92) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw92) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw92) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 94/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw93 rwState
+
+func (w *rw93) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw93) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw93) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw93) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw93) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw93) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw93) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw93) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw93) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw93) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 95/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw94 rwState
+
+func (w *rw94) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw94) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw94) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw94) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw94) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw94) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw94) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw94) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw94) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw94) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 96/512: http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw95 rwState
+
+func (w *rw95) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw95) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw95) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw95) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw95) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw95) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw95) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw95) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw95) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw95) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw95) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 97/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker
+type rw96 rwState
+
+func (w *rw96) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw96) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw96) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw96) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw96) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw96) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+
+// combination 98/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.StringWriter
+type rw97 rwState
+
+func (w *rw97) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw97) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw97) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw97) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw97) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw97) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw97) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 99/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, http.Pusher
+type rw98 rwState
+
+func (w *rw98) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw98) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw98) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw98) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw98) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw98) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw98) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 100/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, http.Pusher, io.StringWriter
+type rw99 rwState
+
+func (w *rw99) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw99) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw99) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw99) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw99) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw99) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw99) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw99) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 101/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, fullDuplexEnabler
+type rw100 rwState
+
+func (w *rw100) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw100) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw100) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw100) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw100) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw100) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw100) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 102/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, fullDuplexEnabler, io.StringWriter
+type rw101 rwState
+
+func (w *rw101) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw101) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw101) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw101) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw101) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw101) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw101) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw101) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 103/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, fullDuplexEnabler, http.Pusher
+type rw102 rwState
+
+func (w *rw102) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw102) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw102) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw102) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw102) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw102) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw102) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw102) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 104/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw103 rwState
+
+func (w *rw103) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw103) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw103) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw103) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw103) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw103) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw103) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw103) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw103) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 105/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, deadliner
+type rw104 rwState
+
+func (w *rw104) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw104) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw104) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw104) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw104) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw104) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw104) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw104) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 106/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, deadliner, io.StringWriter
+type rw105 rwState
+
+func (w *rw105) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw105) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw105) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw105) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw105) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw105) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw105) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw105) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw105) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 107/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, deadliner, http.Pusher
+type rw106 rwState
+
+func (w *rw106) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw106) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw106) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw106) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw106) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw106) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw106) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw106) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw106) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 108/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, deadliner, http.Pusher, io.StringWriter
+type rw107 rwState
+
+func (w *rw107) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw107) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw107) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw107) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw107) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw107) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw107) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw107) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw107) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw107) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 109/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler
+type rw108 rwState
+
+func (w *rw108) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw108) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw108) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw108) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw108) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw108) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw108) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw108) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw108) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 110/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler, io.StringWriter
+type rw109 rwState
+
+func (w *rw109) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw109) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw109) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw109) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw109) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw109) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw109) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw109) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw109) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw109) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 111/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher
+type rw110 rwState
+
+func (w *rw110) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw110) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw110) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw110) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw110) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw110) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw110) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw110) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw110) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw110) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 112/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw111 rwState
+
+func (w *rw111) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw111) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw111) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw111) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw111) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw111) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw111) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw111) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw111) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw111) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw111) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 113/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom
+type rw112 rwState
+
+func (w *rw112) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw112) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw112) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw112) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw112) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw112) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw112) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 114/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, io.StringWriter
+type rw113 rwState
+
+func (w *rw113) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw113) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw113) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw113) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw113) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw113) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw113) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw113) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 115/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, http.Pusher
+type rw114 rwState
+
+func (w *rw114) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw114) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw114) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw114) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw114) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw114) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw114) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw114) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 116/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw115 rwState
+
+func (w *rw115) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw115) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw115) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw115) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw115) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw115) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw115) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw115) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw115) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 117/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler
+type rw116 rwState
+
+func (w *rw116) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw116) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw116) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw116) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw116) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw116) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw116) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw116) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 118/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw117 rwState
+
+func (w *rw117) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw117) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw117) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw117) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw117) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw117) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw117) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw117) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw117) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 119/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw118 rwState
+
+func (w *rw118) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw118) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw118) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw118) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw118) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw118) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw118) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw118) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw118) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 120/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw119 rwState
+
+func (w *rw119) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw119) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw119) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw119) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw119) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw119) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw119) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw119) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw119) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw119) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 121/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner
+type rw120 rwState
+
+func (w *rw120) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw120) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw120) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw120) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw120) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw120) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw120) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw120) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw120) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 122/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, io.StringWriter
+type rw121 rwState
+
+func (w *rw121) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw121) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw121) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw121) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw121) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw121) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw121) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw121) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw121) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw121) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 123/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher
+type rw122 rwState
+
+func (w *rw122) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw122) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw122) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw122) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw122) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw122) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw122) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw122) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw122) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw122) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 124/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw123 rwState
+
+func (w *rw123) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw123) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw123) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw123) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw123) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw123) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw123) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw123) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw123) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw123) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw123) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 125/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw124 rwState
+
+func (w *rw124) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw124) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw124) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw124) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw124) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw124) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw124) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw124) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw124) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw124) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 126/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw125 rwState
+
+func (w *rw125) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw125) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw125) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw125) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw125) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw125) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw125) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw125) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw125) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw125) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw125) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 127/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw126 rwState
+
+func (w *rw126) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw126) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw126) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw126) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw126) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw126) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw126) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw126) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw126) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw126) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw126) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 128/512: http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw127 rwState
+
+func (w *rw127) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw127) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw127) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw127) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw127) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw127) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw127) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw127) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw127) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw127) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw127) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw127) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 129/512: http.ResponseWriter, httpFlushError
+type rw128 rwState
+
+func (w *rw128) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw128) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw128) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw128) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw128) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+
+// combination 130/512: http.ResponseWriter, httpFlushError, io.StringWriter
+type rw129 rwState
+
+func (w *rw129) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw129) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw129) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw129) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw129) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw129) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 131/512: http.ResponseWriter, httpFlushError, http.Pusher
+type rw130 rwState
+
+func (w *rw130) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw130) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw130) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw130) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw130) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw130) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 132/512: http.ResponseWriter, httpFlushError, http.Pusher, io.StringWriter
+type rw131 rwState
+
+func (w *rw131) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw131) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw131) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw131) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw131) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw131) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw131) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 133/512: http.ResponseWriter, httpFlushError, fullDuplexEnabler
+type rw132 rwState
+
+func (w *rw132) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw132) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw132) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw132) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw132) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw132) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 134/512: http.ResponseWriter, httpFlushError, fullDuplexEnabler, io.StringWriter
+type rw133 rwState
+
+func (w *rw133) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw133) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw133) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw133) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw133) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw133) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw133) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 135/512: http.ResponseWriter, httpFlushError, fullDuplexEnabler, http.Pusher
+type rw134 rwState
+
+func (w *rw134) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw134) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw134) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw134) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw134) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw134) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw134) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 136/512: http.ResponseWriter, httpFlushError, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw135 rwState
+
+func (w *rw135) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw135) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw135) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw135) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw135) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw135) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw135) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw135) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 137/512: http.ResponseWriter, httpFlushError, deadliner
+type rw136 rwState
+
+func (w *rw136) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw136) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw136) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw136) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw136) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw136) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw136) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 138/512: http.ResponseWriter, httpFlushError, deadliner, io.StringWriter
+type rw137 rwState
+
+func (w *rw137) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw137) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw137) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw137) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw137) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw137) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw137) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw137) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 139/512: http.ResponseWriter, httpFlushError, deadliner, http.Pusher
+type rw138 rwState
+
+func (w *rw138) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw138) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw138) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw138) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw138) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw138) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw138) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw138) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 140/512: http.ResponseWriter, httpFlushError, deadliner, http.Pusher, io.StringWriter
+type rw139 rwState
+
+func (w *rw139) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw139) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw139) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw139) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw139) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw139) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw139) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw139) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw139) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 141/512: http.ResponseWriter, httpFlushError, deadliner, fullDuplexEnabler
+type rw140 rwState
+
+func (w *rw140) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw140) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw140) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw140) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw140) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw140) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw140) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw140) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 142/512: http.ResponseWriter, httpFlushError, deadliner, fullDuplexEnabler, io.StringWriter
+type rw141 rwState
+
+func (w *rw141) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw141) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw141) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw141) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw141) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw141) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw141) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw141) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw141) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 143/512: http.ResponseWriter, httpFlushError, deadliner, fullDuplexEnabler, http.Pusher
+type rw142 rwState
+
+func (w *rw142) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw142) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw142) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw142) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw142) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw142) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw142) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw142) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw142) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 144/512: http.ResponseWriter, httpFlushError, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw143 rwState
+
+func (w *rw143) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw143) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw143) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw143) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw143) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw143) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw143) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw143) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw143) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw143) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 145/512: http.ResponseWriter, httpFlushError, io.ReaderFrom
+type rw144 rwState
+
+func (w *rw144) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw144) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw144) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw144) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw144) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw144) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 146/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, io.StringWriter
+type rw145 rwState
+
+func (w *rw145) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw145) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw145) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw145) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw145) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw145) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw145) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 147/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, http.Pusher
+type rw146 rwState
+
+func (w *rw146) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw146) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw146) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw146) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw146) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw146) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw146) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 148/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw147 rwState
+
+func (w *rw147) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw147) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw147) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw147) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw147) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw147) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw147) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw147) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 149/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, fullDuplexEnabler
+type rw148 rwState
+
+func (w *rw148) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw148) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw148) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw148) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw148) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw148) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw148) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 150/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw149 rwState
+
+func (w *rw149) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw149) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw149) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw149) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw149) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw149) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw149) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw149) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 151/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw150 rwState
+
+func (w *rw150) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw150) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw150) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw150) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw150) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw150) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw150) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw150) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 152/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw151 rwState
+
+func (w *rw151) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw151) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw151) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw151) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw151) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw151) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw151) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw151) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw151) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 153/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, deadliner
+type rw152 rwState
+
+func (w *rw152) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw152) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw152) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw152) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw152) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw152) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw152) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw152) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 154/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, deadliner, io.StringWriter
+type rw153 rwState
+
+func (w *rw153) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw153) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw153) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw153) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw153) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw153) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw153) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw153) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw153) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 155/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, deadliner, http.Pusher
+type rw154 rwState
+
+func (w *rw154) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw154) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw154) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw154) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw154) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw154) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw154) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw154) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw154) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 156/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw155 rwState
+
+func (w *rw155) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw155) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw155) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw155) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw155) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw155) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw155) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw155) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw155) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw155) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 157/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw156 rwState
+
+func (w *rw156) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw156) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw156) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw156) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw156) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw156) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw156) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw156) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw156) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 158/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw157 rwState
+
+func (w *rw157) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw157) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw157) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw157) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw157) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw157) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw157) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw157) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw157) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw157) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 159/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw158 rwState
+
+func (w *rw158) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw158) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw158) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw158) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw158) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw158) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw158) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw158) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw158) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw158) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 160/512: http.ResponseWriter, httpFlushError, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw159 rwState
+
+func (w *rw159) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw159) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw159) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw159) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw159) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw159) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw159) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw159) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw159) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw159) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw159) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 161/512: http.ResponseWriter, httpFlushError, http.Hijacker
+type rw160 rwState
+
+func (w *rw160) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw160) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw160) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw160) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw160) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw160) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+
+// combination 162/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.StringWriter
+type rw161 rwState
+
+func (w *rw161) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw161) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw161) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw161) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw161) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw161) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw161) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 163/512: http.ResponseWriter, httpFlushError, http.Hijacker, http.Pusher
+type rw162 rwState
+
+func (w *rw162) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw162) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw162) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw162) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw162) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw162) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw162) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 164/512: http.ResponseWriter, httpFlushError, http.Hijacker, http.Pusher, io.StringWriter
+type rw163 rwState
+
+func (w *rw163) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw163) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw163) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw163) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw163) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw163) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw163) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw163) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 165/512: http.ResponseWriter, httpFlushError, http.Hijacker, fullDuplexEnabler
+type rw164 rwState
+
+func (w *rw164) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw164) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw164) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw164) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw164) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw164) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw164) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 166/512: http.ResponseWriter, httpFlushError, http.Hijacker, fullDuplexEnabler, io.StringWriter
+type rw165 rwState
+
+func (w *rw165) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw165) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw165) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw165) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw165) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw165) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw165) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw165) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 167/512: http.ResponseWriter, httpFlushError, http.Hijacker, fullDuplexEnabler, http.Pusher
+type rw166 rwState
+
+func (w *rw166) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw166) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw166) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw166) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw166) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw166) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw166) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw166) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 168/512: http.ResponseWriter, httpFlushError, http.Hijacker, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw167 rwState
+
+func (w *rw167) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw167) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw167) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw167) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw167) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw167) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw167) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw167) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw167) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 169/512: http.ResponseWriter, httpFlushError, http.Hijacker, deadliner
+type rw168 rwState
+
+func (w *rw168) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw168) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw168) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw168) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw168) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw168) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw168) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw168) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 170/512: http.ResponseWriter, httpFlushError, http.Hijacker, deadliner, io.StringWriter
+type rw169 rwState
+
+func (w *rw169) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw169) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw169) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw169) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw169) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw169) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw169) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw169) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw169) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 171/512: http.ResponseWriter, httpFlushError, http.Hijacker, deadliner, http.Pusher
+type rw170 rwState
+
+func (w *rw170) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw170) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw170) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw170) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw170) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw170) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw170) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw170) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw170) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 172/512: http.ResponseWriter, httpFlushError, http.Hijacker, deadliner, http.Pusher, io.StringWriter
+type rw171 rwState
+
+func (w *rw171) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw171) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw171) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw171) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw171) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw171) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw171) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw171) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw171) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw171) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 173/512: http.ResponseWriter, httpFlushError, http.Hijacker, deadliner, fullDuplexEnabler
+type rw172 rwState
+
+func (w *rw172) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw172) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw172) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw172) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw172) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw172) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw172) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw172) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw172) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 174/512: http.ResponseWriter, httpFlushError, http.Hijacker, deadliner, fullDuplexEnabler, io.StringWriter
+type rw173 rwState
+
+func (w *rw173) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw173) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw173) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw173) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw173) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw173) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw173) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw173) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw173) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw173) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 175/512: http.ResponseWriter, httpFlushError, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher
+type rw174 rwState
+
+func (w *rw174) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw174) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw174) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw174) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw174) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw174) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw174) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw174) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw174) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw174) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 176/512: http.ResponseWriter, httpFlushError, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw175 rwState
+
+func (w *rw175) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw175) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw175) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw175) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw175) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw175) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw175) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw175) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw175) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw175) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw175) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 177/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom
+type rw176 rwState
+
+func (w *rw176) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw176) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw176) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw176) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw176) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw176) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw176) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 178/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, io.StringWriter
+type rw177 rwState
+
+func (w *rw177) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw177) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw177) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw177) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw177) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw177) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw177) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw177) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 179/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, http.Pusher
+type rw178 rwState
+
+func (w *rw178) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw178) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw178) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw178) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw178) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw178) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw178) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw178) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 180/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw179 rwState
+
+func (w *rw179) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw179) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw179) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw179) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw179) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw179) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw179) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw179) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw179) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 181/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, fullDuplexEnabler
+type rw180 rwState
+
+func (w *rw180) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw180) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw180) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw180) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw180) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw180) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw180) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw180) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 182/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw181 rwState
+
+func (w *rw181) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw181) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw181) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw181) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw181) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw181) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw181) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw181) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw181) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 183/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw182 rwState
+
+func (w *rw182) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw182) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw182) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw182) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw182) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw182) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw182) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw182) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw182) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 184/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw183 rwState
+
+func (w *rw183) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw183) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw183) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw183) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw183) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw183) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw183) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw183) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw183) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw183) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 185/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner
+type rw184 rwState
+
+func (w *rw184) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw184) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw184) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw184) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw184) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw184) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw184) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw184) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw184) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 186/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, io.StringWriter
+type rw185 rwState
+
+func (w *rw185) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw185) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw185) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw185) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw185) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw185) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw185) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw185) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw185) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw185) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 187/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher
+type rw186 rwState
+
+func (w *rw186) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw186) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw186) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw186) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw186) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw186) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw186) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw186) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw186) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw186) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 188/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw187 rwState
+
+func (w *rw187) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw187) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw187) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw187) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw187) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw187) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw187) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw187) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw187) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw187) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw187) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 189/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw188 rwState
+
+func (w *rw188) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw188) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw188) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw188) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw188) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw188) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw188) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw188) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw188) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw188) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 190/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw189 rwState
+
+func (w *rw189) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw189) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw189) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw189) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw189) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw189) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw189) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw189) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw189) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw189) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw189) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 191/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw190 rwState
+
+func (w *rw190) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw190) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw190) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw190) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw190) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw190) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw190) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw190) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw190) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw190) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw190) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 192/512: http.ResponseWriter, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw191 rwState
+
+func (w *rw191) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw191) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw191) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw191) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw191) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw191) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw191) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw191) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw191) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw191) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw191) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw191) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 193/512: http.ResponseWriter, httpFlushError, http.CloseNotifier
+type rw192 rwState
+
+func (w *rw192) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw192) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw192) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw192) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw192) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw192) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+
+// combination 194/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.StringWriter
+type rw193 rwState
+
+func (w *rw193) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw193) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw193) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw193) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw193) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw193) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw193) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 195/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Pusher
+type rw194 rwState
+
+func (w *rw194) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw194) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw194) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw194) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw194) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw194) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw194) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 196/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Pusher, io.StringWriter
+type rw195 rwState
+
+func (w *rw195) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw195) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw195) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw195) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw195) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw195) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw195) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw195) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 197/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, fullDuplexEnabler
+type rw196 rwState
+
+func (w *rw196) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw196) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw196) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw196) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw196) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw196) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw196) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 198/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, fullDuplexEnabler, io.StringWriter
+type rw197 rwState
+
+func (w *rw197) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw197) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw197) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw197) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw197) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw197) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw197) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw197) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 199/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, fullDuplexEnabler, http.Pusher
+type rw198 rwState
+
+func (w *rw198) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw198) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw198) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw198) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw198) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw198) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw198) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw198) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 200/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw199 rwState
+
+func (w *rw199) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw199) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw199) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw199) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw199) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw199) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw199) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw199) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw199) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 201/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, deadliner
+type rw200 rwState
+
+func (w *rw200) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw200) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw200) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw200) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw200) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw200) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw200) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw200) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 202/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, deadliner, io.StringWriter
+type rw201 rwState
+
+func (w *rw201) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw201) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw201) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw201) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw201) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw201) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw201) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw201) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw201) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 203/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, deadliner, http.Pusher
+type rw202 rwState
+
+func (w *rw202) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw202) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw202) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw202) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw202) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw202) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw202) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw202) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw202) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 204/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, deadliner, http.Pusher, io.StringWriter
+type rw203 rwState
+
+func (w *rw203) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw203) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw203) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw203) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw203) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw203) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw203) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw203) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw203) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw203) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 205/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, deadliner, fullDuplexEnabler
+type rw204 rwState
+
+func (w *rw204) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw204) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw204) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw204) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw204) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw204) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw204) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw204) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw204) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 206/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, deadliner, fullDuplexEnabler, io.StringWriter
+type rw205 rwState
+
+func (w *rw205) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw205) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw205) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw205) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw205) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw205) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw205) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw205) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw205) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw205) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 207/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, deadliner, fullDuplexEnabler, http.Pusher
+type rw206 rwState
+
+func (w *rw206) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw206) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw206) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw206) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw206) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw206) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw206) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw206) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw206) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw206) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 208/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw207 rwState
+
+func (w *rw207) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw207) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw207) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw207) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw207) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw207) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw207) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw207) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw207) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw207) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw207) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 209/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom
+type rw208 rwState
+
+func (w *rw208) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw208) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw208) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw208) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw208) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw208) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw208) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 210/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, io.StringWriter
+type rw209 rwState
+
+func (w *rw209) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw209) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw209) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw209) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw209) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw209) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw209) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw209) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 211/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, http.Pusher
+type rw210 rwState
+
+func (w *rw210) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw210) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw210) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw210) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw210) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw210) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw210) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw210) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 212/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw211 rwState
+
+func (w *rw211) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw211) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw211) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw211) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw211) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw211) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw211) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw211) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw211) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 213/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler
+type rw212 rwState
+
+func (w *rw212) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw212) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw212) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw212) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw212) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw212) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw212) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw212) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 214/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw213 rwState
+
+func (w *rw213) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw213) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw213) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw213) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw213) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw213) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw213) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw213) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw213) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 215/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw214 rwState
+
+func (w *rw214) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw214) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw214) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw214) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw214) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw214) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw214) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw214) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw214) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 216/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw215 rwState
+
+func (w *rw215) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw215) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw215) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw215) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw215) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw215) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw215) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw215) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw215) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw215) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 217/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner
+type rw216 rwState
+
+func (w *rw216) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw216) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw216) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw216) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw216) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw216) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw216) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw216) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw216) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 218/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, io.StringWriter
+type rw217 rwState
+
+func (w *rw217) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw217) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw217) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw217) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw217) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw217) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw217) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw217) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw217) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw217) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 219/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, http.Pusher
+type rw218 rwState
+
+func (w *rw218) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw218) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw218) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw218) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw218) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw218) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw218) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw218) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw218) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw218) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 220/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw219 rwState
+
+func (w *rw219) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw219) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw219) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw219) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw219) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw219) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw219) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw219) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw219) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw219) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw219) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 221/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw220 rwState
+
+func (w *rw220) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw220) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw220) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw220) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw220) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw220) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw220) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw220) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw220) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw220) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 222/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw221 rwState
+
+func (w *rw221) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw221) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw221) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw221) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw221) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw221) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw221) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw221) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw221) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw221) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw221) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 223/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw222 rwState
+
+func (w *rw222) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw222) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw222) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw222) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw222) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw222) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw222) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw222) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw222) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw222) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw222) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 224/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw223 rwState
+
+func (w *rw223) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw223) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw223) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw223) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw223) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw223) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw223) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw223) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw223) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw223) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw223) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw223) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 225/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker
+type rw224 rwState
+
+func (w *rw224) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw224) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw224) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw224) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw224) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw224) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw224) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+
+// combination 226/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.StringWriter
+type rw225 rwState
+
+func (w *rw225) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw225) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw225) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw225) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw225) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw225) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw225) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw225) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 227/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, http.Pusher
+type rw226 rwState
+
+func (w *rw226) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw226) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw226) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw226) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw226) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw226) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw226) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw226) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 228/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, http.Pusher, io.StringWriter
+type rw227 rwState
+
+func (w *rw227) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw227) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw227) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw227) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw227) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw227) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw227) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw227) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw227) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 229/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, fullDuplexEnabler
+type rw228 rwState
+
+func (w *rw228) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw228) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw228) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw228) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw228) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw228) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw228) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw228) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 230/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, fullDuplexEnabler, io.StringWriter
+type rw229 rwState
+
+func (w *rw229) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw229) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw229) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw229) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw229) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw229) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw229) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw229) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw229) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 231/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, fullDuplexEnabler, http.Pusher
+type rw230 rwState
+
+func (w *rw230) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw230) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw230) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw230) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw230) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw230) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw230) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw230) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw230) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 232/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw231 rwState
+
+func (w *rw231) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw231) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw231) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw231) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw231) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw231) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw231) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw231) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw231) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw231) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 233/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner
+type rw232 rwState
+
+func (w *rw232) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw232) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw232) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw232) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw232) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw232) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw232) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw232) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw232) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 234/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, io.StringWriter
+type rw233 rwState
+
+func (w *rw233) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw233) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw233) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw233) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw233) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw233) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw233) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw233) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw233) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw233) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 235/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, http.Pusher
+type rw234 rwState
+
+func (w *rw234) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw234) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw234) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw234) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw234) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw234) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw234) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw234) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw234) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw234) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 236/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, http.Pusher, io.StringWriter
+type rw235 rwState
+
+func (w *rw235) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw235) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw235) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw235) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw235) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw235) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw235) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw235) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw235) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw235) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw235) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 237/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler
+type rw236 rwState
+
+func (w *rw236) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw236) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw236) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw236) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw236) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw236) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw236) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw236) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw236) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw236) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 238/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler, io.StringWriter
+type rw237 rwState
+
+func (w *rw237) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw237) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw237) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw237) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw237) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw237) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw237) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw237) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw237) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw237) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw237) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 239/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher
+type rw238 rwState
+
+func (w *rw238) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw238) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw238) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw238) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw238) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw238) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw238) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw238) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw238) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw238) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw238) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 240/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw239 rwState
+
+func (w *rw239) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw239) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw239) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw239) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw239) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw239) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw239) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw239) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw239) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw239) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw239) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw239) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 241/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom
+type rw240 rwState
+
+func (w *rw240) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw240) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw240) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw240) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw240) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw240) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw240) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw240) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 242/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, io.StringWriter
+type rw241 rwState
+
+func (w *rw241) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw241) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw241) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw241) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw241) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw241) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw241) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw241) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw241) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 243/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, http.Pusher
+type rw242 rwState
+
+func (w *rw242) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw242) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw242) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw242) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw242) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw242) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw242) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw242) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw242) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 244/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw243 rwState
+
+func (w *rw243) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw243) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw243) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw243) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw243) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw243) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw243) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw243) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw243) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw243) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 245/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler
+type rw244 rwState
+
+func (w *rw244) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw244) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw244) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw244) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw244) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw244) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw244) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw244) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw244) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 246/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw245 rwState
+
+func (w *rw245) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw245) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw245) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw245) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw245) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw245) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw245) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw245) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw245) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw245) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 247/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw246 rwState
+
+func (w *rw246) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw246) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw246) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw246) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw246) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw246) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw246) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw246) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw246) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw246) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 248/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw247 rwState
+
+func (w *rw247) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw247) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw247) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw247) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw247) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw247) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw247) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw247) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw247) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw247) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw247) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 249/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner
+type rw248 rwState
+
+func (w *rw248) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw248) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw248) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw248) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw248) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw248) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw248) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw248) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw248) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw248) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 250/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, io.StringWriter
+type rw249 rwState
+
+func (w *rw249) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw249) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw249) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw249) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw249) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw249) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw249) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw249) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw249) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw249) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw249) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 251/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher
+type rw250 rwState
+
+func (w *rw250) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw250) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw250) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw250) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw250) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw250) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw250) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw250) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw250) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw250) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw250) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 252/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw251 rwState
+
+func (w *rw251) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw251) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw251) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw251) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw251) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw251) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw251) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw251) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw251) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw251) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw251) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw251) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 253/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw252 rwState
+
+func (w *rw252) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw252) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw252) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw252) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw252) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw252) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw252) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw252) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw252) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw252) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw252) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 254/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw253 rwState
+
+func (w *rw253) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw253) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw253) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw253) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw253) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw253) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw253) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw253) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw253) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw253) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw253) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw253) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 255/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw254 rwState
+
+func (w *rw254) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw254) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw254) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw254) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw254) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw254) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw254) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw254) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw254) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw254) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw254) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw254) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 256/512: http.ResponseWriter, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw255 rwState
+
+func (w *rw255) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw255) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw255) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw255) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw255) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw255) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw255) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw255) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw255) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw255) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw255) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw255) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw255) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 257/512: http.ResponseWriter, http.Flusher
+type rw256 rwState
+
+func (w *rw256) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw256) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw256) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw256) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw256) Flush() {
+ (*rwState)(w).doFlush()
+}
+
+// combination 258/512: http.ResponseWriter, http.Flusher, io.StringWriter
+type rw257 rwState
+
+func (w *rw257) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw257) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw257) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw257) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw257) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw257) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 259/512: http.ResponseWriter, http.Flusher, http.Pusher
+type rw258 rwState
+
+func (w *rw258) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw258) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw258) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw258) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw258) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw258) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 260/512: http.ResponseWriter, http.Flusher, http.Pusher, io.StringWriter
+type rw259 rwState
+
+func (w *rw259) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw259) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw259) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw259) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw259) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw259) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw259) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 261/512: http.ResponseWriter, http.Flusher, fullDuplexEnabler
+type rw260 rwState
+
+func (w *rw260) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw260) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw260) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw260) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw260) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw260) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 262/512: http.ResponseWriter, http.Flusher, fullDuplexEnabler, io.StringWriter
+type rw261 rwState
+
+func (w *rw261) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw261) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw261) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw261) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw261) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw261) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw261) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 263/512: http.ResponseWriter, http.Flusher, fullDuplexEnabler, http.Pusher
+type rw262 rwState
+
+func (w *rw262) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw262) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw262) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw262) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw262) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw262) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw262) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 264/512: http.ResponseWriter, http.Flusher, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw263 rwState
+
+func (w *rw263) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw263) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw263) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw263) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw263) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw263) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw263) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw263) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 265/512: http.ResponseWriter, http.Flusher, deadliner
+type rw264 rwState
+
+func (w *rw264) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw264) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw264) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw264) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw264) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw264) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw264) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 266/512: http.ResponseWriter, http.Flusher, deadliner, io.StringWriter
+type rw265 rwState
+
+func (w *rw265) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw265) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw265) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw265) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw265) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw265) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw265) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw265) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 267/512: http.ResponseWriter, http.Flusher, deadliner, http.Pusher
+type rw266 rwState
+
+func (w *rw266) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw266) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw266) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw266) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw266) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw266) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw266) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw266) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 268/512: http.ResponseWriter, http.Flusher, deadliner, http.Pusher, io.StringWriter
+type rw267 rwState
+
+func (w *rw267) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw267) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw267) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw267) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw267) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw267) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw267) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw267) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw267) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 269/512: http.ResponseWriter, http.Flusher, deadliner, fullDuplexEnabler
+type rw268 rwState
+
+func (w *rw268) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw268) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw268) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw268) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw268) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw268) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw268) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw268) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 270/512: http.ResponseWriter, http.Flusher, deadliner, fullDuplexEnabler, io.StringWriter
+type rw269 rwState
+
+func (w *rw269) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw269) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw269) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw269) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw269) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw269) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw269) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw269) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw269) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 271/512: http.ResponseWriter, http.Flusher, deadliner, fullDuplexEnabler, http.Pusher
+type rw270 rwState
+
+func (w *rw270) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw270) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw270) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw270) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw270) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw270) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw270) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw270) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw270) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 272/512: http.ResponseWriter, http.Flusher, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw271 rwState
+
+func (w *rw271) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw271) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw271) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw271) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw271) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw271) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw271) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw271) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw271) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw271) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 273/512: http.ResponseWriter, http.Flusher, io.ReaderFrom
+type rw272 rwState
+
+func (w *rw272) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw272) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw272) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw272) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw272) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw272) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 274/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, io.StringWriter
+type rw273 rwState
+
+func (w *rw273) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw273) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw273) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw273) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw273) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw273) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw273) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 275/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, http.Pusher
+type rw274 rwState
+
+func (w *rw274) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw274) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw274) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw274) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw274) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw274) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw274) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 276/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw275 rwState
+
+func (w *rw275) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw275) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw275) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw275) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw275) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw275) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw275) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw275) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 277/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, fullDuplexEnabler
+type rw276 rwState
+
+func (w *rw276) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw276) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw276) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw276) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw276) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw276) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw276) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 278/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw277 rwState
+
+func (w *rw277) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw277) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw277) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw277) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw277) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw277) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw277) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw277) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 279/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw278 rwState
+
+func (w *rw278) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw278) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw278) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw278) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw278) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw278) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw278) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw278) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 280/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw279 rwState
+
+func (w *rw279) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw279) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw279) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw279) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw279) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw279) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw279) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw279) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw279) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 281/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, deadliner
+type rw280 rwState
+
+func (w *rw280) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw280) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw280) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw280) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw280) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw280) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw280) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw280) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 282/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, deadliner, io.StringWriter
+type rw281 rwState
+
+func (w *rw281) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw281) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw281) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw281) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw281) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw281) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw281) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw281) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw281) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 283/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, deadliner, http.Pusher
+type rw282 rwState
+
+func (w *rw282) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw282) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw282) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw282) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw282) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw282) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw282) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw282) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw282) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 284/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw283 rwState
+
+func (w *rw283) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw283) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw283) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw283) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw283) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw283) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw283) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw283) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw283) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw283) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 285/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw284 rwState
+
+func (w *rw284) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw284) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw284) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw284) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw284) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw284) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw284) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw284) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw284) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 286/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw285 rwState
+
+func (w *rw285) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw285) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw285) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw285) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw285) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw285) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw285) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw285) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw285) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw285) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 287/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw286 rwState
+
+func (w *rw286) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw286) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw286) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw286) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw286) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw286) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw286) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw286) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw286) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw286) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 288/512: http.ResponseWriter, http.Flusher, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw287 rwState
+
+func (w *rw287) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw287) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw287) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw287) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw287) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw287) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw287) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw287) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw287) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw287) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw287) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 289/512: http.ResponseWriter, http.Flusher, http.Hijacker
+type rw288 rwState
+
+func (w *rw288) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw288) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw288) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw288) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw288) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw288) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+
+// combination 290/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.StringWriter
+type rw289 rwState
+
+func (w *rw289) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw289) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw289) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw289) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw289) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw289) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw289) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 291/512: http.ResponseWriter, http.Flusher, http.Hijacker, http.Pusher
+type rw290 rwState
+
+func (w *rw290) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw290) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw290) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw290) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw290) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw290) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw290) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 292/512: http.ResponseWriter, http.Flusher, http.Hijacker, http.Pusher, io.StringWriter
+type rw291 rwState
+
+func (w *rw291) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw291) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw291) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw291) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw291) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw291) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw291) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw291) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 293/512: http.ResponseWriter, http.Flusher, http.Hijacker, fullDuplexEnabler
+type rw292 rwState
+
+func (w *rw292) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw292) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw292) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw292) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw292) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw292) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw292) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 294/512: http.ResponseWriter, http.Flusher, http.Hijacker, fullDuplexEnabler, io.StringWriter
+type rw293 rwState
+
+func (w *rw293) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw293) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw293) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw293) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw293) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw293) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw293) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw293) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 295/512: http.ResponseWriter, http.Flusher, http.Hijacker, fullDuplexEnabler, http.Pusher
+type rw294 rwState
+
+func (w *rw294) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw294) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw294) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw294) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw294) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw294) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw294) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw294) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 296/512: http.ResponseWriter, http.Flusher, http.Hijacker, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw295 rwState
+
+func (w *rw295) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw295) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw295) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw295) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw295) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw295) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw295) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw295) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw295) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 297/512: http.ResponseWriter, http.Flusher, http.Hijacker, deadliner
+type rw296 rwState
+
+func (w *rw296) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw296) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw296) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw296) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw296) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw296) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw296) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw296) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 298/512: http.ResponseWriter, http.Flusher, http.Hijacker, deadliner, io.StringWriter
+type rw297 rwState
+
+func (w *rw297) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw297) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw297) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw297) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw297) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw297) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw297) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw297) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw297) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 299/512: http.ResponseWriter, http.Flusher, http.Hijacker, deadliner, http.Pusher
+type rw298 rwState
+
+func (w *rw298) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw298) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw298) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw298) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw298) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw298) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw298) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw298) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw298) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 300/512: http.ResponseWriter, http.Flusher, http.Hijacker, deadliner, http.Pusher, io.StringWriter
+type rw299 rwState
+
+func (w *rw299) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw299) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw299) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw299) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw299) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw299) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw299) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw299) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw299) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw299) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 301/512: http.ResponseWriter, http.Flusher, http.Hijacker, deadliner, fullDuplexEnabler
+type rw300 rwState
+
+func (w *rw300) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw300) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw300) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw300) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw300) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw300) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw300) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw300) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw300) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 302/512: http.ResponseWriter, http.Flusher, http.Hijacker, deadliner, fullDuplexEnabler, io.StringWriter
+type rw301 rwState
+
+func (w *rw301) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw301) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw301) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw301) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw301) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw301) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw301) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw301) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw301) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw301) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 303/512: http.ResponseWriter, http.Flusher, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher
+type rw302 rwState
+
+func (w *rw302) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw302) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw302) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw302) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw302) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw302) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw302) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw302) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw302) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw302) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 304/512: http.ResponseWriter, http.Flusher, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw303 rwState
+
+func (w *rw303) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw303) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw303) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw303) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw303) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw303) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw303) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw303) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw303) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw303) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw303) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 305/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom
+type rw304 rwState
+
+func (w *rw304) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw304) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw304) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw304) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw304) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw304) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw304) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 306/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, io.StringWriter
+type rw305 rwState
+
+func (w *rw305) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw305) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw305) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw305) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw305) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw305) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw305) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw305) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 307/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, http.Pusher
+type rw306 rwState
+
+func (w *rw306) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw306) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw306) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw306) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw306) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw306) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw306) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw306) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 308/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw307 rwState
+
+func (w *rw307) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw307) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw307) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw307) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw307) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw307) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw307) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw307) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw307) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 309/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, fullDuplexEnabler
+type rw308 rwState
+
+func (w *rw308) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw308) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw308) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw308) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw308) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw308) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw308) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw308) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 310/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw309 rwState
+
+func (w *rw309) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw309) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw309) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw309) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw309) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw309) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw309) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw309) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw309) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 311/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw310 rwState
+
+func (w *rw310) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw310) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw310) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw310) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw310) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw310) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw310) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw310) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw310) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 312/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw311 rwState
+
+func (w *rw311) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw311) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw311) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw311) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw311) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw311) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw311) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw311) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw311) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw311) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 313/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, deadliner
+type rw312 rwState
+
+func (w *rw312) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw312) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw312) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw312) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw312) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw312) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw312) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw312) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw312) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 314/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, deadliner, io.StringWriter
+type rw313 rwState
+
+func (w *rw313) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw313) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw313) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw313) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw313) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw313) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw313) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw313) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw313) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw313) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 315/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher
+type rw314 rwState
+
+func (w *rw314) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw314) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw314) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw314) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw314) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw314) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw314) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw314) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw314) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw314) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 316/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw315 rwState
+
+func (w *rw315) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw315) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw315) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw315) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw315) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw315) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw315) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw315) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw315) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw315) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw315) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 317/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw316 rwState
+
+func (w *rw316) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw316) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw316) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw316) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw316) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw316) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw316) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw316) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw316) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw316) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 318/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw317 rwState
+
+func (w *rw317) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw317) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw317) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw317) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw317) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw317) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw317) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw317) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw317) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw317) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw317) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 319/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw318 rwState
+
+func (w *rw318) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw318) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw318) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw318) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw318) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw318) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw318) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw318) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw318) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw318) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw318) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 320/512: http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw319 rwState
+
+func (w *rw319) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw319) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw319) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw319) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw319) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw319) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw319) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw319) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw319) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw319) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw319) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw319) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 321/512: http.ResponseWriter, http.Flusher, http.CloseNotifier
+type rw320 rwState
+
+func (w *rw320) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw320) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw320) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw320) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw320) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw320) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+
+// combination 322/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.StringWriter
+type rw321 rwState
+
+func (w *rw321) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw321) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw321) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw321) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw321) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw321) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw321) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 323/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Pusher
+type rw322 rwState
+
+func (w *rw322) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw322) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw322) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw322) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw322) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw322) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw322) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 324/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Pusher, io.StringWriter
+type rw323 rwState
+
+func (w *rw323) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw323) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw323) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw323) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw323) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw323) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw323) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw323) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 325/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, fullDuplexEnabler
+type rw324 rwState
+
+func (w *rw324) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw324) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw324) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw324) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw324) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw324) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw324) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 326/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, fullDuplexEnabler, io.StringWriter
+type rw325 rwState
+
+func (w *rw325) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw325) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw325) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw325) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw325) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw325) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw325) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw325) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 327/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, fullDuplexEnabler, http.Pusher
+type rw326 rwState
+
+func (w *rw326) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw326) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw326) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw326) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw326) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw326) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw326) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw326) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 328/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw327 rwState
+
+func (w *rw327) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw327) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw327) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw327) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw327) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw327) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw327) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw327) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw327) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 329/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, deadliner
+type rw328 rwState
+
+func (w *rw328) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw328) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw328) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw328) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw328) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw328) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw328) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw328) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 330/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, deadliner, io.StringWriter
+type rw329 rwState
+
+func (w *rw329) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw329) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw329) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw329) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw329) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw329) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw329) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw329) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw329) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 331/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, deadliner, http.Pusher
+type rw330 rwState
+
+func (w *rw330) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw330) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw330) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw330) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw330) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw330) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw330) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw330) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw330) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 332/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, deadliner, http.Pusher, io.StringWriter
+type rw331 rwState
+
+func (w *rw331) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw331) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw331) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw331) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw331) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw331) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw331) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw331) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw331) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw331) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 333/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, deadliner, fullDuplexEnabler
+type rw332 rwState
+
+func (w *rw332) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw332) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw332) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw332) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw332) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw332) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw332) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw332) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw332) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 334/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, deadliner, fullDuplexEnabler, io.StringWriter
+type rw333 rwState
+
+func (w *rw333) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw333) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw333) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw333) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw333) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw333) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw333) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw333) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw333) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw333) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 335/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, deadliner, fullDuplexEnabler, http.Pusher
+type rw334 rwState
+
+func (w *rw334) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw334) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw334) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw334) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw334) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw334) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw334) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw334) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw334) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw334) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 336/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw335 rwState
+
+func (w *rw335) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw335) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw335) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw335) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw335) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw335) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw335) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw335) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw335) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw335) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw335) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 337/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom
+type rw336 rwState
+
+func (w *rw336) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw336) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw336) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw336) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw336) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw336) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw336) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 338/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, io.StringWriter
+type rw337 rwState
+
+func (w *rw337) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw337) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw337) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw337) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw337) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw337) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw337) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw337) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 339/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, http.Pusher
+type rw338 rwState
+
+func (w *rw338) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw338) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw338) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw338) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw338) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw338) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw338) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw338) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 340/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw339 rwState
+
+func (w *rw339) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw339) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw339) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw339) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw339) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw339) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw339) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw339) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw339) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 341/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler
+type rw340 rwState
+
+func (w *rw340) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw340) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw340) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw340) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw340) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw340) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw340) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw340) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 342/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw341 rwState
+
+func (w *rw341) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw341) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw341) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw341) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw341) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw341) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw341) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw341) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw341) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 343/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw342 rwState
+
+func (w *rw342) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw342) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw342) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw342) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw342) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw342) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw342) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw342) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw342) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 344/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw343 rwState
+
+func (w *rw343) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw343) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw343) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw343) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw343) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw343) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw343) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw343) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw343) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw343) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 345/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, deadliner
+type rw344 rwState
+
+func (w *rw344) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw344) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw344) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw344) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw344) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw344) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw344) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw344) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw344) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 346/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, deadliner, io.StringWriter
+type rw345 rwState
+
+func (w *rw345) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw345) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw345) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw345) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw345) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw345) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw345) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw345) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw345) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw345) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 347/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, deadliner, http.Pusher
+type rw346 rwState
+
+func (w *rw346) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw346) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw346) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw346) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw346) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw346) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw346) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw346) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw346) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw346) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 348/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw347 rwState
+
+func (w *rw347) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw347) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw347) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw347) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw347) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw347) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw347) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw347) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw347) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw347) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw347) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 349/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw348 rwState
+
+func (w *rw348) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw348) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw348) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw348) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw348) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw348) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw348) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw348) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw348) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw348) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 350/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw349 rwState
+
+func (w *rw349) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw349) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw349) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw349) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw349) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw349) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw349) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw349) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw349) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw349) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw349) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 351/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw350 rwState
+
+func (w *rw350) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw350) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw350) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw350) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw350) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw350) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw350) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw350) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw350) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw350) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw350) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 352/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw351 rwState
+
+func (w *rw351) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw351) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw351) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw351) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw351) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw351) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw351) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw351) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw351) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw351) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw351) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw351) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 353/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker
+type rw352 rwState
+
+func (w *rw352) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw352) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw352) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw352) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw352) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw352) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw352) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+
+// combination 354/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.StringWriter
+type rw353 rwState
+
+func (w *rw353) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw353) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw353) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw353) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw353) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw353) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw353) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw353) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 355/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, http.Pusher
+type rw354 rwState
+
+func (w *rw354) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw354) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw354) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw354) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw354) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw354) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw354) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw354) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 356/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, http.Pusher, io.StringWriter
+type rw355 rwState
+
+func (w *rw355) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw355) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw355) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw355) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw355) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw355) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw355) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw355) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw355) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 357/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, fullDuplexEnabler
+type rw356 rwState
+
+func (w *rw356) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw356) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw356) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw356) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw356) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw356) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw356) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw356) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 358/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, fullDuplexEnabler, io.StringWriter
+type rw357 rwState
+
+func (w *rw357) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw357) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw357) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw357) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw357) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw357) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw357) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw357) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw357) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 359/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, fullDuplexEnabler, http.Pusher
+type rw358 rwState
+
+func (w *rw358) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw358) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw358) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw358) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw358) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw358) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw358) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw358) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw358) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 360/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw359 rwState
+
+func (w *rw359) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw359) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw359) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw359) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw359) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw359) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw359) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw359) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw359) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw359) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 361/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, deadliner
+type rw360 rwState
+
+func (w *rw360) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw360) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw360) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw360) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw360) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw360) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw360) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw360) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw360) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 362/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, deadliner, io.StringWriter
+type rw361 rwState
+
+func (w *rw361) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw361) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw361) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw361) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw361) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw361) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw361) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw361) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw361) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw361) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 363/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, deadliner, http.Pusher
+type rw362 rwState
+
+func (w *rw362) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw362) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw362) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw362) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw362) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw362) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw362) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw362) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw362) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw362) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 364/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, deadliner, http.Pusher, io.StringWriter
+type rw363 rwState
+
+func (w *rw363) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw363) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw363) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw363) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw363) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw363) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw363) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw363) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw363) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw363) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw363) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 365/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler
+type rw364 rwState
+
+func (w *rw364) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw364) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw364) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw364) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw364) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw364) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw364) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw364) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw364) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw364) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 366/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler, io.StringWriter
+type rw365 rwState
+
+func (w *rw365) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw365) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw365) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw365) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw365) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw365) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw365) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw365) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw365) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw365) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw365) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 367/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher
+type rw366 rwState
+
+func (w *rw366) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw366) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw366) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw366) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw366) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw366) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw366) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw366) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw366) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw366) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw366) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 368/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw367 rwState
+
+func (w *rw367) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw367) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw367) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw367) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw367) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw367) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw367) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw367) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw367) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw367) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw367) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw367) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 369/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom
+type rw368 rwState
+
+func (w *rw368) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw368) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw368) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw368) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw368) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw368) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw368) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw368) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 370/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, io.StringWriter
+type rw369 rwState
+
+func (w *rw369) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw369) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw369) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw369) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw369) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw369) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw369) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw369) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw369) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 371/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, http.Pusher
+type rw370 rwState
+
+func (w *rw370) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw370) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw370) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw370) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw370) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw370) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw370) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw370) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw370) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 372/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw371 rwState
+
+func (w *rw371) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw371) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw371) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw371) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw371) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw371) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw371) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw371) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw371) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw371) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 373/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler
+type rw372 rwState
+
+func (w *rw372) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw372) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw372) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw372) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw372) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw372) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw372) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw372) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw372) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 374/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw373 rwState
+
+func (w *rw373) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw373) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw373) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw373) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw373) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw373) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw373) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw373) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw373) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw373) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 375/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw374 rwState
+
+func (w *rw374) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw374) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw374) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw374) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw374) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw374) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw374) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw374) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw374) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw374) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 376/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw375 rwState
+
+func (w *rw375) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw375) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw375) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw375) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw375) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw375) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw375) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw375) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw375) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw375) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw375) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 377/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner
+type rw376 rwState
+
+func (w *rw376) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw376) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw376) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw376) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw376) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw376) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw376) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw376) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw376) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw376) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 378/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, io.StringWriter
+type rw377 rwState
+
+func (w *rw377) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw377) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw377) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw377) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw377) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw377) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw377) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw377) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw377) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw377) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw377) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 379/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher
+type rw378 rwState
+
+func (w *rw378) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw378) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw378) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw378) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw378) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw378) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw378) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw378) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw378) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw378) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw378) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 380/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw379 rwState
+
+func (w *rw379) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw379) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw379) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw379) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw379) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw379) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw379) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw379) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw379) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw379) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw379) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw379) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 381/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw380 rwState
+
+func (w *rw380) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw380) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw380) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw380) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw380) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw380) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw380) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw380) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw380) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw380) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw380) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 382/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw381 rwState
+
+func (w *rw381) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw381) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw381) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw381) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw381) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw381) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw381) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw381) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw381) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw381) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw381) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw381) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 383/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw382 rwState
+
+func (w *rw382) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw382) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw382) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw382) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw382) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw382) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw382) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw382) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw382) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw382) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw382) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw382) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 384/512: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw383 rwState
+
+func (w *rw383) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw383) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw383) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw383) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw383) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw383) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw383) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw383) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw383) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw383) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw383) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw383) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw383) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 385/512: http.ResponseWriter, http.Flusher, httpFlushError
+type rw384 rwState
+
+func (w *rw384) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw384) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw384) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw384) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw384) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw384) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+
+// combination 386/512: http.ResponseWriter, http.Flusher, httpFlushError, io.StringWriter
+type rw385 rwState
+
+func (w *rw385) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw385) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw385) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw385) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw385) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw385) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw385) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 387/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Pusher
+type rw386 rwState
+
+func (w *rw386) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw386) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw386) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw386) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw386) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw386) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw386) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 388/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Pusher, io.StringWriter
+type rw387 rwState
+
+func (w *rw387) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw387) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw387) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw387) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw387) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw387) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw387) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw387) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 389/512: http.ResponseWriter, http.Flusher, httpFlushError, fullDuplexEnabler
+type rw388 rwState
+
+func (w *rw388) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw388) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw388) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw388) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw388) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw388) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw388) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 390/512: http.ResponseWriter, http.Flusher, httpFlushError, fullDuplexEnabler, io.StringWriter
+type rw389 rwState
+
+func (w *rw389) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw389) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw389) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw389) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw389) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw389) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw389) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw389) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 391/512: http.ResponseWriter, http.Flusher, httpFlushError, fullDuplexEnabler, http.Pusher
+type rw390 rwState
+
+func (w *rw390) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw390) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw390) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw390) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw390) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw390) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw390) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw390) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 392/512: http.ResponseWriter, http.Flusher, httpFlushError, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw391 rwState
+
+func (w *rw391) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw391) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw391) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw391) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw391) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw391) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw391) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw391) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw391) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 393/512: http.ResponseWriter, http.Flusher, httpFlushError, deadliner
+type rw392 rwState
+
+func (w *rw392) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw392) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw392) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw392) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw392) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw392) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw392) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw392) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 394/512: http.ResponseWriter, http.Flusher, httpFlushError, deadliner, io.StringWriter
+type rw393 rwState
+
+func (w *rw393) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw393) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw393) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw393) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw393) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw393) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw393) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw393) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw393) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 395/512: http.ResponseWriter, http.Flusher, httpFlushError, deadliner, http.Pusher
+type rw394 rwState
+
+func (w *rw394) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw394) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw394) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw394) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw394) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw394) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw394) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw394) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw394) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 396/512: http.ResponseWriter, http.Flusher, httpFlushError, deadliner, http.Pusher, io.StringWriter
+type rw395 rwState
+
+func (w *rw395) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw395) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw395) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw395) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw395) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw395) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw395) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw395) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw395) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw395) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 397/512: http.ResponseWriter, http.Flusher, httpFlushError, deadliner, fullDuplexEnabler
+type rw396 rwState
+
+func (w *rw396) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw396) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw396) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw396) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw396) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw396) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw396) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw396) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw396) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 398/512: http.ResponseWriter, http.Flusher, httpFlushError, deadliner, fullDuplexEnabler, io.StringWriter
+type rw397 rwState
+
+func (w *rw397) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw397) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw397) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw397) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw397) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw397) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw397) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw397) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw397) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw397) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 399/512: http.ResponseWriter, http.Flusher, httpFlushError, deadliner, fullDuplexEnabler, http.Pusher
+type rw398 rwState
+
+func (w *rw398) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw398) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw398) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw398) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw398) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw398) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw398) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw398) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw398) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw398) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 400/512: http.ResponseWriter, http.Flusher, httpFlushError, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw399 rwState
+
+func (w *rw399) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw399) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw399) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw399) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw399) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw399) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw399) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw399) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw399) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw399) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw399) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 401/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom
+type rw400 rwState
+
+func (w *rw400) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw400) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw400) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw400) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw400) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw400) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw400) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 402/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, io.StringWriter
+type rw401 rwState
+
+func (w *rw401) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw401) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw401) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw401) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw401) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw401) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw401) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw401) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 403/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, http.Pusher
+type rw402 rwState
+
+func (w *rw402) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw402) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw402) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw402) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw402) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw402) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw402) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw402) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 404/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw403 rwState
+
+func (w *rw403) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw403) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw403) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw403) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw403) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw403) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw403) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw403) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw403) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 405/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, fullDuplexEnabler
+type rw404 rwState
+
+func (w *rw404) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw404) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw404) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw404) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw404) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw404) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw404) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw404) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 406/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw405 rwState
+
+func (w *rw405) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw405) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw405) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw405) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw405) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw405) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw405) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw405) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw405) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 407/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw406 rwState
+
+func (w *rw406) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw406) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw406) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw406) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw406) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw406) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw406) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw406) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw406) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 408/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw407 rwState
+
+func (w *rw407) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw407) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw407) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw407) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw407) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw407) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw407) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw407) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw407) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw407) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 409/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, deadliner
+type rw408 rwState
+
+func (w *rw408) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw408) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw408) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw408) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw408) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw408) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw408) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw408) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw408) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 410/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, deadliner, io.StringWriter
+type rw409 rwState
+
+func (w *rw409) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw409) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw409) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw409) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw409) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw409) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw409) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw409) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw409) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw409) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 411/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, deadliner, http.Pusher
+type rw410 rwState
+
+func (w *rw410) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw410) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw410) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw410) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw410) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw410) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw410) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw410) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw410) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw410) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 412/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw411 rwState
+
+func (w *rw411) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw411) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw411) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw411) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw411) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw411) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw411) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw411) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw411) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw411) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw411) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 413/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw412 rwState
+
+func (w *rw412) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw412) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw412) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw412) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw412) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw412) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw412) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw412) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw412) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw412) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 414/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw413 rwState
+
+func (w *rw413) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw413) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw413) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw413) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw413) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw413) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw413) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw413) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw413) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw413) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw413) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 415/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw414 rwState
+
+func (w *rw414) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw414) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw414) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw414) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw414) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw414) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw414) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw414) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw414) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw414) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw414) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 416/512: http.ResponseWriter, http.Flusher, httpFlushError, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw415 rwState
+
+func (w *rw415) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw415) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw415) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw415) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw415) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw415) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw415) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw415) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw415) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw415) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw415) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw415) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 417/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker
+type rw416 rwState
+
+func (w *rw416) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw416) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw416) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw416) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw416) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw416) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw416) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+
+// combination 418/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.StringWriter
+type rw417 rwState
+
+func (w *rw417) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw417) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw417) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw417) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw417) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw417) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw417) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw417) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 419/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, http.Pusher
+type rw418 rwState
+
+func (w *rw418) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw418) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw418) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw418) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw418) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw418) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw418) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw418) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 420/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, http.Pusher, io.StringWriter
+type rw419 rwState
+
+func (w *rw419) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw419) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw419) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw419) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw419) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw419) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw419) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw419) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw419) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 421/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, fullDuplexEnabler
+type rw420 rwState
+
+func (w *rw420) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw420) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw420) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw420) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw420) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw420) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw420) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw420) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 422/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, fullDuplexEnabler, io.StringWriter
+type rw421 rwState
+
+func (w *rw421) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw421) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw421) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw421) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw421) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw421) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw421) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw421) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw421) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 423/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, fullDuplexEnabler, http.Pusher
+type rw422 rwState
+
+func (w *rw422) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw422) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw422) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw422) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw422) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw422) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw422) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw422) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw422) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 424/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw423 rwState
+
+func (w *rw423) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw423) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw423) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw423) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw423) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw423) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw423) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw423) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw423) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw423) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 425/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, deadliner
+type rw424 rwState
+
+func (w *rw424) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw424) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw424) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw424) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw424) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw424) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw424) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw424) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw424) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 426/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, deadliner, io.StringWriter
+type rw425 rwState
+
+func (w *rw425) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw425) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw425) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw425) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw425) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw425) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw425) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw425) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw425) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw425) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 427/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, deadliner, http.Pusher
+type rw426 rwState
+
+func (w *rw426) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw426) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw426) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw426) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw426) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw426) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw426) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw426) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw426) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw426) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 428/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, deadliner, http.Pusher, io.StringWriter
+type rw427 rwState
+
+func (w *rw427) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw427) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw427) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw427) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw427) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw427) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw427) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw427) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw427) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw427) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw427) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 429/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, deadliner, fullDuplexEnabler
+type rw428 rwState
+
+func (w *rw428) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw428) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw428) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw428) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw428) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw428) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw428) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw428) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw428) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw428) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 430/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, deadliner, fullDuplexEnabler, io.StringWriter
+type rw429 rwState
+
+func (w *rw429) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw429) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw429) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw429) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw429) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw429) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw429) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw429) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw429) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw429) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw429) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 431/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher
+type rw430 rwState
+
+func (w *rw430) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw430) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw430) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw430) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw430) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw430) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw430) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw430) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw430) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw430) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw430) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 432/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw431 rwState
+
+func (w *rw431) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw431) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw431) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw431) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw431) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw431) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw431) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw431) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw431) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw431) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw431) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw431) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 433/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom
+type rw432 rwState
+
+func (w *rw432) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw432) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw432) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw432) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw432) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw432) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw432) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw432) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 434/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, io.StringWriter
+type rw433 rwState
+
+func (w *rw433) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw433) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw433) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw433) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw433) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw433) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw433) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw433) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw433) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 435/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, http.Pusher
+type rw434 rwState
+
+func (w *rw434) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw434) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw434) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw434) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw434) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw434) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw434) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw434) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw434) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 436/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw435 rwState
+
+func (w *rw435) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw435) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw435) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw435) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw435) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw435) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw435) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw435) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw435) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw435) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 437/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, fullDuplexEnabler
+type rw436 rwState
+
+func (w *rw436) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw436) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw436) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw436) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw436) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw436) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw436) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw436) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw436) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 438/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw437 rwState
+
+func (w *rw437) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw437) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw437) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw437) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw437) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw437) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw437) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw437) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw437) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw437) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 439/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw438 rwState
+
+func (w *rw438) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw438) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw438) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw438) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw438) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw438) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw438) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw438) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw438) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw438) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 440/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw439 rwState
+
+func (w *rw439) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw439) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw439) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw439) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw439) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw439) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw439) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw439) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw439) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw439) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw439) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 441/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner
+type rw440 rwState
+
+func (w *rw440) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw440) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw440) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw440) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw440) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw440) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw440) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw440) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw440) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw440) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 442/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, io.StringWriter
+type rw441 rwState
+
+func (w *rw441) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw441) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw441) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw441) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw441) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw441) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw441) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw441) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw441) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw441) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw441) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 443/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher
+type rw442 rwState
+
+func (w *rw442) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw442) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw442) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw442) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw442) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw442) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw442) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw442) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw442) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw442) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw442) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 444/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw443 rwState
+
+func (w *rw443) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw443) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw443) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw443) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw443) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw443) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw443) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw443) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw443) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw443) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw443) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw443) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 445/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw444 rwState
+
+func (w *rw444) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw444) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw444) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw444) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw444) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw444) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw444) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw444) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw444) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw444) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw444) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 446/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw445 rwState
+
+func (w *rw445) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw445) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw445) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw445) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw445) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw445) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw445) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw445) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw445) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw445) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw445) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw445) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 447/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw446 rwState
+
+func (w *rw446) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw446) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw446) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw446) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw446) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw446) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw446) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw446) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw446) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw446) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw446) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw446) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 448/512: http.ResponseWriter, http.Flusher, httpFlushError, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw447 rwState
+
+func (w *rw447) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw447) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw447) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw447) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw447) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw447) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw447) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw447) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw447) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw447) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw447) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw447) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw447) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 449/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier
+type rw448 rwState
+
+func (w *rw448) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw448) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw448) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw448) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw448) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw448) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw448) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+
+// combination 450/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.StringWriter
+type rw449 rwState
+
+func (w *rw449) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw449) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw449) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw449) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw449) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw449) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw449) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw449) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 451/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Pusher
+type rw450 rwState
+
+func (w *rw450) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw450) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw450) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw450) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw450) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw450) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw450) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw450) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 452/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Pusher, io.StringWriter
+type rw451 rwState
+
+func (w *rw451) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw451) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw451) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw451) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw451) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw451) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw451) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw451) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw451) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 453/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, fullDuplexEnabler
+type rw452 rwState
+
+func (w *rw452) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw452) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw452) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw452) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw452) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw452) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw452) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw452) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 454/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, fullDuplexEnabler, io.StringWriter
+type rw453 rwState
+
+func (w *rw453) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw453) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw453) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw453) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw453) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw453) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw453) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw453) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw453) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 455/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, fullDuplexEnabler, http.Pusher
+type rw454 rwState
+
+func (w *rw454) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw454) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw454) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw454) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw454) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw454) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw454) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw454) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw454) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 456/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw455 rwState
+
+func (w *rw455) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw455) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw455) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw455) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw455) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw455) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw455) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw455) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw455) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw455) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 457/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, deadliner
+type rw456 rwState
+
+func (w *rw456) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw456) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw456) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw456) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw456) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw456) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw456) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw456) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw456) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 458/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, deadliner, io.StringWriter
+type rw457 rwState
+
+func (w *rw457) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw457) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw457) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw457) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw457) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw457) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw457) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw457) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw457) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw457) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 459/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, deadliner, http.Pusher
+type rw458 rwState
+
+func (w *rw458) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw458) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw458) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw458) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw458) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw458) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw458) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw458) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw458) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw458) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 460/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, deadliner, http.Pusher, io.StringWriter
+type rw459 rwState
+
+func (w *rw459) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw459) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw459) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw459) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw459) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw459) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw459) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw459) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw459) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw459) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw459) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 461/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, deadliner, fullDuplexEnabler
+type rw460 rwState
+
+func (w *rw460) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw460) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw460) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw460) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw460) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw460) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw460) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw460) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw460) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw460) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 462/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, deadliner, fullDuplexEnabler, io.StringWriter
+type rw461 rwState
+
+func (w *rw461) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw461) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw461) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw461) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw461) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw461) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw461) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw461) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw461) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw461) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw461) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 463/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, deadliner, fullDuplexEnabler, http.Pusher
+type rw462 rwState
+
+func (w *rw462) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw462) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw462) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw462) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw462) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw462) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw462) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw462) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw462) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw462) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw462) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 464/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw463 rwState
+
+func (w *rw463) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw463) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw463) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw463) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw463) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw463) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw463) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw463) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw463) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw463) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw463) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw463) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 465/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom
+type rw464 rwState
+
+func (w *rw464) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw464) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw464) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw464) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw464) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw464) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw464) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw464) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 466/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, io.StringWriter
+type rw465 rwState
+
+func (w *rw465) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw465) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw465) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw465) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw465) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw465) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw465) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw465) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw465) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 467/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, http.Pusher
+type rw466 rwState
+
+func (w *rw466) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw466) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw466) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw466) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw466) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw466) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw466) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw466) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw466) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 468/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw467 rwState
+
+func (w *rw467) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw467) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw467) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw467) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw467) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw467) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw467) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw467) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw467) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw467) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 469/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler
+type rw468 rwState
+
+func (w *rw468) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw468) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw468) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw468) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw468) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw468) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw468) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw468) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw468) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 470/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw469 rwState
+
+func (w *rw469) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw469) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw469) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw469) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw469) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw469) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw469) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw469) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw469) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw469) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 471/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw470 rwState
+
+func (w *rw470) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw470) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw470) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw470) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw470) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw470) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw470) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw470) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw470) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw470) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 472/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw471 rwState
+
+func (w *rw471) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw471) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw471) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw471) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw471) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw471) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw471) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw471) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw471) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw471) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw471) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 473/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner
+type rw472 rwState
+
+func (w *rw472) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw472) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw472) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw472) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw472) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw472) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw472) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw472) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw472) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw472) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 474/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, io.StringWriter
+type rw473 rwState
+
+func (w *rw473) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw473) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw473) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw473) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw473) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw473) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw473) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw473) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw473) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw473) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw473) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 475/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, http.Pusher
+type rw474 rwState
+
+func (w *rw474) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw474) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw474) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw474) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw474) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw474) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw474) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw474) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw474) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw474) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw474) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 476/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw475 rwState
+
+func (w *rw475) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw475) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw475) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw475) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw475) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw475) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw475) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw475) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw475) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw475) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw475) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw475) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 477/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw476 rwState
+
+func (w *rw476) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw476) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw476) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw476) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw476) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw476) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw476) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw476) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw476) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw476) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw476) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 478/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw477 rwState
+
+func (w *rw477) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw477) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw477) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw477) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw477) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw477) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw477) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw477) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw477) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw477) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw477) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw477) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 479/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw478 rwState
+
+func (w *rw478) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw478) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw478) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw478) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw478) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw478) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw478) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw478) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw478) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw478) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw478) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw478) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 480/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw479 rwState
+
+func (w *rw479) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw479) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw479) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw479) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw479) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw479) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw479) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw479) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw479) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw479) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw479) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw479) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw479) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 481/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker
+type rw480 rwState
+
+func (w *rw480) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw480) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw480) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw480) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw480) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw480) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw480) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw480) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+
+// combination 482/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.StringWriter
+type rw481 rwState
+
+func (w *rw481) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw481) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw481) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw481) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw481) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw481) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw481) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw481) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw481) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 483/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, http.Pusher
+type rw482 rwState
+
+func (w *rw482) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw482) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw482) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw482) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw482) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw482) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw482) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw482) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw482) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 484/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, http.Pusher, io.StringWriter
+type rw483 rwState
+
+func (w *rw483) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw483) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw483) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw483) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw483) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw483) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw483) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw483) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw483) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw483) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 485/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, fullDuplexEnabler
+type rw484 rwState
+
+func (w *rw484) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw484) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw484) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw484) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw484) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw484) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw484) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw484) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw484) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 486/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, fullDuplexEnabler, io.StringWriter
+type rw485 rwState
+
+func (w *rw485) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw485) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw485) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw485) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw485) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw485) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw485) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw485) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw485) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw485) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 487/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, fullDuplexEnabler, http.Pusher
+type rw486 rwState
+
+func (w *rw486) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw486) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw486) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw486) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw486) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw486) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw486) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw486) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw486) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw486) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 488/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw487 rwState
+
+func (w *rw487) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw487) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw487) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw487) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw487) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw487) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw487) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw487) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw487) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw487) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw487) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 489/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner
+type rw488 rwState
+
+func (w *rw488) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw488) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw488) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw488) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw488) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw488) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw488) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw488) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw488) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw488) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 490/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, io.StringWriter
+type rw489 rwState
+
+func (w *rw489) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw489) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw489) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw489) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw489) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw489) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw489) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw489) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw489) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw489) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw489) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 491/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, http.Pusher
+type rw490 rwState
+
+func (w *rw490) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw490) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw490) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw490) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw490) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw490) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw490) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw490) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw490) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw490) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw490) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 492/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, http.Pusher, io.StringWriter
+type rw491 rwState
+
+func (w *rw491) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw491) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw491) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw491) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw491) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw491) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw491) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw491) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw491) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw491) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw491) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw491) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 493/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler
+type rw492 rwState
+
+func (w *rw492) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw492) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw492) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw492) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw492) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw492) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw492) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw492) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw492) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw492) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw492) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 494/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler, io.StringWriter
+type rw493 rwState
+
+func (w *rw493) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw493) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw493) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw493) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw493) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw493) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw493) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw493) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw493) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw493) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw493) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw493) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 495/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher
+type rw494 rwState
+
+func (w *rw494) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw494) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw494) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw494) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw494) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw494) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw494) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw494) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw494) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw494) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw494) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw494) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 496/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw495 rwState
+
+func (w *rw495) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw495) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw495) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw495) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw495) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw495) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw495) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw495) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw495) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw495) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw495) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw495) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw495) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 497/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom
+type rw496 rwState
+
+func (w *rw496) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw496) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw496) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw496) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw496) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw496) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw496) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw496) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw496) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+
+// combination 498/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, io.StringWriter
+type rw497 rwState
+
+func (w *rw497) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw497) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw497) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw497) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw497) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw497) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw497) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw497) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw497) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw497) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 499/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, http.Pusher
+type rw498 rwState
+
+func (w *rw498) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw498) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw498) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw498) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw498) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw498) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw498) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw498) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw498) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw498) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 500/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, http.Pusher, io.StringWriter
+type rw499 rwState
+
+func (w *rw499) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw499) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw499) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw499) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw499) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw499) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw499) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw499) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw499) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw499) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw499) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 501/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler
+type rw500 rwState
+
+func (w *rw500) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw500) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw500) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw500) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw500) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw500) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw500) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw500) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw500) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw500) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 502/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, io.StringWriter
+type rw501 rwState
+
+func (w *rw501) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw501) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw501) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw501) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw501) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw501) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw501) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw501) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw501) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw501) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw501) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 503/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher
+type rw502 rwState
+
+func (w *rw502) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw502) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw502) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw502) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw502) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw502) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw502) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw502) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw502) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw502) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw502) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 504/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw503 rwState
+
+func (w *rw503) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw503) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw503) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw503) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw503) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw503) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw503) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw503) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw503) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw503) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw503) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw503) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 505/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner
+type rw504 rwState
+
+func (w *rw504) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw504) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw504) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw504) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw504) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw504) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw504) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw504) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw504) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw504) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw504) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+
+// combination 506/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, io.StringWriter
+type rw505 rwState
+
+func (w *rw505) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw505) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw505) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw505) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw505) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw505) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw505) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw505) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw505) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw505) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw505) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw505) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 507/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher
+type rw506 rwState
+
+func (w *rw506) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw506) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw506) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw506) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw506) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw506) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw506) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw506) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw506) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw506) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw506) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw506) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 508/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, http.Pusher, io.StringWriter
+type rw507 rwState
+
+func (w *rw507) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw507) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw507) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw507) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw507) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw507) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw507) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw507) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw507) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw507) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw507) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw507) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw507) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 509/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler
+type rw508 rwState
+
+func (w *rw508) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw508) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw508) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw508) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw508) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw508) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw508) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw508) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw508) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw508) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw508) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw508) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+
+// combination 510/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, io.StringWriter
+type rw509 rwState
+
+func (w *rw509) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw509) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw509) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw509) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw509) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw509) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw509) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw509) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw509) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw509) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw509) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw509) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw509) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+// combination 511/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher
+type rw510 rwState
+
+func (w *rw510) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw510) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw510) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw510) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw510) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw510) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw510) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw510) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw510) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw510) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw510) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw510) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw510) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+
+// combination 512/512: http.ResponseWriter, http.Flusher, httpFlushError, http.CloseNotifier, http.Hijacker, io.ReaderFrom, deadliner, fullDuplexEnabler, http.Pusher, io.StringWriter
+type rw511 rwState
+
+func (w *rw511) Unwrap() http.ResponseWriter { return w.w }
+func (w *rw511) Header() http.Header {
+ return (*rwState)(w).doHeader()
+}
+func (w *rw511) WriteHeader(code int) {
+ (*rwState)(w).doWriteHeader(code)
+}
+func (w *rw511) Write(b []byte) (int, error) {
+ return (*rwState)(w).doWrite(b)
+}
+func (w *rw511) Flush() {
+ (*rwState)(w).doFlush()
+}
+func (w *rw511) FlushError() error {
+ return (*rwState)(w).doFlushError()
+}
+func (w *rw511) CloseNotify() <-chan bool {
+ return (*rwState)(w).doCloseNotify()
+}
+func (w *rw511) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return (*rwState)(w).doHijack()
+}
+func (w *rw511) ReadFrom(src io.Reader) (int64, error) {
+ return (*rwState)(w).doReadFrom(src)
+}
+func (w *rw511) SetReadDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetReadDeadline(deadline)
+}
+func (w *rw511) SetWriteDeadline(deadline time.Time) error {
+ return (*rwState)(w).doSetWriteDeadline(deadline)
+}
+func (w *rw511) EnableFullDuplex() error {
+ return (*rwState)(w).doEnableFullDuplex()
+}
+func (w *rw511) Push(target string, opts *http.PushOptions) error {
+ return (*rwState)(w).doPush(target, opts)
+}
+func (w *rw511) WriteString(s string) (int, error) {
+ return (*rwState)(w).doWriteString(s)
+}
+
+type Unwrapper interface {
+ Unwrap() http.ResponseWriter
+}
+
+// Unwrap returns the underlying http.ResponseWriter from within zero or more
+// layers of httpsnoop wrappers.
+func Unwrap(w http.ResponseWriter) http.ResponseWriter {
+ if rw, ok := w.(Unwrapper); ok {
+ // recurse until rw.Unwrap() returns a non-Unwrapper
+ return Unwrap(rw.Unwrap())
+ }
+ return w
+}
diff --git a/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go b/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go
deleted file mode 100644
index 101cedde674..00000000000
--- a/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go
+++ /dev/null
@@ -1,436 +0,0 @@
-// +build go1.8
-// Code generated by "httpsnoop/codegen"; DO NOT EDIT.
-
-package httpsnoop
-
-import (
- "bufio"
- "io"
- "net"
- "net/http"
-)
-
-// HeaderFunc is part of the http.ResponseWriter interface.
-type HeaderFunc func() http.Header
-
-// WriteHeaderFunc is part of the http.ResponseWriter interface.
-type WriteHeaderFunc func(code int)
-
-// WriteFunc is part of the http.ResponseWriter interface.
-type WriteFunc func(b []byte) (int, error)
-
-// FlushFunc is part of the http.Flusher interface.
-type FlushFunc func()
-
-// CloseNotifyFunc is part of the http.CloseNotifier interface.
-type CloseNotifyFunc func() <-chan bool
-
-// HijackFunc is part of the http.Hijacker interface.
-type HijackFunc func() (net.Conn, *bufio.ReadWriter, error)
-
-// ReadFromFunc is part of the io.ReaderFrom interface.
-type ReadFromFunc func(src io.Reader) (int64, error)
-
-// PushFunc is part of the http.Pusher interface.
-type PushFunc func(target string, opts *http.PushOptions) error
-
-// Hooks defines a set of method interceptors for methods included in
-// http.ResponseWriter as well as some others. You can think of them as
-// middleware for the function calls they target. See Wrap for more details.
-type Hooks struct {
- Header func(HeaderFunc) HeaderFunc
- WriteHeader func(WriteHeaderFunc) WriteHeaderFunc
- Write func(WriteFunc) WriteFunc
- Flush func(FlushFunc) FlushFunc
- CloseNotify func(CloseNotifyFunc) CloseNotifyFunc
- Hijack func(HijackFunc) HijackFunc
- ReadFrom func(ReadFromFunc) ReadFromFunc
- Push func(PushFunc) PushFunc
-}
-
-// Wrap returns a wrapped version of w that provides the exact same interface
-// as w. Specifically if w implements any combination of:
-//
-// - http.Flusher
-// - http.CloseNotifier
-// - http.Hijacker
-// - io.ReaderFrom
-// - http.Pusher
-//
-// The wrapped version will implement the exact same combination. If no hooks
-// are set, the wrapped version also behaves exactly as w. Hooks targeting
-// methods not supported by w are ignored. Any other hooks will intercept the
-// method they target and may modify the call's arguments and/or return values.
-// The CaptureMetrics implementation serves as a working example for how the
-// hooks can be used.
-func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter {
- rw := &rw{w: w, h: hooks}
- _, i0 := w.(http.Flusher)
- _, i1 := w.(http.CloseNotifier)
- _, i2 := w.(http.Hijacker)
- _, i3 := w.(io.ReaderFrom)
- _, i4 := w.(http.Pusher)
- switch {
- // combination 1/32
- case !i0 && !i1 && !i2 && !i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- }{rw, rw}
- // combination 2/32
- case !i0 && !i1 && !i2 && !i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Pusher
- }{rw, rw, rw}
- // combination 3/32
- case !i0 && !i1 && !i2 && i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- io.ReaderFrom
- }{rw, rw, rw}
- // combination 4/32
- case !i0 && !i1 && !i2 && i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- io.ReaderFrom
- http.Pusher
- }{rw, rw, rw, rw}
- // combination 5/32
- case !i0 && !i1 && i2 && !i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Hijacker
- }{rw, rw, rw}
- // combination 6/32
- case !i0 && !i1 && i2 && !i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Hijacker
- http.Pusher
- }{rw, rw, rw, rw}
- // combination 7/32
- case !i0 && !i1 && i2 && i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Hijacker
- io.ReaderFrom
- }{rw, rw, rw, rw}
- // combination 8/32
- case !i0 && !i1 && i2 && i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Hijacker
- io.ReaderFrom
- http.Pusher
- }{rw, rw, rw, rw, rw}
- // combination 9/32
- case !i0 && i1 && !i2 && !i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.CloseNotifier
- }{rw, rw, rw}
- // combination 10/32
- case !i0 && i1 && !i2 && !i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.CloseNotifier
- http.Pusher
- }{rw, rw, rw, rw}
- // combination 11/32
- case !i0 && i1 && !i2 && i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.CloseNotifier
- io.ReaderFrom
- }{rw, rw, rw, rw}
- // combination 12/32
- case !i0 && i1 && !i2 && i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.CloseNotifier
- io.ReaderFrom
- http.Pusher
- }{rw, rw, rw, rw, rw}
- // combination 13/32
- case !i0 && i1 && i2 && !i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.CloseNotifier
- http.Hijacker
- }{rw, rw, rw, rw}
- // combination 14/32
- case !i0 && i1 && i2 && !i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.CloseNotifier
- http.Hijacker
- http.Pusher
- }{rw, rw, rw, rw, rw}
- // combination 15/32
- case !i0 && i1 && i2 && i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.CloseNotifier
- http.Hijacker
- io.ReaderFrom
- }{rw, rw, rw, rw, rw}
- // combination 16/32
- case !i0 && i1 && i2 && i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.CloseNotifier
- http.Hijacker
- io.ReaderFrom
- http.Pusher
- }{rw, rw, rw, rw, rw, rw}
- // combination 17/32
- case i0 && !i1 && !i2 && !i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- }{rw, rw, rw}
- // combination 18/32
- case i0 && !i1 && !i2 && !i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.Pusher
- }{rw, rw, rw, rw}
- // combination 19/32
- case i0 && !i1 && !i2 && i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- io.ReaderFrom
- }{rw, rw, rw, rw}
- // combination 20/32
- case i0 && !i1 && !i2 && i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- io.ReaderFrom
- http.Pusher
- }{rw, rw, rw, rw, rw}
- // combination 21/32
- case i0 && !i1 && i2 && !i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.Hijacker
- }{rw, rw, rw, rw}
- // combination 22/32
- case i0 && !i1 && i2 && !i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.Hijacker
- http.Pusher
- }{rw, rw, rw, rw, rw}
- // combination 23/32
- case i0 && !i1 && i2 && i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.Hijacker
- io.ReaderFrom
- }{rw, rw, rw, rw, rw}
- // combination 24/32
- case i0 && !i1 && i2 && i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.Hijacker
- io.ReaderFrom
- http.Pusher
- }{rw, rw, rw, rw, rw, rw}
- // combination 25/32
- case i0 && i1 && !i2 && !i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.CloseNotifier
- }{rw, rw, rw, rw}
- // combination 26/32
- case i0 && i1 && !i2 && !i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.CloseNotifier
- http.Pusher
- }{rw, rw, rw, rw, rw}
- // combination 27/32
- case i0 && i1 && !i2 && i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.CloseNotifier
- io.ReaderFrom
- }{rw, rw, rw, rw, rw}
- // combination 28/32
- case i0 && i1 && !i2 && i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.CloseNotifier
- io.ReaderFrom
- http.Pusher
- }{rw, rw, rw, rw, rw, rw}
- // combination 29/32
- case i0 && i1 && i2 && !i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.CloseNotifier
- http.Hijacker
- }{rw, rw, rw, rw, rw}
- // combination 30/32
- case i0 && i1 && i2 && !i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.CloseNotifier
- http.Hijacker
- http.Pusher
- }{rw, rw, rw, rw, rw, rw}
- // combination 31/32
- case i0 && i1 && i2 && i3 && !i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.CloseNotifier
- http.Hijacker
- io.ReaderFrom
- }{rw, rw, rw, rw, rw, rw}
- // combination 32/32
- case i0 && i1 && i2 && i3 && i4:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.CloseNotifier
- http.Hijacker
- io.ReaderFrom
- http.Pusher
- }{rw, rw, rw, rw, rw, rw, rw}
- }
- panic("unreachable")
-}
-
-type rw struct {
- w http.ResponseWriter
- h Hooks
-}
-
-func (w *rw) Unwrap() http.ResponseWriter {
- return w.w
-}
-
-func (w *rw) Header() http.Header {
- f := w.w.(http.ResponseWriter).Header
- if w.h.Header != nil {
- f = w.h.Header(f)
- }
- return f()
-}
-
-func (w *rw) WriteHeader(code int) {
- f := w.w.(http.ResponseWriter).WriteHeader
- if w.h.WriteHeader != nil {
- f = w.h.WriteHeader(f)
- }
- f(code)
-}
-
-func (w *rw) Write(b []byte) (int, error) {
- f := w.w.(http.ResponseWriter).Write
- if w.h.Write != nil {
- f = w.h.Write(f)
- }
- return f(b)
-}
-
-func (w *rw) Flush() {
- f := w.w.(http.Flusher).Flush
- if w.h.Flush != nil {
- f = w.h.Flush(f)
- }
- f()
-}
-
-func (w *rw) CloseNotify() <-chan bool {
- f := w.w.(http.CloseNotifier).CloseNotify
- if w.h.CloseNotify != nil {
- f = w.h.CloseNotify(f)
- }
- return f()
-}
-
-func (w *rw) Hijack() (net.Conn, *bufio.ReadWriter, error) {
- f := w.w.(http.Hijacker).Hijack
- if w.h.Hijack != nil {
- f = w.h.Hijack(f)
- }
- return f()
-}
-
-func (w *rw) ReadFrom(src io.Reader) (int64, error) {
- f := w.w.(io.ReaderFrom).ReadFrom
- if w.h.ReadFrom != nil {
- f = w.h.ReadFrom(f)
- }
- return f(src)
-}
-
-func (w *rw) Push(target string, opts *http.PushOptions) error {
- f := w.w.(http.Pusher).Push
- if w.h.Push != nil {
- f = w.h.Push(f)
- }
- return f(target, opts)
-}
-
-type Unwrapper interface {
- Unwrap() http.ResponseWriter
-}
-
-// Unwrap returns the underlying http.ResponseWriter from within zero or more
-// layers of httpsnoop wrappers.
-func Unwrap(w http.ResponseWriter) http.ResponseWriter {
- if rw, ok := w.(Unwrapper); ok {
- // recurse until rw.Unwrap() returns a non-Unwrapper
- return Unwrap(rw.Unwrap())
- } else {
- return w
- }
-}
diff --git a/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go b/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go
deleted file mode 100644
index e0951df1527..00000000000
--- a/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go
+++ /dev/null
@@ -1,278 +0,0 @@
-// +build !go1.8
-// Code generated by "httpsnoop/codegen"; DO NOT EDIT.
-
-package httpsnoop
-
-import (
- "bufio"
- "io"
- "net"
- "net/http"
-)
-
-// HeaderFunc is part of the http.ResponseWriter interface.
-type HeaderFunc func() http.Header
-
-// WriteHeaderFunc is part of the http.ResponseWriter interface.
-type WriteHeaderFunc func(code int)
-
-// WriteFunc is part of the http.ResponseWriter interface.
-type WriteFunc func(b []byte) (int, error)
-
-// FlushFunc is part of the http.Flusher interface.
-type FlushFunc func()
-
-// CloseNotifyFunc is part of the http.CloseNotifier interface.
-type CloseNotifyFunc func() <-chan bool
-
-// HijackFunc is part of the http.Hijacker interface.
-type HijackFunc func() (net.Conn, *bufio.ReadWriter, error)
-
-// ReadFromFunc is part of the io.ReaderFrom interface.
-type ReadFromFunc func(src io.Reader) (int64, error)
-
-// Hooks defines a set of method interceptors for methods included in
-// http.ResponseWriter as well as some others. You can think of them as
-// middleware for the function calls they target. See Wrap for more details.
-type Hooks struct {
- Header func(HeaderFunc) HeaderFunc
- WriteHeader func(WriteHeaderFunc) WriteHeaderFunc
- Write func(WriteFunc) WriteFunc
- Flush func(FlushFunc) FlushFunc
- CloseNotify func(CloseNotifyFunc) CloseNotifyFunc
- Hijack func(HijackFunc) HijackFunc
- ReadFrom func(ReadFromFunc) ReadFromFunc
-}
-
-// Wrap returns a wrapped version of w that provides the exact same interface
-// as w. Specifically if w implements any combination of:
-//
-// - http.Flusher
-// - http.CloseNotifier
-// - http.Hijacker
-// - io.ReaderFrom
-//
-// The wrapped version will implement the exact same combination. If no hooks
-// are set, the wrapped version also behaves exactly as w. Hooks targeting
-// methods not supported by w are ignored. Any other hooks will intercept the
-// method they target and may modify the call's arguments and/or return values.
-// The CaptureMetrics implementation serves as a working example for how the
-// hooks can be used.
-func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter {
- rw := &rw{w: w, h: hooks}
- _, i0 := w.(http.Flusher)
- _, i1 := w.(http.CloseNotifier)
- _, i2 := w.(http.Hijacker)
- _, i3 := w.(io.ReaderFrom)
- switch {
- // combination 1/16
- case !i0 && !i1 && !i2 && !i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- }{rw, rw}
- // combination 2/16
- case !i0 && !i1 && !i2 && i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- io.ReaderFrom
- }{rw, rw, rw}
- // combination 3/16
- case !i0 && !i1 && i2 && !i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Hijacker
- }{rw, rw, rw}
- // combination 4/16
- case !i0 && !i1 && i2 && i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Hijacker
- io.ReaderFrom
- }{rw, rw, rw, rw}
- // combination 5/16
- case !i0 && i1 && !i2 && !i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.CloseNotifier
- }{rw, rw, rw}
- // combination 6/16
- case !i0 && i1 && !i2 && i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.CloseNotifier
- io.ReaderFrom
- }{rw, rw, rw, rw}
- // combination 7/16
- case !i0 && i1 && i2 && !i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.CloseNotifier
- http.Hijacker
- }{rw, rw, rw, rw}
- // combination 8/16
- case !i0 && i1 && i2 && i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.CloseNotifier
- http.Hijacker
- io.ReaderFrom
- }{rw, rw, rw, rw, rw}
- // combination 9/16
- case i0 && !i1 && !i2 && !i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- }{rw, rw, rw}
- // combination 10/16
- case i0 && !i1 && !i2 && i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- io.ReaderFrom
- }{rw, rw, rw, rw}
- // combination 11/16
- case i0 && !i1 && i2 && !i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.Hijacker
- }{rw, rw, rw, rw}
- // combination 12/16
- case i0 && !i1 && i2 && i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.Hijacker
- io.ReaderFrom
- }{rw, rw, rw, rw, rw}
- // combination 13/16
- case i0 && i1 && !i2 && !i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.CloseNotifier
- }{rw, rw, rw, rw}
- // combination 14/16
- case i0 && i1 && !i2 && i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.CloseNotifier
- io.ReaderFrom
- }{rw, rw, rw, rw, rw}
- // combination 15/16
- case i0 && i1 && i2 && !i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.CloseNotifier
- http.Hijacker
- }{rw, rw, rw, rw, rw}
- // combination 16/16
- case i0 && i1 && i2 && i3:
- return struct {
- Unwrapper
- http.ResponseWriter
- http.Flusher
- http.CloseNotifier
- http.Hijacker
- io.ReaderFrom
- }{rw, rw, rw, rw, rw, rw}
- }
- panic("unreachable")
-}
-
-type rw struct {
- w http.ResponseWriter
- h Hooks
-}
-
-func (w *rw) Unwrap() http.ResponseWriter {
- return w.w
-}
-
-func (w *rw) Header() http.Header {
- f := w.w.(http.ResponseWriter).Header
- if w.h.Header != nil {
- f = w.h.Header(f)
- }
- return f()
-}
-
-func (w *rw) WriteHeader(code int) {
- f := w.w.(http.ResponseWriter).WriteHeader
- if w.h.WriteHeader != nil {
- f = w.h.WriteHeader(f)
- }
- f(code)
-}
-
-func (w *rw) Write(b []byte) (int, error) {
- f := w.w.(http.ResponseWriter).Write
- if w.h.Write != nil {
- f = w.h.Write(f)
- }
- return f(b)
-}
-
-func (w *rw) Flush() {
- f := w.w.(http.Flusher).Flush
- if w.h.Flush != nil {
- f = w.h.Flush(f)
- }
- f()
-}
-
-func (w *rw) CloseNotify() <-chan bool {
- f := w.w.(http.CloseNotifier).CloseNotify
- if w.h.CloseNotify != nil {
- f = w.h.CloseNotify(f)
- }
- return f()
-}
-
-func (w *rw) Hijack() (net.Conn, *bufio.ReadWriter, error) {
- f := w.w.(http.Hijacker).Hijack
- if w.h.Hijack != nil {
- f = w.h.Hijack(f)
- }
- return f()
-}
-
-func (w *rw) ReadFrom(src io.Reader) (int64, error) {
- f := w.w.(io.ReaderFrom).ReadFrom
- if w.h.ReadFrom != nil {
- f = w.h.ReadFrom(f)
- }
- return f(src)
-}
-
-type Unwrapper interface {
- Unwrap() http.ResponseWriter
-}
-
-// Unwrap returns the underlying http.ResponseWriter from within zero or more
-// layers of httpsnoop wrappers.
-func Unwrap(w http.ResponseWriter) http.ResponseWriter {
- if rw, ok := w.(Unwrapper); ok {
- // recurse until rw.Unwrap() returns a non-Unwrapper
- return Unwrap(rw.Unwrap())
- } else {
- return w
- }
-}
diff --git a/vendor/github.com/fsnotify/fsnotify/.cirrus.yml b/vendor/github.com/fsnotify/fsnotify/.cirrus.yml
deleted file mode 100644
index 7f257e99ac9..00000000000
--- a/vendor/github.com/fsnotify/fsnotify/.cirrus.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-freebsd_task:
- name: 'FreeBSD'
- freebsd_instance:
- image_family: freebsd-14-2
- install_script:
- - pkg update -f
- - pkg install -y go
- test_script:
- # run tests as user "cirrus" instead of root
- - pw useradd cirrus -m
- - chown -R cirrus:cirrus .
- - FSNOTIFY_BUFFER=4096 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./...
- - sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./...
- - FSNOTIFY_DEBUG=1 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race -v ./...
diff --git a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
index 6468d2cf400..3027f3c67a2 100644
--- a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
+++ b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
@@ -1,5 +1,54 @@
# Changelog
+1.10.1 2026-05-04
+-----------------
+
+### Changes and fixes
+
+- inotify: don't remove sibling watches sharing a path prefix ([#754])
+
+- inotify, windows: don't rename sibling watches sharing a path prefix
+ ([#755])
+
+
+[#754]: https://github.com/fsnotify/fsnotify/pull/754
+[#755]: https://github.com/fsnotify/fsnotify/pull/755
+
+
+1.10.0 2026-04-30
+-----------------
+This version of fsnotify needs Go 1.23.
+
+### Changes and fixes
+
+- inotify: improve initialization error message ([#731])
+
+- inotify: send Rename event if recursive watch is renamed ([#696])
+
+- inotify: avoid copying event buffers when reading names ([#741])
+
+- kqueue: skip dangling symlinks (ENOENT) in watchDirectoryFiles, so a
+ bad entry no longer aborts Watcher.Add for the whole directory ([#748])
+
+- kqueue: drop watches directly in Close() to fix a file descriptor leak
+ when recycling watchers ([#740])
+
+- windows: fix nil pointer dereference in remWatch ([#736])
+
+- windows: lock watch field updates against concurrent WatchList to fix
+ a race introduced in v1.9.0 ([#709], [#749])
+
+
+[#696]: https://github.com/fsnotify/fsnotify/pull/696
+[#709]: https://github.com/fsnotify/fsnotify/pull/709
+[#731]: https://github.com/fsnotify/fsnotify/pull/731
+[#736]: https://github.com/fsnotify/fsnotify/pull/736
+[#740]: https://github.com/fsnotify/fsnotify/pull/740
+[#741]: https://github.com/fsnotify/fsnotify/pull/741
+[#748]: https://github.com/fsnotify/fsnotify/pull/748
+[#749]: https://github.com/fsnotify/fsnotify/pull/749
+
+
1.9.0 2024-04-04
----------------
diff --git a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
index 4cc40fa597d..cd0ee612da6 100644
--- a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
+++ b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
@@ -77,6 +77,8 @@ End-of-line escapes with `\` are not supported.
debug [yes/no] # Enable/disable FSNOTIFY_DEBUG (tests are run in
parallel by default, so -parallel=1 is probably a good
idea).
+ state # Print internal state to stderr (exact output differs
+ # per backend).
print [any strings] # Print text to stdout; for debugging.
touch path
diff --git a/vendor/github.com/fsnotify/fsnotify/README.md b/vendor/github.com/fsnotify/fsnotify/README.md
index 1f4eb583d50..2e56ef4c9a5 100644
--- a/vendor/github.com/fsnotify/fsnotify/README.md
+++ b/vendor/github.com/fsnotify/fsnotify/README.md
@@ -1,7 +1,7 @@
fsnotify is a Go library to provide cross-platform filesystem notifications on
Windows, Linux, macOS, BSD, and illumos.
-Go 1.17 or newer is required; the full documentation is at
+Go 1.23 or newer is required; the full documentation is at
https://pkg.go.dev/github.com/fsnotify/fsnotify
---
@@ -12,7 +12,7 @@ Platform support:
| :-------------------- | :--------- | :------------------------------------------------------------------------ |
| inotify | Linux | Supported |
| kqueue | BSD, macOS | Supported |
-| ReadDirectoryChangesW | Windows | Supported |
+| ReadDirectoryChangesW | Windows | Supported ([excluding `Chmod` operations][#487]) |
| FEN | illumos | Supported |
| fanotify | Linux 5.9+ | [Not yet](https://github.com/fsnotify/fsnotify/issues/114) |
| FSEvents | macOS | [Needs support in x/sys/unix][fsevents] |
@@ -22,6 +22,7 @@ Platform support:
Linux and illumos should include Android and Solaris, but these are currently
untested.
+[#487]: https://github.com/fsnotify/fsnotify/issues/487
[fsevents]: https://github.com/fsnotify/fsnotify/issues/11#issuecomment-1279133120
[usn]: https://github.com/fsnotify/fsnotify/issues/53#issuecomment-1279829847
@@ -126,7 +127,7 @@ settings* until we have a native FSEvents implementation (see [#11]).
### Watching a file doesn't work well
Watching individual files (rather than directories) is generally not recommended
as many programs (especially editors) update files atomically: it will write to
-a temporary file which is then moved to to destination, overwriting the original
+a temporary file which is then moved to a destination, overwriting the original
(or some variant thereof). The watcher on the original file is now lost, as that
no longer exists.
@@ -151,26 +152,57 @@ This is the event that inotify sends, so not much can be changed about this.
The `fs.inotify.max_user_watches` sysctl variable specifies the upper limit for
the number of watches per user, and `fs.inotify.max_user_instances` specifies
the maximum number of inotify instances per user. Every Watcher you create is an
-"instance", and every path you add is a "watch".
+"instance", and every path you add is a "watch". Reaching the limit will result
+in a "no space left on device" or "too many open files" error.
These are also exposed in `/proc` as `/proc/sys/fs/inotify/max_user_watches` and
-`/proc/sys/fs/inotify/max_user_instances`
+`/proc/sys/fs/inotify/max_user_instances`. The default values differ per distro
+and available memory.
To increase them you can use `sysctl` or write the value to proc file:
- # The default values on Linux 5.18
- sysctl fs.inotify.max_user_watches=124983
- sysctl fs.inotify.max_user_instances=128
+ sysctl fs.inotify.max_user_watches=200000
+ sysctl fs.inotify.max_user_instances=256
To make the changes persist on reboot edit `/etc/sysctl.conf` or
`/usr/lib/sysctl.d/50-default.conf` (details differ per Linux distro; check your
distro's documentation):
- fs.inotify.max_user_watches=124983
- fs.inotify.max_user_instances=128
+ fs.inotify.max_user_watches=200000
+ fs.inotify.max_user_instances=256
+
+### Windows
+Recursive watching is not currently enabled through fsnotify's public API
+(see the FAQ "Are subdirectories watched?" above). The notes below
+describe Windows backend behavior observed when recursive watching is
+enabled internally (for example, in fsnotify's own tests). They are kept
+here as a reference for maintainers and contributors who encounter the
+behavior, since the recursive code path still exists in the backend.
+
+When recursive watching is enabled and you watch a directory, you may
+receive a `Write` event for an intermediate directory whenever a child
+entry inside it is created, renamed, or removed. For example, with a
+recursive watch on `/a` and a new file `/a/b/c`, you will receive
+`Create /a/b/c` and may also receive `Write /a/b`.
+
+This happens because, on NTFS-backed volumes, modifying the entries of a
+directory updates that directory's last-write time, and the Windows
+backend requests `FILE_NOTIFY_CHANGE_LAST_WRITE` to support `Write` events
+on files. The same `Write` filter therefore picks up the directory's
+metadata update.
+
+kqueue has the same "directory `Write` = directory contents changed"
+semantics, so portable code that treats `Write` on a directory as
+"something inside it changed" works on Windows and BSD/macOS, but not on
+Linux (inotify uses `Write` only for file-content changes). If you only
+care about file content, filter out `Write` events whose path refers to a
+directory.
+
+Whether the directory `Write` is actually delivered alongside the child
+events is not guaranteed: it depends on `ReadDirectoryChangesW` buffering,
+NTFS metadata update timing, and event coalescing, none of which fsnotify
+controls.
-Reaching the limit will result in a "no space left on device" or "too many open
-files" error.
### kqueue (macOS, all BSD systems)
kqueue requires opening a file descriptor for every file that's being watched;
diff --git a/vendor/github.com/fsnotify/fsnotify/backend_fen.go b/vendor/github.com/fsnotify/fsnotify/backend_fen.go
index 57fc6928484..e43c6d088cc 100644
--- a/vendor/github.com/fsnotify/fsnotify/backend_fen.go
+++ b/vendor/github.com/fsnotify/fsnotify/backend_fen.go
@@ -158,7 +158,9 @@ func (w *fen) readEvents() {
pevents := make([]unix.PortEvent, 8)
for {
- count, err := w.port.Get(pevents, 1, nil)
+ count, err := internal.IgnoringEINTR(func() (int, error) {
+ return w.port.Get(pevents, 1, nil)
+ })
if err != nil && err != unix.ETIME {
// Interrupted system call (count should be 0) ignore and continue
if errors.Is(err, unix.EINTR) && count == 0 {
diff --git a/vendor/github.com/fsnotify/fsnotify/backend_inotify.go b/vendor/github.com/fsnotify/fsnotify/backend_inotify.go
index a36cb89d736..4c3f6f7c283 100644
--- a/vendor/github.com/fsnotify/fsnotify/backend_inotify.go
+++ b/vendor/github.com/fsnotify/fsnotify/backend_inotify.go
@@ -55,10 +55,10 @@ type (
path map[string]uint32 // pathname → wd
}
watch struct {
- wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
- flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
- path string // Watch path.
- recurse bool // Recursion with ./...?
+ wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
+ flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
+ path string // Watch path.
+ watchFlags watchFlag
}
koekje struct {
cookie uint32
@@ -66,6 +66,9 @@ type (
}
)
+func (w watch) byUser() bool { return w.watchFlags&flagByUser != 0 }
+func (w watch) recurse() bool { return w.watchFlags&flagRecurse != 0 }
+
func newWatches() *watches {
return &watches{
wd: make(map[uint32]*watch),
@@ -79,6 +82,13 @@ func (w *watches) len() int { return len(w.wd) }
func (w *watches) add(ww *watch) { w.wd[ww.wd] = ww; w.path[ww.path] = ww.wd }
func (w *watches) remove(watch *watch) { delete(w.path, watch.path); delete(w.wd, watch.wd) }
+func isSameOrDescendantPath(path, root string) bool {
+ if path == root {
+ return true
+ }
+ return strings.HasPrefix(path, root+string(os.PathSeparator))
+}
+
func (w *watches) removePath(path string) ([]uint32, error) {
path, recurse := recursivePath(path)
wd, ok := w.path[path]
@@ -87,20 +97,20 @@ func (w *watches) removePath(path string) ([]uint32, error) {
}
watch := w.wd[wd]
- if recurse && !watch.recurse {
+ if recurse && !watch.recurse() {
return nil, fmt.Errorf("can't use /... with non-recursive watch %q", path)
}
delete(w.path, path)
delete(w.wd, wd)
- if !watch.recurse {
+ if !watch.recurse() {
return []uint32{wd}, nil
}
wds := make([]uint32, 0, 8)
wds = append(wds, wd)
for p, rwd := range w.path {
- if strings.HasPrefix(p, path) {
+ if isSameOrDescendantPath(p, path) {
delete(w.path, p)
delete(w.wd, rwd)
wds = append(wds, rwd)
@@ -139,7 +149,7 @@ func newBackend(ev chan Event, errs chan error) (backend, error) {
// I/O operations won't terminate on close.
fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC | unix.IN_NONBLOCK)
if fd == -1 {
- return nil, errno
+ return nil, fmt.Errorf("couldn't initialize inotify: %w", errno)
}
w := &inotify{
@@ -188,11 +198,8 @@ func (w *inotify) AddWith(path string, opts ...addOpt) error {
return fmt.Errorf("%w: %s", xErrUnsupported, with.op)
}
- add := func(path string, with withOpts, recurse bool) error {
+ add := func(path string, with withOpts, wf watchFlag) error {
var flags uint32
- if with.noFollow {
- flags |= unix.IN_DONT_FOLLOW
- }
if with.op.Has(Create) {
flags |= unix.IN_CREATE
}
@@ -220,7 +227,7 @@ func (w *inotify) AddWith(path string, opts ...addOpt) error {
if with.op.Has(xUnportableCloseRead) {
flags |= unix.IN_CLOSE_NOWRITE
}
- return w.register(path, flags, recurse)
+ return w.register(path, flags, wf)
}
w.mu.Lock()
@@ -248,14 +255,18 @@ func (w *inotify) AddWith(path string, opts ...addOpt) error {
w.sendEvent(Event{Name: root, Op: Create})
}
- return add(root, with, true)
+ wf := flagRecurse
+ if root == path {
+ wf |= flagByUser
+ }
+ return add(root, with, wf)
})
}
- return add(path, with, false)
+ return add(path, with, 0)
}
-func (w *inotify) register(path string, flags uint32, recurse bool) error {
+func (w *inotify) register(path string, flags uint32, wf watchFlag) error {
return w.watches.updatePath(path, func(existing *watch) (*watch, error) {
if existing != nil {
flags |= existing.flags | unix.IN_MASK_ADD
@@ -272,10 +283,10 @@ func (w *inotify) register(path string, flags uint32, recurse bool) error {
if existing == nil {
return &watch{
- wd: uint32(wd),
- path: path,
- flags: flags,
- recurse: recurse,
+ wd: uint32(wd),
+ path: path,
+ flags: flags,
+ watchFlags: wf,
}, nil
}
@@ -425,11 +436,7 @@ func (w *inotify) handleEvent(inEvent *unix.InotifyEvent, buf *[65536]byte, offs
nameLen = uint32(inEvent.Len)
)
if nameLen > 0 {
- /// Point "bytes" at the first byte of the filename
- bb := *buf
- bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&bb[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen]
- /// The filename is padded with NULL bytes. TrimRight() gets rid of those.
- name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\x00")
+ name += "/" + inotifyEventName(buf, offset, nameLen)
}
if debug {
@@ -450,7 +457,9 @@ func (w *inotify) handleEvent(inEvent *unix.InotifyEvent, buf *[65536]byte, offs
// We can't really update the state when a watched path is moved; only
// IN_MOVE_SELF is sent and not IN_MOVED_{FROM,TO}. So remove the watch.
if inEvent.Mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF {
- if watch.recurse { // Do nothing
+ // Watch is set up as part of recurse: do nothing as the move gets
+ // registered from the parent directory.
+ if watch.recurse() && !watch.byUser() {
return Event{}, true
}
@@ -460,6 +469,10 @@ func (w *inotify) handleEvent(inEvent *unix.InotifyEvent, buf *[65536]byte, offs
return Event{}, false
}
}
+
+ if watch.recurse() {
+ return Event{Name: watch.path, Op: Rename}, true
+ }
}
/// Skip if we're watching both this path and the parent; the parent will
@@ -473,11 +486,11 @@ func (w *inotify) handleEvent(inEvent *unix.InotifyEvent, buf *[65536]byte, offs
ev := w.newEvent(name, inEvent.Mask, inEvent.Cookie)
// Need to update watch path for recurse.
- if watch.recurse {
+ if watch.recurse() {
isDir := inEvent.Mask&unix.IN_ISDIR == unix.IN_ISDIR
/// New directory created: set up watch on it.
if isDir && ev.Has(Create) {
- err := w.register(ev.Name, watch.flags, true)
+ err := w.register(ev.Name, watch.flags, flagRecurse)
if !w.sendError(err) {
return Event{}, false
}
@@ -495,7 +508,7 @@ func (w *inotify) handleEvent(inEvent *unix.InotifyEvent, buf *[65536]byte, offs
if k == watch.wd || ww.path == ev.Name {
continue
}
- if strings.HasPrefix(ww.path, ev.renamedFrom) {
+ if isSameOrDescendantPath(ww.path, ev.renamedFrom) {
ww.path = strings.Replace(ww.path, ev.renamedFrom, ev.Name, 1)
w.watches.wd[k] = ww
}
@@ -507,12 +520,13 @@ func (w *inotify) handleEvent(inEvent *unix.InotifyEvent, buf *[65536]byte, offs
return ev, true
}
-func (w *inotify) isRecursive(path string) bool {
- ww := w.watches.byPath(path)
- if ww == nil { // path could be a file, so also check the Dir.
- ww = w.watches.byPath(filepath.Dir(path))
+func inotifyEventName(buf *[65536]byte, offset, nameLen uint32) string {
+ start := int(offset + unix.SizeofInotifyEvent)
+ bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[start]))[:nameLen:nameLen]
+ for nameLen > 0 && bytes[nameLen-1] == 0 {
+ nameLen--
}
- return ww != nil && ww.recurse
+ return string(bytes[:nameLen])
}
func (w *inotify) newEvent(name string, mask, cookie uint32) Event {
@@ -578,6 +592,6 @@ func (w *inotify) state() {
w.mu.Lock()
defer w.mu.Unlock()
for wd, ww := range w.watches.wd {
- fmt.Fprintf(os.Stderr, "%4d: recurse=%t %q\n", wd, ww.recurse, ww.path)
+ fmt.Fprintf(os.Stderr, "%4d: %q watchFlags=0x%x\n", wd, ww.path, ww.watchFlags)
}
}
diff --git a/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go b/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
index 340aeec061c..d2c8cfb6c6a 100644
--- a/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
+++ b/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
@@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"runtime"
+ "sort"
"sync"
"time"
@@ -245,9 +246,26 @@ func (w *kqueue) Close() error {
return nil
}
+ // Snapshot and drop all watches directly. w.Remove -> w.remove
+ // short-circuits on isClosed() (which is already true after
+ // w.shared.close() above), so calling Remove here in the happy path
+ // leaked every watched directory + file descriptor. On macOS a
+ // single directory watch opens an fd for every file in the dir, so
+ // long-running processes that recreate watchers (hot-reload dev
+ // servers, etc.) ran out of fds with EMFILE (#732).
pathsToRemove := w.watches.listPaths(false)
for _, name := range pathsToRemove {
- w.Remove(name)
+ info, ok := w.watches.byPath(name)
+ if !ok {
+ // w.path has an entry for name but w.wd doesn't --
+ // drop the stale lookup entry so the map state is
+ // consistent after Close.
+ w.watches.remove(0, name)
+ continue
+ }
+ _ = w.register([]int{info.wd}, unix.EV_DELETE, 0)
+ unix.Close(info.wd)
+ w.watches.remove(info.wd, name)
}
unix.Close(w.closepipe[1]) // Send "quit" message to readEvents
@@ -376,19 +394,12 @@ func (w *kqueue) addWatch(name string, flags uint32, listDir bool) (string, erro
}
}
- // Retry on EINTR; open() can return EINTR in practice on macOS.
- // See #354, and Go issues 11180 and 39237.
- for {
- info.wd, err = unix.Open(name, openMode, 0)
- if err == nil {
- break
- }
- if errors.Is(err, unix.EINTR) {
- continue
- }
+ info.wd, err = internal.IgnoringEINTR(func() (int, error) {
+ return unix.Open(name, openMode, 0)
+ })
+ if err != nil {
return "", err
}
-
info.isDir = fi.IsDir()
}
@@ -436,9 +447,10 @@ func (w *kqueue) readEvents() {
eventBuffer := make([]unix.Kevent_t, 10)
for {
- kevents, err := w.read(eventBuffer)
- // EINTR is okay, the syscall was interrupted before timeout expired.
- if err != nil && err != unix.EINTR {
+ kevents, err := internal.IgnoringEINTR(func() ([]unix.Kevent_t, error) {
+ return w.read(eventBuffer)
+ })
+ if err != nil {
if !w.sendError(fmt.Errorf("fsnotify.readEvents: %w", err)) {
return
}
@@ -583,12 +595,14 @@ func (w *kqueue) watchDirectoryFiles(dirPath string) error {
cleanPath, err := w.internalWatch(path, fi)
if err != nil {
- // No permission to read the file; that's not a problem: just skip.
- // But do add it to w.fileExists to prevent it from being picked up
- // as a "new" file later (it still shows up in the directory
+ // No permission, or the entry resolved to a missing target
+ // (e.g. a dangling symlink): not a problem, just skip. But
+ // do mark it as seen to prevent it from being picked up as
+ // a "new" file later (it still shows up in the directory
// listing).
switch {
- case errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM):
+ case errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM) ||
+ errors.Is(err, os.ErrNotExist):
cleanPath = filepath.Clean(path)
default:
return fmt.Errorf("%q: %w", path, err)
@@ -703,3 +717,19 @@ func (w *kqueue) xSupports(op Op) bool {
}
return true
}
+
+func (w *kqueue) state() {
+ w.watches.mu.Lock()
+ defer w.watches.mu.Unlock()
+
+ all := make([]int, 0, len(w.watches.wd))
+ for wd := range w.watches.wd {
+ all = append(all, wd)
+ }
+ sort.Ints(all)
+
+ for _, wd := range all {
+ ww := w.watches.wd[wd]
+ fmt.Fprintf(os.Stderr, "%4d %q linkname=%q\n", wd, ww.name, ww.linkName)
+ }
+}
diff --git a/vendor/github.com/fsnotify/fsnotify/backend_windows.go b/vendor/github.com/fsnotify/fsnotify/backend_windows.go
index 3433642d641..fb9210f24ed 100644
--- a/vendor/github.com/fsnotify/fsnotify/backend_windows.go
+++ b/vendor/github.com/fsnotify/fsnotify/backend_windows.go
@@ -11,7 +11,6 @@ import (
"fmt"
"os"
"path/filepath"
- "reflect"
"runtime"
"strings"
"sync"
@@ -37,6 +36,13 @@ type readDirChangesW struct {
var defaultBufferSize = 50
+func isSameOrDescendantPath(path, root string) bool {
+ if path == root {
+ return true
+ }
+ return strings.HasPrefix(path, root+string(os.PathSeparator))
+}
+
func newBackend(ev chan Event, errs chan error) (backend, error) {
port, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0)
if err != nil {
@@ -359,22 +365,26 @@ func (w *readDirChangesW) addWatch(pathname string, flags uint64, bufsize int) e
} else {
windows.CloseHandle(ino.handle)
}
+ w.mu.Lock()
if pathname == dir {
watchEntry.mask |= flags
} else {
watchEntry.names[filepath.Base(pathname)] |= flags
}
+ w.mu.Unlock()
err = w.startRead(watchEntry)
if err != nil {
return err
}
+ w.mu.Lock()
if pathname == dir {
watchEntry.mask &= ^provisional
} else {
watchEntry.names[filepath.Base(pathname)] &= ^provisional
}
+ w.mu.Unlock()
return nil
}
@@ -394,8 +404,13 @@ func (w *readDirChangesW) remWatch(pathname string) error {
w.mu.Lock()
watch := w.watches.get(ino)
w.mu.Unlock()
+ if watch == nil {
+ windows.CloseHandle(ino.handle)
+ return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname)
+ }
if recurse && !watch.recurse {
+ windows.CloseHandle(ino.handle)
return fmt.Errorf("can't use \\... with non-recursive watch %q", pathname)
}
@@ -403,16 +418,19 @@ func (w *readDirChangesW) remWatch(pathname string) error {
if err != nil {
w.sendError(os.NewSyscallError("CloseHandle", err))
}
- if watch == nil {
- return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname)
- }
if pathname == dir {
- w.sendEvent(watch.path, "", watch.mask&sysFSIGNORED)
+ w.mu.Lock()
+ mask := watch.mask
watch.mask = 0
+ w.mu.Unlock()
+ w.sendEvent(watch.path, "", mask&sysFSIGNORED)
} else {
name := filepath.Base(pathname)
- w.sendEvent(filepath.Join(watch.path, name), "", watch.names[name]&sysFSIGNORED)
+ w.mu.Lock()
+ mask := watch.names[name]
delete(watch.names, name)
+ w.mu.Unlock()
+ w.sendEvent(filepath.Join(watch.path, name), "", mask&sysFSIGNORED)
}
return w.startRead(watch)
@@ -420,17 +438,23 @@ func (w *readDirChangesW) remWatch(pathname string) error {
// Must run within the I/O thread.
func (w *readDirChangesW) deleteWatch(watch *watch) {
- for name, mask := range watch.names {
- if mask&provisional == 0 {
- w.sendEvent(filepath.Join(watch.path, name), "", mask&sysFSIGNORED)
+ // Snapshot+clear under the lock so concurrent WatchList() readers see a
+ // consistent state. sendEvent must run outside the lock since it can
+ // block on the user-facing Events channel.
+ w.mu.Lock()
+ names := watch.names
+ watch.names = make(map[string]uint64)
+ mask := watch.mask
+ watch.mask = 0
+ w.mu.Unlock()
+
+ for name, m := range names {
+ if m&provisional == 0 {
+ w.sendEvent(filepath.Join(watch.path, name), "", m&sysFSIGNORED)
}
- delete(watch.names, name)
}
- if watch.mask != 0 {
- if watch.mask&provisional == 0 {
- w.sendEvent(watch.path, "", watch.mask&sysFSIGNORED)
- }
- watch.mask = 0
+ if mask != 0 && mask&provisional == 0 {
+ w.sendEvent(watch.path, "", mask&sysFSIGNORED)
}
}
@@ -457,9 +481,8 @@ func (w *readDirChangesW) startRead(watch *watch) error {
}
// We need to pass the array, rather than the slice.
- hdr := (*reflect.SliceHeader)(unsafe.Pointer(&watch.buf))
rdErr := windows.ReadDirectoryChanges(watch.ino.handle,
- (*byte)(unsafe.Pointer(hdr.Data)), uint32(hdr.Len),
+ unsafe.SliceData(watch.buf), uint32(len(watch.buf)),
watch.recurse, mask, nil, &watch.ov, 0)
if rdErr != nil {
err := os.NewSyscallError("ReadDirectoryChanges", rdErr)
@@ -565,12 +588,7 @@ func (w *readDirChangesW) readEvents() {
// Create a buf that is the size of the path name
size := int(raw.FileNameLength / 2)
- var buf []uint16
- // TODO: Use unsafe.Slice in Go 1.17; https://stackoverflow.com/questions/51187973
- sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
- sh.Data = uintptr(unsafe.Pointer(&raw.FileName))
- sh.Len = size
- sh.Cap = size
+ buf := unsafe.Slice(&raw.FileName, size)
name := windows.UTF16ToString(buf)
fullname := filepath.Join(watch.path, name)
@@ -587,31 +605,35 @@ func (w *readDirChangesW) readEvents() {
case windows.FILE_ACTION_RENAMED_OLD_NAME:
watch.rename = name
case windows.FILE_ACTION_RENAMED_NEW_NAME:
- // Update saved path of all sub-watches.
+ // Update saved path of all sub-watches and rename the
+ // names entry under the lock so WatchList() can't observe
+ // a torn state.
old := filepath.Join(watch.path, watch.rename)
w.mu.Lock()
for _, watchMap := range w.watches {
for _, ww := range watchMap {
- if strings.HasPrefix(ww.path, old) {
+ if isSameOrDescendantPath(ww.path, old) {
ww.path = filepath.Join(fullname, strings.TrimPrefix(ww.path, old))
}
}
}
- w.mu.Unlock()
-
if watch.names[watch.rename] != 0 {
watch.names[name] |= watch.names[watch.rename]
delete(watch.names, watch.rename)
mask = sysFSMOVESELF
}
+ w.mu.Unlock()
}
if raw.Action != windows.FILE_ACTION_RENAMED_NEW_NAME {
w.sendEvent(fullname, "", watch.names[name]&mask)
}
if raw.Action == windows.FILE_ACTION_REMOVED {
- w.sendEvent(fullname, "", watch.names[name]&sysFSIGNORED)
+ w.mu.Lock()
+ ignored := watch.names[name] & sysFSIGNORED
delete(watch.names, name)
+ w.mu.Unlock()
+ w.sendEvent(fullname, "", ignored)
}
if watch.rename != "" && raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME {
diff --git a/vendor/github.com/fsnotify/fsnotify/fsnotify.go b/vendor/github.com/fsnotify/fsnotify/fsnotify.go
index f64be4bf98e..38cb4dd481c 100644
--- a/vendor/github.com/fsnotify/fsnotify/fsnotify.go
+++ b/vendor/github.com/fsnotify/fsnotify/fsnotify.go
@@ -51,26 +51,25 @@ import (
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
// for the number of watches per user, and fs.inotify.max_user_instances
// specifies the maximum number of inotify instances per user. Every Watcher you
-// create is an "instance", and every path you add is a "watch".
+// create is an "instance", and every path you add is a "watch". Reaching the
+// limit will result in a "no space left on device" or "too many open files"
+// error.
//
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
-// /proc/sys/fs/inotify/max_user_instances
+// /proc/sys/fs/inotify/max_user_instances. The default values differ per distro
+// and available memory.
//
// To increase them you can use sysctl or write the value to the /proc file:
//
-// # Default values on Linux 5.18
-// sysctl fs.inotify.max_user_watches=124983
-// sysctl fs.inotify.max_user_instances=128
+// sysctl fs.inotify.max_user_watches=200000
+// sysctl fs.inotify.max_user_instances=256
//
// To make the changes persist on reboot edit /etc/sysctl.conf or
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
// your distro's documentation):
//
-// fs.inotify.max_user_watches=124983
-// fs.inotify.max_user_instances=128
-//
-// Reaching the limit will result in a "no space left on device" or "too many open
-// files" error.
+// fs.inotify.max_user_watches=200000
+// fs.inotify.max_user_instances=256
//
// # kqueue notes (macOS, BSD)
//
@@ -93,6 +92,28 @@ import (
// Sometimes it will send events for all files, sometimes it will send no
// events, and often only for some files.
//
+// Recursive watching is not currently enabled through fsnotify's public
+// API; the recursive code path is gated and only exercised by fsnotify's
+// own tests. The note below describes backend behavior observed when
+// recursive watching is enabled internally, and is kept here as a
+// reference for maintainers and contributors who encounter it.
+//
+// When recursive watching is enabled and you watch a directory, you may
+// receive a Write event for an intermediate directory whenever a child
+// entry inside it is created, renamed, or removed. For example, with a
+// recursive watch on /a and a new file /a/b/c, you will receive
+// Create /a/b/c and may also receive Write /a/b.
+//
+// This happens because, on NTFS-backed volumes, modifying the entries of a
+// directory updates that directory's last-write time, and the Windows
+// backend requests FILE_NOTIFY_CHANGE_LAST_WRITE to support Write events
+// on files. The same Write filter therefore picks up the directory's
+// metadata update.
+//
+// Whether the directory Write is actually delivered alongside the child
+// events is not guaranteed; it depends on ReadDirectoryChangesW buffering,
+// NTFS metadata update timing, and event coalescing.
+//
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
// value that is guaranteed to work with SMB filesystems. If you have many
// events in quick succession this may not be enough, and you will have to use
@@ -129,8 +150,12 @@ type Watcher struct {
// want to wait until you've stopped receiving them
// (see the dedup example in cmd/fsnotify).
//
- // Some systems may send Write event for directories
- // when the directory content changes.
+ // Some systems also send Write events for directories
+ // when the directory contents change. This is the
+ // case for kqueue, and on Windows for the directory
+ // that contains a created, renamed, or removed child
+ // entry. It does not happen on inotify. See the
+ // per-platform notes on [Watcher].
//
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
// when a file is removed (or more accurately, when a
@@ -179,7 +204,9 @@ const (
Create Op = 1 << iota
// The pathname was written to; this does *not* mean the write has finished,
- // and a write can be followed by more writes.
+ // and a write can be followed by more writes. On Windows and kqueue, a
+ // Write on a directory can also indicate that its contents changed; see
+ // the per-platform notes on [Watcher].
Write
// The path was removed; any watches on it will be removed. Some "remove"
@@ -220,7 +247,7 @@ const (
// File opened for reading was closed.
//
- // Only works on Linux and FreeBSD.
+ // Only works on Linux.
xUnportableCloseRead
)
@@ -410,7 +437,6 @@ type (
withOpts struct {
bufsize int
op Op
- noFollow bool
sendCreate bool
}
)
@@ -469,12 +495,6 @@ func withOps(op Op) addOpt {
return func(opt *withOpts) { opt.op = op }
}
-// WithNoFollow disables following symlinks, so the symlinks themselves are
-// watched.
-func withNoFollow() addOpt {
- return func(opt *withOpts) { opt.noFollow = true }
-}
-
// "Internal" option for recursive watches on inotify.
func withCreate() addOpt {
return func(opt *withOpts) { opt.sendCreate = true }
@@ -494,3 +514,13 @@ func recursivePath(path string) (string, bool) {
}
return path, false
}
+
+type watchFlag uint8
+
+const (
+ // Added by user with Add(), rather than an internal watch.
+ flagByUser = watchFlag(0x01)
+ // Part of recursive watch; as the top-level path added by the user or an
+ // "internal" watch.
+ flagRecurse = watchFlag(0x02)
+)
diff --git a/vendor/github.com/fsnotify/fsnotify/internal/darwin.go b/vendor/github.com/fsnotify/fsnotify/internal/darwin.go
index 0b01bc182a1..6721aa60968 100644
--- a/vendor/github.com/fsnotify/fsnotify/internal/darwin.go
+++ b/vendor/github.com/fsnotify/fsnotify/internal/darwin.go
@@ -15,25 +15,6 @@ var (
var maxfiles uint64
-func SetRlimit() {
- // Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
- var l syscall.Rlimit
- err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
- if err == nil && l.Cur != l.Max {
- l.Cur = l.Max
- syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l)
- }
- maxfiles = l.Cur
-
- if n, err := syscall.SysctlUint32("kern.maxfiles"); err == nil && uint64(n) < maxfiles {
- maxfiles = uint64(n)
- }
-
- if n, err := syscall.SysctlUint32("kern.maxfilesperproc"); err == nil && uint64(n) < maxfiles {
- maxfiles = uint64(n)
- }
-}
-
func Maxfiles() uint64 { return maxfiles }
func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) }
func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, dev) }
diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go
index 928319fb09a..7600180742b 100644
--- a/vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go
+++ b/vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go
@@ -6,52 +6,10 @@ var names = []struct {
n string
m uint32
}{
- {"NOTE_ABSOLUTE", unix.NOTE_ABSOLUTE},
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
- {"NOTE_BACKGROUND", unix.NOTE_BACKGROUND},
- {"NOTE_CHILD", unix.NOTE_CHILD},
- {"NOTE_CRITICAL", unix.NOTE_CRITICAL},
{"NOTE_DELETE", unix.NOTE_DELETE},
- {"NOTE_EXEC", unix.NOTE_EXEC},
- {"NOTE_EXIT", unix.NOTE_EXIT},
- {"NOTE_EXITSTATUS", unix.NOTE_EXITSTATUS},
- {"NOTE_EXIT_CSERROR", unix.NOTE_EXIT_CSERROR},
- {"NOTE_EXIT_DECRYPTFAIL", unix.NOTE_EXIT_DECRYPTFAIL},
- {"NOTE_EXIT_DETAIL", unix.NOTE_EXIT_DETAIL},
- {"NOTE_EXIT_DETAIL_MASK", unix.NOTE_EXIT_DETAIL_MASK},
- {"NOTE_EXIT_MEMORY", unix.NOTE_EXIT_MEMORY},
- {"NOTE_EXIT_REPARENTED", unix.NOTE_EXIT_REPARENTED},
{"NOTE_EXTEND", unix.NOTE_EXTEND},
- {"NOTE_FFAND", unix.NOTE_FFAND},
- {"NOTE_FFCOPY", unix.NOTE_FFCOPY},
- {"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK},
- {"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK},
- {"NOTE_FFNOP", unix.NOTE_FFNOP},
- {"NOTE_FFOR", unix.NOTE_FFOR},
- {"NOTE_FORK", unix.NOTE_FORK},
- {"NOTE_FUNLOCK", unix.NOTE_FUNLOCK},
- {"NOTE_LEEWAY", unix.NOTE_LEEWAY},
{"NOTE_LINK", unix.NOTE_LINK},
- {"NOTE_LOWAT", unix.NOTE_LOWAT},
- {"NOTE_MACHTIME", unix.NOTE_MACHTIME},
- {"NOTE_MACH_CONTINUOUS_TIME", unix.NOTE_MACH_CONTINUOUS_TIME},
- {"NOTE_NONE", unix.NOTE_NONE},
- {"NOTE_NSECONDS", unix.NOTE_NSECONDS},
- {"NOTE_OOB", unix.NOTE_OOB},
- //{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, -0x100000 (?!)
- {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
- {"NOTE_REAP", unix.NOTE_REAP},
{"NOTE_RENAME", unix.NOTE_RENAME},
- {"NOTE_REVOKE", unix.NOTE_REVOKE},
- {"NOTE_SECONDS", unix.NOTE_SECONDS},
- {"NOTE_SIGNAL", unix.NOTE_SIGNAL},
- {"NOTE_TRACK", unix.NOTE_TRACK},
- {"NOTE_TRACKERR", unix.NOTE_TRACKERR},
- {"NOTE_TRIGGER", unix.NOTE_TRIGGER},
- {"NOTE_USECONDS", unix.NOTE_USECONDS},
- {"NOTE_VM_ERROR", unix.NOTE_VM_ERROR},
- {"NOTE_VM_PRESSURE", unix.NOTE_VM_PRESSURE},
- {"NOTE_VM_PRESSURE_SUDDEN_TERMINATE", unix.NOTE_VM_PRESSURE_SUDDEN_TERMINATE},
- {"NOTE_VM_PRESSURE_TERMINATE", unix.NOTE_VM_PRESSURE_TERMINATE},
{"NOTE_WRITE", unix.NOTE_WRITE},
}
diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go
index 3186b0c3491..7600180742b 100644
--- a/vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go
+++ b/vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go
@@ -7,27 +7,9 @@ var names = []struct {
m uint32
}{
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
- {"NOTE_CHILD", unix.NOTE_CHILD},
{"NOTE_DELETE", unix.NOTE_DELETE},
- {"NOTE_EXEC", unix.NOTE_EXEC},
- {"NOTE_EXIT", unix.NOTE_EXIT},
{"NOTE_EXTEND", unix.NOTE_EXTEND},
- {"NOTE_FFAND", unix.NOTE_FFAND},
- {"NOTE_FFCOPY", unix.NOTE_FFCOPY},
- {"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK},
- {"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK},
- {"NOTE_FFNOP", unix.NOTE_FFNOP},
- {"NOTE_FFOR", unix.NOTE_FFOR},
- {"NOTE_FORK", unix.NOTE_FORK},
{"NOTE_LINK", unix.NOTE_LINK},
- {"NOTE_LOWAT", unix.NOTE_LOWAT},
- {"NOTE_OOB", unix.NOTE_OOB},
- {"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
- {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
{"NOTE_RENAME", unix.NOTE_RENAME},
- {"NOTE_REVOKE", unix.NOTE_REVOKE},
- {"NOTE_TRACK", unix.NOTE_TRACK},
- {"NOTE_TRACKERR", unix.NOTE_TRACKERR},
- {"NOTE_TRIGGER", unix.NOTE_TRIGGER},
{"NOTE_WRITE", unix.NOTE_WRITE},
}
diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go
index f69fdb930f5..b9e45f55512 100644
--- a/vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go
+++ b/vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go
@@ -6,37 +6,15 @@ var names = []struct {
n string
m uint32
}{
- {"NOTE_ABSTIME", unix.NOTE_ABSTIME},
- {"NOTE_ATTRIB", unix.NOTE_ATTRIB},
- {"NOTE_CHILD", unix.NOTE_CHILD},
- {"NOTE_CLOSE", unix.NOTE_CLOSE},
- {"NOTE_CLOSE_WRITE", unix.NOTE_CLOSE_WRITE},
{"NOTE_DELETE", unix.NOTE_DELETE},
- {"NOTE_EXEC", unix.NOTE_EXEC},
- {"NOTE_EXIT", unix.NOTE_EXIT},
+ {"NOTE_WRITE", unix.NOTE_WRITE},
{"NOTE_EXTEND", unix.NOTE_EXTEND},
- {"NOTE_FFAND", unix.NOTE_FFAND},
- {"NOTE_FFCOPY", unix.NOTE_FFCOPY},
- {"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK},
- {"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK},
- {"NOTE_FFNOP", unix.NOTE_FFNOP},
- {"NOTE_FFOR", unix.NOTE_FFOR},
- {"NOTE_FILE_POLL", unix.NOTE_FILE_POLL},
- {"NOTE_FORK", unix.NOTE_FORK},
+ {"NOTE_ATTRIB", unix.NOTE_ATTRIB},
{"NOTE_LINK", unix.NOTE_LINK},
- {"NOTE_LOWAT", unix.NOTE_LOWAT},
- {"NOTE_MSECONDS", unix.NOTE_MSECONDS},
- {"NOTE_NSECONDS", unix.NOTE_NSECONDS},
- {"NOTE_OPEN", unix.NOTE_OPEN},
- {"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
- {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
- {"NOTE_READ", unix.NOTE_READ},
{"NOTE_RENAME", unix.NOTE_RENAME},
{"NOTE_REVOKE", unix.NOTE_REVOKE},
- {"NOTE_SECONDS", unix.NOTE_SECONDS},
- {"NOTE_TRACK", unix.NOTE_TRACK},
- {"NOTE_TRACKERR", unix.NOTE_TRACKERR},
- {"NOTE_TRIGGER", unix.NOTE_TRIGGER},
- {"NOTE_USECONDS", unix.NOTE_USECONDS},
- {"NOTE_WRITE", unix.NOTE_WRITE},
+ {"NOTE_OPEN", unix.NOTE_OPEN},
+ {"NOTE_CLOSE", unix.NOTE_CLOSE},
+ {"NOTE_CLOSE_WRITE", unix.NOTE_CLOSE_WRITE},
+ {"NOTE_READ", unix.NOTE_READ},
}
diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go
index 607e683bd73..5d8116436db 100644
--- a/vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go
+++ b/vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go
@@ -27,6 +27,6 @@ func Debug(name string, kevent *unix.Kevent_t) {
if unknown > 0 {
l = append(l, fmt.Sprintf("0x%x", unknown))
}
- fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %10d:%-60s → %q\n",
+ fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %10d:%-20s → %q\n",
time.Now().Format("15:04:05.000000000"), mask, strings.Join(l, " | "), name)
}
diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go
index e5b3b6f6943..7600180742b 100644
--- a/vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go
+++ b/vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go
@@ -7,19 +7,9 @@ var names = []struct {
m uint32
}{
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
- {"NOTE_CHILD", unix.NOTE_CHILD},
{"NOTE_DELETE", unix.NOTE_DELETE},
- {"NOTE_EXEC", unix.NOTE_EXEC},
- {"NOTE_EXIT", unix.NOTE_EXIT},
{"NOTE_EXTEND", unix.NOTE_EXTEND},
- {"NOTE_FORK", unix.NOTE_FORK},
{"NOTE_LINK", unix.NOTE_LINK},
- {"NOTE_LOWAT", unix.NOTE_LOWAT},
- {"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
- {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
{"NOTE_RENAME", unix.NOTE_RENAME},
- {"NOTE_REVOKE", unix.NOTE_REVOKE},
- {"NOTE_TRACK", unix.NOTE_TRACK},
- {"NOTE_TRACKERR", unix.NOTE_TRACKERR},
{"NOTE_WRITE", unix.NOTE_WRITE},
}
diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go
index 1dd455bc5a4..871766d6997 100644
--- a/vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go
+++ b/vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go
@@ -7,22 +7,10 @@ var names = []struct {
m uint32
}{
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
- // {"NOTE_CHANGE", unix.NOTE_CHANGE}, // Not on 386?
- {"NOTE_CHILD", unix.NOTE_CHILD},
{"NOTE_DELETE", unix.NOTE_DELETE},
- {"NOTE_EOF", unix.NOTE_EOF},
- {"NOTE_EXEC", unix.NOTE_EXEC},
- {"NOTE_EXIT", unix.NOTE_EXIT},
{"NOTE_EXTEND", unix.NOTE_EXTEND},
- {"NOTE_FORK", unix.NOTE_FORK},
{"NOTE_LINK", unix.NOTE_LINK},
- {"NOTE_LOWAT", unix.NOTE_LOWAT},
- {"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
- {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
{"NOTE_RENAME", unix.NOTE_RENAME},
- {"NOTE_REVOKE", unix.NOTE_REVOKE},
- {"NOTE_TRACK", unix.NOTE_TRACK},
- {"NOTE_TRACKERR", unix.NOTE_TRACKERR},
{"NOTE_TRUNCATE", unix.NOTE_TRUNCATE},
{"NOTE_WRITE", unix.NOTE_WRITE},
}
diff --git a/vendor/github.com/fsnotify/fsnotify/internal/freebsd.go b/vendor/github.com/fsnotify/fsnotify/internal/freebsd.go
index 5ac8b507978..758a2490525 100644
--- a/vendor/github.com/fsnotify/fsnotify/internal/freebsd.go
+++ b/vendor/github.com/fsnotify/fsnotify/internal/freebsd.go
@@ -15,17 +15,6 @@ var (
var maxfiles uint64
-func SetRlimit() {
- // Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
- var l syscall.Rlimit
- err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
- if err == nil && l.Cur != l.Max {
- l.Cur = l.Max
- syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l)
- }
- maxfiles = uint64(l.Cur)
-}
-
func Maxfiles() uint64 { return maxfiles }
func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) }
func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, uint64(dev)) }
diff --git a/vendor/github.com/fsnotify/fsnotify/internal/unix.go b/vendor/github.com/fsnotify/fsnotify/internal/unix.go
index b251fb80386..9c66f5d30db 100644
--- a/vendor/github.com/fsnotify/fsnotify/internal/unix.go
+++ b/vendor/github.com/fsnotify/fsnotify/internal/unix.go
@@ -15,17 +15,6 @@ var (
var maxfiles uint64
-func SetRlimit() {
- // Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
- var l syscall.Rlimit
- err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
- if err == nil && l.Cur != l.Max {
- l.Cur = l.Max
- syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l)
- }
- maxfiles = uint64(l.Cur)
-}
-
func Maxfiles() uint64 { return maxfiles }
func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) }
func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, dev) }
diff --git a/vendor/github.com/fsnotify/fsnotify/internal/unix2.go b/vendor/github.com/fsnotify/fsnotify/internal/unix2.go
index 37dfeddc289..b2d89592f7c 100644
--- a/vendor/github.com/fsnotify/fsnotify/internal/unix2.go
+++ b/vendor/github.com/fsnotify/fsnotify/internal/unix2.go
@@ -2,6 +2,24 @@
package internal
+import "syscall"
+
func HasPrivilegesForSymlink() bool {
return true
}
+
+// IgnoringEINTR makes a function call and repeats it if it returns an
+// EINTR error. This appears to be required even though we install all
+// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
+// Also #20400 and #36644 are issues in which a signal handler is
+// installed without setting SA_RESTART. None of these are the common case,
+// but there are enough of them that it seems that we can't avoid
+// an EINTR loop.
+func IgnoringEINTR[T any](fn func() (T, error)) (T, error) {
+ for {
+ v, err := fn()
+ if err != syscall.EINTR {
+ return v, err
+ }
+ }
+}
diff --git a/vendor/github.com/fsnotify/fsnotify/internal/windows.go b/vendor/github.com/fsnotify/fsnotify/internal/windows.go
index 896bc2e5a2f..e24d5692641 100644
--- a/vendor/github.com/fsnotify/fsnotify/internal/windows.go
+++ b/vendor/github.com/fsnotify/fsnotify/internal/windows.go
@@ -14,7 +14,6 @@ var (
ErrUnixEACCES = errors.New("dummy")
)
-func SetRlimit() {}
func Maxfiles() uint64 { return 1<<64 - 1 }
func Mkfifo(path string, mode uint32) error { return errors.New("no FIFOs on Windows") }
func Mknod(path string, mode uint32, dev int) error { return errors.New("no device nodes on Windows") }
diff --git a/vendor/github.com/fxamacker/cbor/v2/.golangci.yml b/vendor/github.com/fxamacker/cbor/v2/.golangci.yml
index 38cb9ae101b..08081fbde50 100644
--- a/vendor/github.com/fxamacker/cbor/v2/.golangci.yml
+++ b/vendor/github.com/fxamacker/cbor/v2/.golangci.yml
@@ -1,104 +1,116 @@
-# Do not delete linter settings. Linters like gocritic can be enabled on the command line.
-
-linters-settings:
- depguard:
- rules:
- prevent_unmaintained_packages:
- list-mode: strict
- files:
- - $all
- - "!$test"
- allow:
- - $gostd
- - github.com/x448/float16
- deny:
- - pkg: io/ioutil
- desc: "replaced by io and os packages since Go 1.16: https://tip.golang.org/doc/go1.16#ioutil"
- dupl:
- threshold: 100
- funlen:
- lines: 100
- statements: 50
- goconst:
- ignore-tests: true
- min-len: 2
- min-occurrences: 3
- gocritic:
- enabled-tags:
- - diagnostic
- - experimental
- - opinionated
- - performance
- - style
- disabled-checks:
- - commentedOutCode
- - dupImport # https://github.com/go-critic/go-critic/issues/845
- - ifElseChain
- - octalLiteral
- - paramTypeCombine
- - whyNoLint
- gofmt:
- simplify: false
- goimports:
- local-prefixes: github.com/fxamacker/cbor
- golint:
- min-confidence: 0
- govet:
- check-shadowing: true
- lll:
- line-length: 140
- maligned:
- suggest-new: true
- misspell:
- locale: US
- staticcheck:
- checks: ["all"]
-
+version: "2"
linters:
- disable-all: true
+ default: none
enable:
- asciicheck
- bidichk
- depguard
- errcheck
- - exportloopref
+ - forbidigo
- goconst
- gocritic
- gocyclo
- - gofmt
- - goimports
- goprintffuncname
- gosec
- - gosimple
- govet
- ineffassign
- misspell
- nilerr
- revive
- staticcheck
- - stylecheck
- - typecheck
- unconvert
- unused
-
+ settings:
+ depguard:
+ rules:
+ prevent_unmaintained_packages:
+ list-mode: strict
+ files:
+ - $all
+ - '!$test'
+ allow:
+ - $gostd
+ - github.com/x448/float16
+ deny:
+ - pkg: io/ioutil
+ desc: 'replaced by io and os packages since Go 1.16: https://tip.golang.org/doc/go1.16#ioutil'
+ dupl:
+ threshold: 100
+ funlen:
+ lines: 100
+ statements: 50
+ goconst:
+ min-len: 2
+ min-occurrences: 3
+ gocritic:
+ disabled-checks:
+ - commentedOutCode
+ - dupImport
+ - ifElseChain
+ - octalLiteral
+ - paramTypeCombine
+ - whyNoLint
+ enabled-tags:
+ - diagnostic
+ - experimental
+ - opinionated
+ - performance
+ - style
+ govet:
+ enable:
+ - shadow
+ lll:
+ line-length: 140
+ misspell:
+ locale: US
+ staticcheck:
+ checks:
+ - all
+ exclusions:
+ generated: lax
+ presets:
+ - comments
+ - common-false-positives
+ - legacy
+ - std-error-handling
+ rules:
+ - path: decode.go
+ text: string ` overflows ` has (\d+) occurrences, make it a constant
+ - path: decode.go
+ text: string ` \(range is \[` has (\d+) occurrences, make it a constant
+ - path: decode.go
+ text: string `, ` has (\d+) occurrences, make it a constant
+ - path: decode.go
+ text: string ` overflows Go's int64` has (\d+) occurrences, make it a constant
+ - path: decode.go
+ text: string `\]\)` has (\d+) occurrences, make it a constant
+ - path: valid.go
+ text: string ` for type ` has (\d+) occurrences, make it a constant
+ - path: valid.go
+ text: 'string `cbor: ` has (\d+) occurrences, make it a constant'
+ - linters:
+ - goconst
+ path: (.+)_test\.go
+ paths:
+ - third_party$
+ - builtin$
+ - examples$
issues:
- # max-issues-per-linter default is 50. Set to 0 to disable limit.
max-issues-per-linter: 0
- # max-same-issues default is 3. Set to 0 to disable limit.
max-same-issues: 0
-
- exclude-rules:
- - path: decode.go
- text: "string ` overflows ` has (\\d+) occurrences, make it a constant"
- - path: decode.go
- text: "string ` \\(range is \\[` has (\\d+) occurrences, make it a constant"
- - path: decode.go
- text: "string `, ` has (\\d+) occurrences, make it a constant"
- - path: decode.go
- text: "string ` overflows Go's int64` has (\\d+) occurrences, make it a constant"
- - path: decode.go
- text: "string `\\]\\)` has (\\d+) occurrences, make it a constant"
- - path: valid.go
- text: "string ` for type ` has (\\d+) occurrences, make it a constant"
- - path: valid.go
- text: "string `cbor: ` has (\\d+) occurrences, make it a constant"
+formatters:
+ enable:
+ - gofmt
+ - goimports
+ settings:
+ gofmt:
+ simplify: false
+ goimports:
+ local-prefixes:
+ - github.com/fxamacker/cbor
+ exclusions:
+ generated: lax
+ paths:
+ - third_party$
+ - builtin$
+ - examples$
diff --git a/vendor/github.com/fxamacker/cbor/v2/README.md b/vendor/github.com/fxamacker/cbor/v2/README.md
index d072b81c730..7aca561095d 100644
--- a/vendor/github.com/fxamacker/cbor/v2/README.md
+++ b/vendor/github.com/fxamacker/cbor/v2/README.md
@@ -683,7 +683,7 @@ because RFC 8949 treats CBOR data item with remaining bytes as malformed.
Other useful functions:
- `Diagnose`, `DiagnoseFirst` produce human-readable [Extended Diagnostic Notation](https://www.rfc-editor.org/rfc/rfc8610.html#appendix-G) from CBOR data.
- `UnmarshalFirst` decodes first CBOR data item and return any remaining bytes.
-- `Wellformed` returns true if the CBOR data item is well-formed.
+- `Wellformed` returns nil error if the CBOR data item is well-formed.
Interfaces identical or comparable to Go `encoding` packages include:
`Marshaler`, `Unmarshaler`, `BinaryMarshaler`, and `BinaryUnmarshaler`.
@@ -702,28 +702,29 @@ Default limits may need to be increased for systems handling very large data (e.
## Status
-[v2.9.0](https://github.com/fxamacker/cbor/releases/tag/v2.9.0) (Jul 13, 2025) improved interoperability/transcoding between CBOR & JSON, refactored tests, and improved docs.
-- Add opt-in support for `encoding.TextMarshaler` and `encoding.TextUnmarshaler` to encode and decode from CBOR text string.
-- Add opt-in support for `json.Marshaler` and `json.Unmarshaler` via user-provided transcoding function.
-- Update docs for TimeMode, Tag, RawTag, and add example for Embedded JSON Tag for CBOR.
+v2.9.2 (Sunday, May 3, 2026) refactors and hardens the streaming encoder by adding stricter checks for encoding to CBOR indefinite-length data. This prevents improper use of this library from producing malformed CBOR indefinite-length data that would be rejected by the decoder.
-v2.9.0 passed fuzz tests and is production quality.
+This release includes other bugfixes, defensive checks, and added more tests.
-The minimum version of Go required to build:
-- v2.8.0 and newer releases require go 1.20+.
-- v2.7.1 and older releases require go 1.17+.
+v2.9.2 passed fuzz tests (billions of executions) and is production quality.
-For more details, see [release notes](https://github.com/fxamacker/cbor/releases).
+For more details, see [v2.9.2 release notes](https://github.com/fxamacker/cbor/releases).
### Prior Releases
-[v2.8.0](https://github.com/fxamacker/cbor/releases/tag/v2.8.0) (March 30, 2025) is a small release primarily to add `omitzero` option to struct field tags and fix bugs. It passed fuzz tests (billions of executions) and is production quality.
+Releases and commits tend to be on Sundays because my work schedule didn't leave time to work on this during weekdays (sometimes consecutive weekends and consecutive Christmas breaks, too). Monday morning releases were to allow more fuzzing to run overnight before clicking the release button.
-[v2.7.0](https://github.com/fxamacker/cbor/releases/tag/v2.7.0) (June 23, 2024) adds features and improvements that help large projects (e.g. Kubernetes) use CBOR as an alternative to JSON and Protocol Buffers. Other improvements include speedups, improved memory use, bug fixes, new serialization options, etc. It passed fuzz tests (5+ billion executions) and is production quality.
+[v2.9.1](https://github.com/fxamacker/cbor/releases/tag/v2.9.1) (Monday, Mar 30, 2026) includes important bugfixes, defensive checks, improved code quality, and more tests. Although not public, the fuzzer was also improved by adding more fuzz tests. It passed fuzz tests (billions of executions) and is production quality.
-[v2.6.0](https://github.com/fxamacker/cbor/releases/tag/v2.6.0) (February 2024) adds important new features, optimizations, and bug fixes. It is especially useful to systems that need to convert data between CBOR and JSON. New options and optimizations improve handling of bignum, integers, maps, and strings.
+[v2.9.0](https://github.com/fxamacker/cbor/releases/tag/v2.9.0) (Sunday, Jul 13, 2025) improved interoperability/transcoding between CBOR & JSON, refactored tests, and improved docs. It passed fuzz tests (billions of executions) and is production quality.
-[v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) was released on Sunday, August 13, 2023 with new features and important bug fixes. It is fuzz tested and production quality after extended beta [v2.5.0-beta](https://github.com/fxamacker/cbor/releases/tag/v2.5.0-beta) (Dec 2022) -> [v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) (Aug 2023).
+[v2.8.0](https://github.com/fxamacker/cbor/releases/tag/v2.8.0) (Sunday, March 30, 2025) is a small release primarily to add `omitzero` option to struct field tags and fix bugs. It passed fuzz tests (billions of executions) and is production quality.
+
+[v2.7.0](https://github.com/fxamacker/cbor/releases/tag/v2.7.0) (Monday, June 23, 2024) adds features and improvements that help large projects (e.g. Kubernetes) use CBOR as an alternative to JSON and Protocol Buffers. Other improvements include speedups, improved memory use, bug fixes, new serialization options, etc. It passed fuzz tests (5+ billion executions) and is production quality.
+
+[v2.6.0](https://github.com/fxamacker/cbor/releases/tag/v2.6.0) (Sunday, Feb 11, 2024) adds important new features, optimizations, and bug fixes. It is especially useful to systems that need to convert data between CBOR and JSON. New options and optimizations improve handling of bignum, integers, maps, and strings.
+
+[v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) (Sunday, August 13, 2023) adds new features and important bug fixes. It is fuzz tested and production quality after extended beta [v2.5.0-beta](https://github.com/fxamacker/cbor/releases/tag/v2.5.0-beta) (Dec 2022) -> [v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) (Aug 2023).
__IMPORTANT__: 👉 Before upgrading from v2.4 or older release, please read the notable changes highlighted in the release notes. v2.5.0 is a large release with bug fixes to error handling for extraneous data in `Unmarshal`, etc. that should be reviewed before upgrading.
diff --git a/vendor/github.com/fxamacker/cbor/v2/cache.go b/vendor/github.com/fxamacker/cbor/v2/cache.go
index 5051f110fbb..5743f3eb25e 100644
--- a/vendor/github.com/fxamacker/cbor/v2/cache.go
+++ b/vendor/github.com/fxamacker/cbor/v2/cache.go
@@ -92,94 +92,126 @@ func newTypeInfo(t reflect.Type) *typeInfo {
}
type decodingStructType struct {
- fields fields
- fieldIndicesByName map[string]int
- err error
- toArray bool
+ fields decodingFields
+ fieldIndicesByName map[string]int // Only populated if toArray is false
+ fieldIndicesByIntKey map[int64]int // Only populated if toArray is false
+ err error
+ toArray bool
}
-// The stdlib errors.Join was introduced in Go 1.20, and we still support Go 1.17, so instead,
-// here's a very basic implementation of an aggregated error.
-type multierror []error
-
-func (m multierror) Error() string {
- var sb strings.Builder
- for i, err := range m {
- sb.WriteString(err.Error())
- if i < len(m)-1 {
- sb.WriteString(", ")
- }
- }
- return sb.String()
-}
-
-func getDecodingStructType(t reflect.Type) *decodingStructType {
+func getDecodingStructType(t reflect.Type) (*decodingStructType, error) {
if v, _ := decodingStructTypeCache.Load(t); v != nil {
- return v.(*decodingStructType)
+ structType := v.(*decodingStructType)
+ if structType.err != nil {
+ return nil, structType.err
+ }
+ return structType, nil
}
flds, structOptions := getFields(t)
toArray := hasToArrayOption(structOptions)
- var errs []error
- for i := 0; i < len(flds); i++ {
- if flds[i].keyAsInt {
- nameAsInt, numErr := strconv.Atoi(flds[i].name)
- if numErr != nil {
- errs = append(errs, errors.New("cbor: failed to parse field name \""+flds[i].name+"\" to int ("+numErr.Error()+")"))
- break
+ if toArray {
+ return getDecodingStructToArrayType(t, flds)
+ }
+
+ fieldIndicesByName := make(map[string]int, len(flds))
+ var fieldIndicesByIntKey map[int64]int
+
+ decFlds := make(decodingFields, len(flds))
+ for i, f := range flds {
+ // nameAsInt is set in getFields() except for fields with an unparsable tagged name.
+ // Atoi() is called here to catch and save parsing errors.
+ if f.keyAsInt && f.nameAsInt == 0 {
+ if _, numErr := strconv.Atoi(f.name); numErr != nil {
+ structType := &decodingStructType{
+ err: errors.New("cbor: failed to parse field name \"" + f.name + "\" to int (" + numErr.Error() + ")"),
+ }
+ decodingStructTypeCache.Store(t, structType)
+ return nil, structType.err
}
- flds[i].nameAsInt = int64(nameAsInt)
}
- flds[i].typInfo = getTypeInfo(flds[i].typ)
- }
+ if f.keyAsInt {
+ if fieldIndicesByIntKey == nil {
+ fieldIndicesByIntKey = make(map[int64]int, len(flds))
+ }
+ // The duplication check is only a safeguard, since getFields() already deduplicates fields.
+ if _, ok := fieldIndicesByIntKey[f.nameAsInt]; ok {
+ structType := &decodingStructType{
+ err: fmt.Errorf("cbor: two or more fields of %v have the same keyasint value %d", t, f.nameAsInt),
+ }
+ decodingStructTypeCache.Store(t, structType)
+ return nil, structType.err
+ }
+ fieldIndicesByIntKey[f.nameAsInt] = i
+ } else {
+ // The duplication check is only a safeguard, since getFields() already deduplicates fields.
+ if _, ok := fieldIndicesByName[f.name]; ok {
+ structType := &decodingStructType{
+ err: fmt.Errorf("cbor: two or more fields of %v have the same name %q", t, f.name),
+ }
+ decodingStructTypeCache.Store(t, structType)
+ return nil, structType.err
+ }
+ fieldIndicesByName[f.name] = i
+ }
- fieldIndicesByName := make(map[string]int, len(flds))
- for i, fld := range flds {
- if _, ok := fieldIndicesByName[fld.name]; ok {
- errs = append(errs, fmt.Errorf("cbor: two or more fields of %v have the same name %q", t, fld.name))
- continue
+ decFlds[i] = &decodingField{
+ field: *f,
+ typInfo: getTypeInfo(f.typ),
}
- fieldIndicesByName[fld.name] = i
}
- var err error
- {
- var multi multierror
- for _, each := range errs {
- if each != nil {
- multi = append(multi, each)
+ structType := &decodingStructType{
+ fields: decFlds,
+ fieldIndicesByName: fieldIndicesByName,
+ fieldIndicesByIntKey: fieldIndicesByIntKey,
+ }
+ decodingStructTypeCache.Store(t, structType)
+ return structType, nil
+}
+
+func getDecodingStructToArrayType(t reflect.Type, flds fields) (*decodingStructType, error) {
+ decFlds := make(decodingFields, len(flds))
+ for i, f := range flds {
+ // nameAsInt is set in getFields() except for fields with an unparsable tagged name.
+ // Atoi() is called here to catch and save parsing errors.
+ if f.keyAsInt && f.nameAsInt == 0 {
+ if _, numErr := strconv.Atoi(f.name); numErr != nil {
+ structType := &decodingStructType{
+ err: errors.New("cbor: failed to parse field name \"" + f.name + "\" to int (" + numErr.Error() + ")"),
+ }
+ decodingStructTypeCache.Store(t, structType)
+ return nil, structType.err
}
}
- if len(multi) == 1 {
- err = multi[0]
- } else if len(multi) > 1 {
- err = multi
+
+ decFlds[i] = &decodingField{
+ field: *f,
+ typInfo: getTypeInfo(f.typ),
}
}
structType := &decodingStructType{
- fields: flds,
- fieldIndicesByName: fieldIndicesByName,
- err: err,
- toArray: toArray,
+ fields: decFlds,
+ toArray: true,
}
decodingStructTypeCache.Store(t, structType)
- return structType
+ return structType, nil
}
type encodingStructType struct {
- fields fields
- bytewiseFields fields
- lengthFirstFields fields
- omitEmptyFieldsIdx []int
+ fields encodingFields
+ bytewiseFields encodingFields // Only populated if toArray is false
+ lengthFirstFields encodingFields // Only populated if toArray is false
+ omitEmptyFieldsIdx []int // Only populated if toArray is false
err error
toArray bool
}
-func (st *encodingStructType) getFields(em *encMode) fields {
+func (st *encodingStructType) getFields(em *encMode) encodingFields {
switch em.sort {
case SortNone, SortFastShuffle:
return st.fields
@@ -191,7 +223,7 @@ func (st *encodingStructType) getFields(em *encMode) fields {
}
type bytewiseFieldSorter struct {
- fields fields
+ fields encodingFields
}
func (x *bytewiseFieldSorter) Len() int {
@@ -203,11 +235,11 @@ func (x *bytewiseFieldSorter) Swap(i, j int) {
}
func (x *bytewiseFieldSorter) Less(i, j int) bool {
- return bytes.Compare(x.fields[i].cborName, x.fields[j].cborName) <= 0
+ return bytes.Compare(x.fields[i].cborName, x.fields[j].cborName) < 0
}
type lengthFirstFieldSorter struct {
- fields fields
+ fields encodingFields
}
func (x *lengthFirstFieldSorter) Len() int {
@@ -222,13 +254,16 @@ func (x *lengthFirstFieldSorter) Less(i, j int) bool {
if len(x.fields[i].cborName) != len(x.fields[j].cborName) {
return len(x.fields[i].cborName) < len(x.fields[j].cborName)
}
- return bytes.Compare(x.fields[i].cborName, x.fields[j].cborName) <= 0
+ return bytes.Compare(x.fields[i].cborName, x.fields[j].cborName) < 0
}
func getEncodingStructType(t reflect.Type) (*encodingStructType, error) {
if v, _ := encodingStructTypeCache.Load(t); v != nil {
structType := v.(*encodingStructType)
- return structType, structType.err
+ if structType.err != nil {
+ return nil, structType.err
+ }
+ return structType, nil
}
flds, structOptions := getFields(t)
@@ -237,111 +272,119 @@ func getEncodingStructType(t reflect.Type) (*encodingStructType, error) {
return getEncodingStructToArrayType(t, flds)
}
- var err error
var hasKeyAsInt bool
var hasKeyAsStr bool
var omitEmptyIdx []int
+
+ encFlds := make(encodingFields, len(flds))
+
e := getEncodeBuffer()
- for i := 0; i < len(flds); i++ {
+ defer putEncodeBuffer(e)
+
+ for i, f := range flds {
+ encFlds[i] = &encodingField{field: *f}
+ ef := encFlds[i]
+
// Get field's encodeFunc
- flds[i].ef, flds[i].ief, flds[i].izf = getEncodeFunc(flds[i].typ)
- if flds[i].ef == nil {
- err = &UnsupportedTypeError{t}
- break
+ ef.ef, ef.ief, ef.izf = getEncodeFunc(f.typ)
+ if ef.ef == nil {
+ structType := &encodingStructType{err: &UnsupportedTypeError{t}}
+ encodingStructTypeCache.Store(t, structType)
+ return nil, structType.err
}
// Encode field name
- if flds[i].keyAsInt {
- nameAsInt, numErr := strconv.Atoi(flds[i].name)
- if numErr != nil {
- err = errors.New("cbor: failed to parse field name \"" + flds[i].name + "\" to int (" + numErr.Error() + ")")
- break
+ if f.keyAsInt {
+ if f.nameAsInt == 0 {
+ // nameAsInt is set in getFields() except for fields with an unparsable tagged name.
+ // Atoi() is called here to catch and save parsing errors.
+ if _, numErr := strconv.Atoi(f.name); numErr != nil {
+ structType := &encodingStructType{
+ err: errors.New("cbor: failed to parse field name \"" + f.name + "\" to int (" + numErr.Error() + ")"),
+ }
+ encodingStructTypeCache.Store(t, structType)
+ return nil, structType.err
+ }
}
- flds[i].nameAsInt = int64(nameAsInt)
+ nameAsInt := f.nameAsInt
if nameAsInt >= 0 {
- encodeHead(e, byte(cborTypePositiveInt), uint64(nameAsInt))
+ encodeHead(e, byte(cborTypePositiveInt), uint64(nameAsInt)) //nolint:gosec
} else {
n := nameAsInt*(-1) - 1
- encodeHead(e, byte(cborTypeNegativeInt), uint64(n))
+ encodeHead(e, byte(cborTypeNegativeInt), uint64(n)) //nolint:gosec
}
- flds[i].cborName = make([]byte, e.Len())
- copy(flds[i].cborName, e.Bytes())
+ ef.cborName = make([]byte, e.Len())
+ copy(ef.cborName, e.Bytes())
e.Reset()
hasKeyAsInt = true
} else {
- encodeHead(e, byte(cborTypeTextString), uint64(len(flds[i].name)))
- flds[i].cborName = make([]byte, e.Len()+len(flds[i].name))
- n := copy(flds[i].cborName, e.Bytes())
- copy(flds[i].cborName[n:], flds[i].name)
+ encodeHead(e, byte(cborTypeTextString), uint64(len(f.name)))
+ ef.cborName = make([]byte, e.Len()+len(f.name))
+ n := copy(ef.cborName, e.Bytes())
+ copy(ef.cborName[n:], f.name)
e.Reset()
// If cborName contains a text string, then cborNameByteString contains a
// string that has the byte string major type but is otherwise identical to
// cborName.
- flds[i].cborNameByteString = make([]byte, len(flds[i].cborName))
- copy(flds[i].cborNameByteString, flds[i].cborName)
+ ef.cborNameByteString = make([]byte, len(ef.cborName))
+ copy(ef.cborNameByteString, ef.cborName)
// Reset encoded CBOR type to byte string, preserving the "additional
// information" bits:
- flds[i].cborNameByteString[0] = byte(cborTypeByteString) |
- getAdditionalInformation(flds[i].cborNameByteString[0])
+ ef.cborNameByteString[0] = byte(cborTypeByteString) |
+ getAdditionalInformation(ef.cborNameByteString[0])
hasKeyAsStr = true
}
// Check if field can be omitted when empty
- if flds[i].omitEmpty {
+ if f.omitEmpty {
omitEmptyIdx = append(omitEmptyIdx, i)
}
}
- putEncodeBuffer(e)
-
- if err != nil {
- structType := &encodingStructType{err: err}
- encodingStructTypeCache.Store(t, structType)
- return structType, structType.err
- }
// Sort fields by canonical order
- bytewiseFields := make(fields, len(flds))
- copy(bytewiseFields, flds)
+ bytewiseFields := make(encodingFields, len(encFlds))
+ copy(bytewiseFields, encFlds)
sort.Sort(&bytewiseFieldSorter{bytewiseFields})
lengthFirstFields := bytewiseFields
if hasKeyAsInt && hasKeyAsStr {
- lengthFirstFields = make(fields, len(flds))
- copy(lengthFirstFields, flds)
+ lengthFirstFields = make(encodingFields, len(encFlds))
+ copy(lengthFirstFields, encFlds)
sort.Sort(&lengthFirstFieldSorter{lengthFirstFields})
}
structType := &encodingStructType{
- fields: flds,
+ fields: encFlds,
bytewiseFields: bytewiseFields,
lengthFirstFields: lengthFirstFields,
omitEmptyFieldsIdx: omitEmptyIdx,
}
encodingStructTypeCache.Store(t, structType)
- return structType, structType.err
+ return structType, nil
}
func getEncodingStructToArrayType(t reflect.Type, flds fields) (*encodingStructType, error) {
- for i := 0; i < len(flds); i++ {
- // Get field's encodeFunc
- flds[i].ef, flds[i].ief, flds[i].izf = getEncodeFunc(flds[i].typ)
- if flds[i].ef == nil {
+ encFlds := make(encodingFields, len(flds))
+ for i, f := range flds {
+ encFlds[i] = &encodingField{field: *f}
+ encFlds[i].ef, encFlds[i].ief, encFlds[i].izf = getEncodeFunc(f.typ)
+ if encFlds[i].ef == nil {
structType := &encodingStructType{err: &UnsupportedTypeError{t}}
encodingStructTypeCache.Store(t, structType)
- return structType, structType.err
+ return nil, structType.err
}
}
structType := &encodingStructType{
- fields: flds,
+ fields: encFlds,
toArray: true,
}
encodingStructTypeCache.Store(t, structType)
- return structType, structType.err
+ return structType, nil
}
func getEncodeFunc(t reflect.Type) (encodeFunc, isEmptyFunc, isZeroFunc) {
diff --git a/vendor/github.com/fxamacker/cbor/v2/decode.go b/vendor/github.com/fxamacker/cbor/v2/decode.go
index f0bdc3b38dd..1d3e63d0684 100644
--- a/vendor/github.com/fxamacker/cbor/v2/decode.go
+++ b/vendor/github.com/fxamacker/cbor/v2/decode.go
@@ -16,7 +16,6 @@ import (
"math/big"
"reflect"
"strconv"
- "strings"
"time"
"unicode/utf8"
@@ -326,14 +325,14 @@ func (dmkm DupMapKeyMode) valid() bool {
return dmkm >= 0 && dmkm < maxDupMapKeyMode
}
-// IndefLengthMode specifies whether to allow indefinite length items.
+// IndefLengthMode specifies whether to allow indefinite-length items.
type IndefLengthMode int
const (
- // IndefLengthAllowed allows indefinite length items.
+ // IndefLengthAllowed allows indefinite-length items.
IndefLengthAllowed IndefLengthMode = iota
- // IndefLengthForbidden disallows indefinite length items.
+ // IndefLengthForbidden disallows indefinite-length items.
IndefLengthForbidden
maxIndefLengthMode
@@ -378,6 +377,7 @@ const (
// - int64 if value fits
// - big.Int or *big.Int (see BigIntDecMode) if value < math.MinInt64
// - return UnmarshalTypeError if value > math.MaxInt64
+ //
// Deprecated: IntDecConvertSigned should not be used.
// Please use other options, such as IntDecConvertSignedOrError, IntDecConvertSignedOrBigInt, IntDecConvertNone.
IntDecConvertSigned
@@ -811,7 +811,7 @@ type DecOptions struct {
// Default is 128*1024=131072 and it can be set to [16, 2147483647]
MaxMapPairs int
- // IndefLength specifies whether to allow indefinite length CBOR items.
+ // IndefLength specifies whether to allow indefinite-length CBOR items.
IndefLength IndefLengthMode
// TagsMd specifies whether to allow CBOR tags (major type 6).
@@ -1055,7 +1055,7 @@ func (opts DecOptions) decMode() (*decMode, error) { //nolint:gocritic // ignore
}
if !opts.ExtraReturnErrors.valid() {
- return nil, errors.New("cbor: invalid ExtraReturnErrors " + strconv.Itoa(int(opts.ExtraReturnErrors)))
+ return nil, errors.New("cbor: invalid ExtraReturnErrors " + strconv.Itoa(int(opts.ExtraReturnErrors))) //nolint:gosec
}
if opts.DefaultMapType != nil && opts.DefaultMapType.Kind() != reflect.Map {
@@ -1149,8 +1149,8 @@ func (opts DecOptions) decMode() (*decMode, error) { //nolint:gocritic // ignore
unrecognizedTagToAny: opts.UnrecognizedTagToAny,
timeTagToAny: opts.TimeTagToAny,
simpleValues: simpleValues,
- nanDec: opts.NaN,
- infDec: opts.Inf,
+ nan: opts.NaN,
+ inf: opts.Inf,
byteStringToTime: opts.ByteStringToTime,
byteStringExpectedFormat: opts.ByteStringExpectedFormat,
bignumTag: opts.BignumTag,
@@ -1230,8 +1230,8 @@ type decMode struct {
unrecognizedTagToAny UnrecognizedTagToAnyMode
timeTagToAny TimeTagToAnyMode
simpleValues *SimpleValueRegistry
- nanDec NaNMode
- infDec InfMode
+ nan NaNMode
+ inf InfMode
byteStringToTime ByteStringToTimeMode
byteStringExpectedFormat ByteStringExpectedFormatMode
bignumTag BignumTagMode
@@ -1272,8 +1272,8 @@ func (dm *decMode) DecOptions() DecOptions {
UnrecognizedTagToAny: dm.unrecognizedTagToAny,
TimeTagToAny: dm.timeTagToAny,
SimpleValues: simpleValues,
- NaN: dm.nanDec,
- Inf: dm.infDec,
+ NaN: dm.nan,
+ Inf: dm.inf,
ByteStringToTime: dm.byteStringToTime,
ByteStringExpectedFormat: dm.byteStringExpectedFormat,
BignumTag: dm.bignumTag,
@@ -1583,11 +1583,11 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
_, ai, val := d.getHead()
switch ai {
case additionalInformationAsFloat16:
- f := float64(float16.Frombits(uint16(val)).Float32())
+ f := float64(float16.Frombits(uint16(val)).Float32()) //nolint:gosec
return fillFloat(t, f, v)
case additionalInformationAsFloat32:
- f := float64(math.Float32frombits(uint32(val)))
+ f := float64(math.Float32frombits(uint32(val))) //nolint:gosec
return fillFloat(t, f, v)
case additionalInformationAsFloat64:
@@ -1595,10 +1595,10 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
return fillFloat(t, f, v)
default: // ai <= 24
- if d.dm.simpleValues.rejected[SimpleValue(val)] {
+ if d.dm.simpleValues.rejected[SimpleValue(val)] { //nolint:gosec
return &UnacceptableDataItemError{
CBORType: t.String(),
- Message: "simple value " + strconv.FormatInt(int64(val), 10) + " is not recognized",
+ Message: "simple value " + strconv.FormatInt(int64(val), 10) + " is not recognized", //nolint:gosec
}
}
@@ -1677,20 +1677,23 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
return d.parseToValue(v, tInfo)
case cborTypeArray:
- if tInfo.nonPtrKind == reflect.Slice {
+ switch tInfo.nonPtrKind {
+ case reflect.Slice:
return d.parseArrayToSlice(v, tInfo)
- } else if tInfo.nonPtrKind == reflect.Array {
+ case reflect.Array:
return d.parseArrayToArray(v, tInfo)
- } else if tInfo.nonPtrKind == reflect.Struct {
+ case reflect.Struct:
return d.parseArrayToStruct(v, tInfo)
}
+
d.skip()
return &UnmarshalTypeError{CBORType: t.String(), GoType: tInfo.nonPtrType.String()}
case cborTypeMap:
- if tInfo.nonPtrKind == reflect.Struct {
+ switch tInfo.nonPtrKind {
+ case reflect.Struct:
return d.parseMapToStruct(v, tInfo)
- } else if tInfo.nonPtrKind == reflect.Map {
+ case reflect.Map:
return d.parseMapToMap(v, tInfo)
}
d.skip()
@@ -1745,8 +1748,8 @@ func (d *decoder) parseToTime() (time.Time, bool, error) {
// Read tag number
_, _, tagNum := d.getHead()
if tagNum != 0 && tagNum != 1 {
- d.skip() // skip tag content
- return time.Time{}, false, errors.New("cbor: wrong tag number for time.Time, got " + strconv.Itoa(int(tagNum)) + ", expect 0 or 1")
+ d.skip() // skip tag content
+ return time.Time{}, false, errors.New("cbor: wrong tag number for time.Time, got " + strconv.Itoa(int(tagNum)) + ", expect 0 or 1") //nolint:gosec
}
}
} else {
@@ -1815,10 +1818,10 @@ func (d *decoder) parseToTime() (time.Time, bool, error) {
var f float64
switch ai {
case additionalInformationAsFloat16:
- f = float64(float16.Frombits(uint16(val)).Float32())
+ f = float64(float16.Frombits(uint16(val)).Float32()) //nolint:gosec
case additionalInformationAsFloat32:
- f = float64(math.Float32frombits(uint32(val)))
+ f = float64(math.Float32frombits(uint32(val))) //nolint:gosec
case additionalInformationAsFloat64:
f = math.Float64frombits(val)
@@ -1832,6 +1835,13 @@ func (d *decoder) parseToTime() (time.Time, bool, error) {
return time.Time{}, true, nil
}
seconds, fractional := math.Modf(f)
+ if seconds > math.MaxInt64 || seconds < math.MinInt64 {
+ return time.Time{}, false, &UnmarshalTypeError{
+ CBORType: t.String(),
+ GoType: typeTime.String(),
+ errorMsg: fmt.Sprintf("%v overflows Go's int64", f),
+ }
+ }
return time.Unix(int64(seconds), int64(fractional*1e9)), true, nil
default:
@@ -2145,14 +2155,14 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (any, error) { //nolint:gocyc
case cborTypePrimitives:
_, ai, val := d.getHead()
- if ai <= 24 && d.dm.simpleValues.rejected[SimpleValue(val)] {
+ if ai <= 24 && d.dm.simpleValues.rejected[SimpleValue(val)] { //nolint:gosec
return nil, &UnacceptableDataItemError{
CBORType: t.String(),
- Message: "simple value " + strconv.FormatInt(int64(val), 10) + " is not recognized",
+ Message: "simple value " + strconv.FormatInt(int64(val), 10) + " is not recognized", //nolint:gosec
}
}
if ai < 20 || ai == 24 {
- return SimpleValue(val), nil
+ return SimpleValue(val), nil //nolint:gosec
}
switch ai {
@@ -2165,11 +2175,11 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (any, error) { //nolint:gocyc
return nil, nil
case additionalInformationAsFloat16:
- f := float64(float16.Frombits(uint16(val)).Float32())
+ f := float64(float16.Frombits(uint16(val)).Float32()) //nolint:gosec
return f, nil
case additionalInformationAsFloat32:
- f := float64(math.Float32frombits(uint32(val)))
+ f := float64(math.Float32frombits(uint32(val))) //nolint:gosec
return f, nil
case additionalInformationAsFloat64:
@@ -2202,16 +2212,16 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (any, error) { //nolint:gocyc
func (d *decoder) parseByteString() ([]byte, bool) {
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
if !indefiniteLength {
- b := d.data[d.off : d.off+int(val)]
- d.off += int(val)
+ b := d.data[d.off : d.off+int(val)] //nolint:gosec
+ d.off += int(val) //nolint:gosec
return b, false
}
- // Process indefinite length string chunks.
+ // Process indefinite-length string chunks.
b := []byte{}
for !d.foundBreak() {
_, _, val = d.getHead()
- b = append(b, d.data[d.off:d.off+int(val)]...)
- d.off += int(val)
+ b = append(b, d.data[d.off:d.off+int(val)]...) //nolint:gosec
+ d.off += int(val) //nolint:gosec
}
return b, true
}
@@ -2253,7 +2263,7 @@ func (d *decoder) applyByteStringTextConversion(
default:
// If this happens, there is a bug: the decoder has pushed an invalid
// "expected later encoding" tag to the stack.
- panic(fmt.Sprintf("unrecognized expected later encoding tag: %d", d.expectedLaterEncodingTags))
+ panic(fmt.Sprintf("unrecognized expected later encoding tag: %d", d.expectedLaterEncodingTags[len(d.expectedLaterEncodingTags)-1]))
}
case reflect.Slice:
@@ -2300,19 +2310,19 @@ func (d *decoder) applyByteStringTextConversion(
func (d *decoder) parseTextString() ([]byte, error) {
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
if !indefiniteLength {
- b := d.data[d.off : d.off+int(val)]
- d.off += int(val)
+ b := d.data[d.off : d.off+int(val)] //nolint:gosec
+ d.off += int(val) //nolint:gosec
if d.dm.utf8 == UTF8RejectInvalid && !utf8.Valid(b) {
return nil, &SemanticError{"cbor: invalid UTF-8 string"}
}
return b, nil
}
- // Process indefinite length string chunks.
+ // Process indefinite-length string chunks.
b := []byte{}
for !d.foundBreak() {
_, _, val = d.getHead()
- x := d.data[d.off : d.off+int(val)]
- d.off += int(val)
+ x := d.data[d.off : d.off+int(val)] //nolint:gosec
+ d.off += int(val) //nolint:gosec
if d.dm.utf8 == UTF8RejectInvalid && !utf8.Valid(x) {
for !d.foundBreak() {
d.skip() // Skip remaining chunk on error
@@ -2327,7 +2337,7 @@ func (d *decoder) parseTextString() ([]byte, error) {
func (d *decoder) parseArray() ([]any, error) {
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
hasSize := !indefiniteLength
- count := int(val)
+ count := int(val) //nolint:gosec
if !hasSize {
count = d.numOfItemsUntilBreak() // peek ahead to get array size to preallocate slice for better performance
}
@@ -2349,7 +2359,7 @@ func (d *decoder) parseArray() ([]any, error) {
func (d *decoder) parseArrayToSlice(v reflect.Value, tInfo *typeInfo) error {
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
hasSize := !indefiniteLength
- count := int(val)
+ count := int(val) //nolint:gosec
if !hasSize {
count = d.numOfItemsUntilBreak() // peek ahead to get array size to preallocate slice for better performance
}
@@ -2371,7 +2381,7 @@ func (d *decoder) parseArrayToSlice(v reflect.Value, tInfo *typeInfo) error {
func (d *decoder) parseArrayToArray(v reflect.Value, tInfo *typeInfo) error {
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
hasSize := !indefiniteLength
- count := int(val)
+ count := int(val) //nolint:gosec
gi := 0
vLen := v.Len()
var err error
@@ -2400,7 +2410,7 @@ func (d *decoder) parseArrayToArray(v reflect.Value, tInfo *typeInfo) error {
func (d *decoder) parseMap() (any, error) {
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
hasSize := !indefiniteLength
- count := int(val)
+ count := int(val) //nolint:gosec
m := make(map[any]any)
var k, e any
var err, lastErr error
@@ -2465,7 +2475,7 @@ func (d *decoder) parseMap() (any, error) {
func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //nolint:gocyclo
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
hasSize := !indefiniteLength
- count := int(val)
+ count := int(val) //nolint:gosec
if v.IsNil() {
mapsize := count
if !hasSize {
@@ -2566,9 +2576,9 @@ func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //noli
}
func (d *decoder) parseArrayToStruct(v reflect.Value, tInfo *typeInfo) error {
- structType := getDecodingStructType(tInfo.nonPtrType)
- if structType.err != nil {
- return structType.err
+ structType, structTypeErr := getDecodingStructType(tInfo.nonPtrType)
+ if structTypeErr != nil {
+ return structTypeErr
}
if !structType.toArray {
@@ -2584,7 +2594,7 @@ func (d *decoder) parseArrayToStruct(v reflect.Value, tInfo *typeInfo) error {
start := d.off
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
hasSize := !indefiniteLength
- count := int(val)
+ count := int(val) //nolint:gosec
if !hasSize {
count = d.numOfItemsUntilBreak() // peek ahead to get array size
}
@@ -2637,11 +2647,72 @@ func (d *decoder) parseArrayToStruct(v reflect.Value, tInfo *typeInfo) error {
return err
}
-// parseMapToStruct needs to be fast so gocyclo can be ignored for now.
+// skipMapEntriesFromIndex skips remaining map entries starting from index i.
+func (d *decoder) skipMapEntriesFromIndex(i, count int, hasSize bool) {
+ for ; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ {
+ d.skip()
+ d.skip()
+ }
+}
+
+// skipMapForDupKey skips the current map value and all remaining map entries,
+// then returns a DupMapKeyError for the given key at map index i.
+func (d *decoder) skipMapForDupKey(dupKey any, i, count int, hasSize bool) error {
+ // Skip the value of the duplicate key.
+ d.skip()
+ // Skip all remaining map entries.
+ d.skipMapEntriesFromIndex(i+1, count, hasSize)
+ return &DupMapKeyError{dupKey, i}
+}
+
+// skipMapForUnknownField skips the current map value and all remaining map entries,
+// then returns a UnknownFieldError for the given key at map index i.
+func (d *decoder) skipMapForUnknownField(i, count int, hasSize bool) error {
+ // Skip the value of the unknown key.
+ d.skip()
+ // Skip all remaining map entries.
+ d.skipMapEntriesFromIndex(i+1, count, hasSize)
+ return &UnknownFieldError{i}
+}
+
+// decodeToStructField decodes the next CBOR value into the struct field f in v.
+// If the field cannot be resolved, the CBOR value is skipped.
+func (d *decoder) decodeToStructField(v reflect.Value, f *decodingField, tInfo *typeInfo) error {
+ var fv reflect.Value
+
+ if len(f.idx) == 1 {
+ fv = v.Field(f.idx[0])
+ } else {
+ var err error
+ fv, err = getFieldValue(v, f.idx, func(v reflect.Value) (reflect.Value, error) {
+ // Return a new value for embedded field null pointer to point to, or return error.
+ if !v.CanSet() {
+ return reflect.Value{}, errors.New("cbor: cannot set embedded pointer to unexported struct: " + v.Type().String())
+ }
+ v.Set(reflect.New(v.Type().Elem()))
+ return v, nil
+ })
+ if !fv.IsValid() {
+ d.skip()
+ return err
+ }
+ }
+
+ err := d.parseToValue(fv, f.typInfo)
+ if err != nil {
+ if typeError, ok := err.(*UnmarshalTypeError); ok {
+ typeError.StructFieldName = tInfo.nonPtrType.String() + "." + f.name
+ }
+ return err
+ }
+
+ return nil
+}
+
func (d *decoder) parseMapToStruct(v reflect.Value, tInfo *typeInfo) error { //nolint:gocyclo
- structType := getDecodingStructType(tInfo.nonPtrType)
- if structType.err != nil {
- return structType.err
+ structType, structTypeErr := getDecodingStructType(tInfo.nonPtrType)
+ if structTypeErr != nil {
+ return structTypeErr
}
if structType.toArray {
@@ -2654,14 +2725,12 @@ func (d *decoder) parseMapToStruct(v reflect.Value, tInfo *typeInfo) error { //n
}
}
- var err, lastErr error
-
// Get CBOR map size
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
hasSize := !indefiniteLength
- count := int(val)
+ count := int(val) //nolint:gosec
- // Keeps track of matched struct fields
+ // Keep track of matched struct fields to detect duplicate map keys.
var foundFldIdx []bool
{
const maxStackFields = 128
@@ -2675,99 +2744,80 @@ func (d *decoder) parseMapToStruct(v reflect.Value, tInfo *typeInfo) error { //n
}
}
- // Keeps track of CBOR map keys to detect duplicate map key
- keyCount := 0
- var mapKeys map[any]struct{}
-
- errOnUnknownField := (d.dm.extraReturnErrors & ExtraDecErrorUnknownField) > 0
+ // Keep track of unmatched CBOR map keys to detect duplicate map keys.
+ var unmatchedMapKeys map[any]struct{}
-MapEntryLoop:
- for j := 0; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ {
- var f *field
+ var err error
- // If duplicate field detection is enabled and the key at index j did not match any
- // field, k will hold the map key.
- var k any
+ caseInsensitive := d.dm.fieldNameMatching == FieldNameMatchingPreferCaseSensitive
+ for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ {
t := d.nextCBORType()
- if t == cborTypeTextString || (t == cborTypeByteString && d.dm.fieldNameByteString == FieldNameByteStringAllowed) {
+
+ // Reclassify disallowed byte string keys so they fall to the default case.
+ // keyType is only used for branch control.
+ keyType := t
+ if t == cborTypeByteString && d.dm.fieldNameByteString != FieldNameByteStringAllowed {
+ keyType = 0xff
+ }
+
+ switch keyType {
+ case cborTypeTextString, cborTypeByteString:
var keyBytes []byte
if t == cborTypeTextString {
- keyBytes, lastErr = d.parseTextString()
- if lastErr != nil {
+ var parseErr error
+ keyBytes, parseErr = d.parseTextString()
+ if parseErr != nil {
if err == nil {
- err = lastErr
+ err = parseErr
}
- d.skip() // skip value
+ d.skip() // Skip value
continue
}
} else { // cborTypeByteString
keyBytes, _ = d.parseByteString()
}
- // Check for exact match on field name.
- if i, ok := structType.fieldIndicesByName[string(keyBytes)]; ok {
- fld := structType.fields[i]
+ // Find matching struct field (exact match, then case-insensitive fallback).
+ if fldIdx, ok := findStructFieldByKey(structType, keyBytes, caseInsensitive); ok {
+ fld := structType.fields[fldIdx]
- if !foundFldIdx[i] {
- f = fld
- foundFldIdx[i] = true
- } else if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
- err = &DupMapKeyError{fld.name, j}
- d.skip() // skip value
- j++
- // skip the rest of the map
- for ; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ {
- d.skip()
- d.skip()
+ switch checkDupField(d.dm, foundFldIdx, fldIdx) {
+ case mapActionParseValueAndContinue:
+ if fieldErr := d.decodeToStructField(v, fld, tInfo); fieldErr != nil && err == nil {
+ err = fieldErr
}
- return err
- } else {
- // discard repeated match
+ continue
+ case mapActionSkipAllAndReturnError:
+ return d.skipMapForDupKey(string(keyBytes), i, count, hasSize)
+ case mapActionSkipValueAndContinue:
d.skip()
- continue MapEntryLoop
+ continue
}
}
- // Find field with case-insensitive match
- if f == nil && d.dm.fieldNameMatching == FieldNameMatchingPreferCaseSensitive {
- keyLen := len(keyBytes)
- keyString := string(keyBytes)
- for i := 0; i < len(structType.fields); i++ {
- fld := structType.fields[i]
- if len(fld.name) == keyLen && strings.EqualFold(fld.name, keyString) {
- if !foundFldIdx[i] {
- f = fld
- foundFldIdx[i] = true
- } else if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
- err = &DupMapKeyError{keyString, j}
- d.skip() // skip value
- j++
- // skip the rest of the map
- for ; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ {
- d.skip()
- d.skip()
- }
- return err
- } else {
- // discard repeated match
- d.skip()
- continue MapEntryLoop
- }
- break
- }
- }
+ // No matching struct field found.
+ if unmatchedErr := handleUnmatchedMapKey(d, string(keyBytes), i, count, hasSize, &unmatchedMapKeys); unmatchedErr != nil {
+ return unmatchedErr
}
- if d.dm.dupMapKey == DupMapKeyEnforcedAPF && f == nil {
- k = string(keyBytes)
- }
- } else if t <= cborTypeNegativeInt { // uint/int
+ case cborTypePositiveInt, cborTypeNegativeInt:
var nameAsInt int64
if t == cborTypePositiveInt {
_, _, val := d.getHead()
- nameAsInt = int64(val)
+ if val > math.MaxInt64 {
+ if err == nil {
+ err = &UnmarshalTypeError{
+ CBORType: t.String(),
+ GoType: reflect.TypeOf(int64(0)).String(),
+ errorMsg: strconv.FormatUint(val, 10) + " overflows Go's int64",
+ }
+ }
+ d.skip() // skip value
+ continue
+ }
+ nameAsInt = int64(val) //nolint:gosec
} else {
_, _, val := d.getHead()
if val > math.MaxInt64 {
@@ -2781,39 +2831,35 @@ MapEntryLoop:
d.skip() // skip value
continue
}
- nameAsInt = int64(-1) ^ int64(val)
- }
-
- // Find field
- for i := 0; i < len(structType.fields); i++ {
- fld := structType.fields[i]
- if fld.keyAsInt && fld.nameAsInt == nameAsInt {
- if !foundFldIdx[i] {
- f = fld
- foundFldIdx[i] = true
- } else if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
- err = &DupMapKeyError{nameAsInt, j}
- d.skip() // skip value
- j++
- // skip the rest of the map
- for ; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ {
- d.skip()
- d.skip()
- }
- return err
- } else {
- // discard repeated match
- d.skip()
- continue MapEntryLoop
+ nameAsInt = int64(-1) ^ int64(val) //nolint:gosec
+ }
+
+ // Find field by integer key
+ if fldIdx, ok := structType.fieldIndicesByIntKey[nameAsInt]; ok {
+ fld := structType.fields[fldIdx]
+
+ switch checkDupField(d.dm, foundFldIdx, fldIdx) {
+ case mapActionParseValueAndContinue:
+ if fieldErr := d.decodeToStructField(v, fld, tInfo); fieldErr != nil && err == nil {
+ err = fieldErr
}
- break
+ continue
+ case mapActionSkipAllAndReturnError:
+ return d.skipMapForDupKey(nameAsInt, i, count, hasSize)
+ case mapActionSkipValueAndContinue:
+ d.skip()
+ continue
}
}
- if d.dm.dupMapKey == DupMapKeyEnforcedAPF && f == nil {
- k = nameAsInt
+ // No matching struct field found.
+ if unmatchedErr := handleUnmatchedMapKey(d, nameAsInt, i, count, hasSize, &unmatchedMapKeys); unmatchedErr != nil {
+ return unmatchedErr
}
- } else {
+
+ default:
+ // CBOR map keys that can't be matched to any struct field.
+
if err == nil {
err = &UnmarshalTypeError{
CBORType: t.String(),
@@ -2821,97 +2867,31 @@ MapEntryLoop:
errorMsg: "map key is of type " + t.String() + " and cannot be used to match struct field name",
}
}
+
+ var otherKey any
if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
// parse key
- k, lastErr = d.parse(true)
- if lastErr != nil {
+ var parseErr error
+ otherKey, parseErr = d.parse(true)
+ if parseErr != nil {
d.skip() // skip value
continue
}
// Detect if CBOR map key can be used as Go map key.
- if !isHashableValue(reflect.ValueOf(k)) {
+ if !isHashableValue(reflect.ValueOf(otherKey)) {
d.skip() // skip value
continue
}
} else {
d.skip() // skip key
}
- }
-
- if f == nil {
- if errOnUnknownField {
- err = &UnknownFieldError{j}
- d.skip() // Skip value
- j++
- // skip the rest of the map
- for ; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ {
- d.skip()
- d.skip()
- }
- return err
- }
-
- // Two map keys that match the same struct field are immediately considered
- // duplicates. This check detects duplicates between two map keys that do
- // not match a struct field. If unknown field errors are enabled, then this
- // check is never reached.
- if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
- if mapKeys == nil {
- mapKeys = make(map[any]struct{}, 1)
- }
- mapKeys[k] = struct{}{}
- newKeyCount := len(mapKeys)
- if newKeyCount == keyCount {
- err = &DupMapKeyError{k, j}
- d.skip() // skip value
- j++
- // skip the rest of the map
- for ; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ {
- d.skip()
- d.skip()
- }
- return err
- }
- keyCount = newKeyCount
- }
-
- d.skip() // Skip value
- continue
- }
-
- // Get field value by index
- var fv reflect.Value
- if len(f.idx) == 1 {
- fv = v.Field(f.idx[0])
- } else {
- fv, lastErr = getFieldValue(v, f.idx, func(v reflect.Value) (reflect.Value, error) {
- // Return a new value for embedded field null pointer to point to, or return error.
- if !v.CanSet() {
- return reflect.Value{}, errors.New("cbor: cannot set embedded pointer to unexported struct: " + v.Type().String())
- }
- v.Set(reflect.New(v.Type().Elem()))
- return v, nil
- })
- if lastErr != nil && err == nil {
- err = lastErr
- }
- if !fv.IsValid() {
- d.skip()
- continue
- }
- }
- if lastErr = d.parseToValue(fv, f.typInfo); lastErr != nil {
- if err == nil {
- if typeError, ok := lastErr.(*UnmarshalTypeError); ok {
- typeError.StructFieldName = tInfo.nonPtrType.String() + "." + f.name
- err = typeError
- } else {
- err = lastErr
- }
+ if unmatchedErr := handleUnmatchedMapKey(d, otherKey, i, count, hasSize, &unmatchedMapKeys); unmatchedErr != nil {
+ return unmatchedErr
}
}
}
+
return err
}
@@ -2958,15 +2938,15 @@ func (d *decoder) skip() {
switch t {
case cborTypeByteString, cborTypeTextString:
- d.off += int(val)
+ d.off += int(val) //nolint:gosec
case cborTypeArray:
- for i := 0; i < int(val); i++ {
+ for i := 0; i < int(val); i++ { //nolint:gosec
d.skip()
}
case cborTypeMap:
- for i := 0; i < int(val)*2; i++ {
+ for i := 0; i < int(val)*2; i++ { //nolint:gosec
d.skip()
}
diff --git a/vendor/github.com/fxamacker/cbor/v2/decode_map_utils.go b/vendor/github.com/fxamacker/cbor/v2/decode_map_utils.go
new file mode 100644
index 00000000000..3c8c423ad1a
--- /dev/null
+++ b/vendor/github.com/fxamacker/cbor/v2/decode_map_utils.go
@@ -0,0 +1,98 @@
+// Copyright (c) Faye Amacker. All rights reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+package cbor
+
+import "strings"
+
+// mapAction represents the next action during decoding a CBOR map to a Go struct.
+type mapAction int
+
+const (
+ mapActionParseValueAndContinue mapAction = iota // The caller should process the map value.
+ mapActionSkipValueAndContinue // The caller should skip the map value.
+ mapActionSkipAllAndReturnError // The caller should skip the rest of the map and return an error.
+)
+
+// checkDupField checks if a struct field at index i has already been matched and returns the next action.
+// If not matched, it marks the field as matched and returns mapActionParseValueAndContinue.
+// If matched and DupMapKeyEnforcedAPF is specified in the given dm, it returns mapActionSkipAllAndReturnError.
+// If matched and DupMapKeyEnforcedAPF is not specified in the given dm, it returns mapActionSkipValueAndContinue.
+func checkDupField(dm *decMode, foundFldIdx []bool, i int) mapAction {
+ if !foundFldIdx[i] {
+ foundFldIdx[i] = true
+ return mapActionParseValueAndContinue
+ }
+ if dm.dupMapKey == DupMapKeyEnforcedAPF {
+ return mapActionSkipAllAndReturnError
+ }
+ return mapActionSkipValueAndContinue
+}
+
+// findStructFieldByKey finds a struct field matching keyBytes by name.
+// It tries an exact match first. If no exact match is found and
+// caseInsensitive is true, it falls back to a case-insensitive search.
+// findStructFieldByKey returns the field index and true, or -1 and false.
+func findStructFieldByKey(
+ structType *decodingStructType,
+ keyBytes []byte,
+ caseInsensitive bool,
+) (int, bool) {
+ if fldIdx, ok := structType.fieldIndicesByName[string(keyBytes)]; ok {
+ return fldIdx, true
+ }
+ if caseInsensitive {
+ return findFieldCaseInsensitive(structType.fields, string(keyBytes))
+ }
+ return -1, false
+}
+
+// findFieldCaseInsensitive returns the index of the first field whose name
+// case-insensitively matches key, or -1 and false if no field matches.
+func findFieldCaseInsensitive(flds decodingFields, key string) (int, bool) {
+ keyLen := len(key)
+ for i, f := range flds {
+ if f.keyAsInt {
+ continue
+ }
+ if len(f.name) == keyLen && strings.EqualFold(f.name, key) {
+ return i, true
+ }
+ }
+ return -1, false
+}
+
+// handleUnmatchedMapKey handles a map entry whose key does not match any struct
+// field. It can return UnknownFieldError or DupMapKeyError.
+// handleUnmatchedMapKey consumes the CBOR value, so the caller doesn't need to skip any values.
+// If an error is returned, the caller should abort parsing the map and return the error.
+// If no error is returned, the caller should continue to process the next map pair.
+func handleUnmatchedMapKey(
+ d *decoder,
+ key any,
+ i int,
+ count int,
+ hasSize bool,
+ // *map[any]struct{} is used here because we use lazy initialization for uks
+ uks *map[any]struct{}, //nolint:gocritic
+) error {
+ errOnUnknownField := (d.dm.extraReturnErrors & ExtraDecErrorUnknownField) > 0
+
+ if errOnUnknownField {
+ return d.skipMapForUnknownField(i, count, hasSize)
+ }
+
+ if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
+ if *uks == nil {
+ *uks = make(map[any]struct{})
+ }
+ if _, dup := (*uks)[key]; dup {
+ return d.skipMapForDupKey(key, i, count, hasSize)
+ }
+ (*uks)[key] = struct{}{}
+ }
+
+ // Skip value.
+ d.skip()
+ return nil
+}
diff --git a/vendor/github.com/fxamacker/cbor/v2/diagnose.go b/vendor/github.com/fxamacker/cbor/v2/diagnose.go
index 44afb866089..42a67ad11fa 100644
--- a/vendor/github.com/fxamacker/cbor/v2/diagnose.go
+++ b/vendor/github.com/fxamacker/cbor/v2/diagnose.go
@@ -51,11 +51,8 @@ const (
maxByteStringEncoding
)
-func (bse ByteStringEncoding) valid() error {
- if bse >= maxByteStringEncoding {
- return errors.New("cbor: invalid ByteStringEncoding " + strconv.Itoa(int(bse)))
- }
- return nil
+func (bse ByteStringEncoding) valid() bool {
+ return bse < maxByteStringEncoding
}
// DiagOptions specifies Diag options.
@@ -104,8 +101,8 @@ func (opts DiagOptions) DiagMode() (DiagMode, error) {
}
func (opts DiagOptions) diagMode() (*diagMode, error) {
- if err := opts.ByteStringEncoding.valid(); err != nil {
- return nil, err
+ if !opts.ByteStringEncoding.valid() {
+ return nil, errors.New("cbor: invalid ByteStringEncoding " + strconv.Itoa(int(opts.ByteStringEncoding)))
}
decMode, err := DecOptions{
@@ -360,7 +357,7 @@ func (di *diagnose) item() error { //nolint:gocyclo
case cborTypeArray:
_, _, val := di.d.getHead()
- count := int(val)
+ count := int(val) //nolint:gosec
di.w.WriteByte('[')
for i := 0; i < count; i++ {
@@ -376,7 +373,7 @@ func (di *diagnose) item() error { //nolint:gocyclo
case cborTypeMap:
_, _, val := di.d.getHead()
- count := int(val)
+ count := int(val) //nolint:gosec
di.w.WriteByte('{')
for i := 0; i < count; i++ {
@@ -477,8 +474,8 @@ func (di *diagnose) item() error { //nolint:gocyclo
func (di *diagnose) writeU16(val rune) {
di.w.WriteString("\\u")
var in [2]byte
- in[0] = byte(val >> 8)
- in[1] = byte(val)
+ in[0] = byte(val >> 8) //nolint:gosec
+ in[1] = byte(val) //nolint:gosec
sz := hex.EncodedLen(len(in))
di.w.Grow(sz)
dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz]
@@ -608,7 +605,7 @@ func (di *diagnose) encodeTextString(val string, quote byte) error {
c, size := utf8.DecodeRuneInString(val[i:])
switch {
- case c == utf8.RuneError:
+ case c == utf8.RuneError && size == 1:
return &SemanticError{"cbor: invalid UTF-8 string"}
case c < utf16SurrSelf:
@@ -631,7 +628,7 @@ func (di *diagnose) encodeFloat(ai byte, val uint64) error {
f64 := float64(0)
switch ai {
case additionalInformationAsFloat16:
- f16 := float16.Frombits(uint16(val))
+ f16 := float16.Frombits(uint16(val)) //nolint:gosec
switch {
case f16.IsNaN():
di.w.WriteString("NaN")
@@ -647,7 +644,7 @@ func (di *diagnose) encodeFloat(ai byte, val uint64) error {
}
case additionalInformationAsFloat32:
- f32 := math.Float32frombits(uint32(val))
+ f32 := math.Float32frombits(uint32(val)) //nolint:gosec
switch {
case f32 != f32:
di.w.WriteString("NaN")
diff --git a/vendor/github.com/fxamacker/cbor/v2/doc.go b/vendor/github.com/fxamacker/cbor/v2/doc.go
index c758b737489..e4c1d27b8dd 100644
--- a/vendor/github.com/fxamacker/cbor/v2/doc.go
+++ b/vendor/github.com/fxamacker/cbor/v2/doc.go
@@ -56,20 +56,30 @@ modes won't accidentally change at runtime after they're created.
Modes are intended to be reused and are safe for concurrent use.
-EncMode and DecMode Interfaces
+EncMode, UserBufferEncMode, and DecMode Interfaces
// EncMode interface uses immutable options and is safe for concurrent use.
type EncMode interface {
- Marshal(v interface{}) ([]byte, error)
+ Marshal(v any) ([]byte, error)
NewEncoder(w io.Writer) *Encoder
- EncOptions() EncOptions // returns copy of options
+ EncOptions() EncOptions
+ }
+
+ // UserBufferEncMode extends EncMode with MarshalToBuffer, which supports
+ // user specified buffer rather than encoding into the built-in buffer pool.
+ type UserBufferEncMode interface {
+ EncMode
+ MarshalToBuffer(v any, buf *bytes.Buffer) error
}
// DecMode interface uses immutable options and is safe for concurrent use.
type DecMode interface {
- Unmarshal(data []byte, v interface{}) error
+ Unmarshal(data []byte, v any) error
+ UnmarshalFirst(data []byte, v any) (rest []byte, err error)
+ Valid(data []byte) error // Deprecated: use Wellformed instead.
+ Wellformed(data []byte) error
NewDecoder(r io.Reader) *Decoder
- DecOptions() DecOptions // returns copy of options
+ DecOptions() DecOptions
}
Using Default Encoding Mode
diff --git a/vendor/github.com/fxamacker/cbor/v2/encode.go b/vendor/github.com/fxamacker/cbor/v2/encode.go
index c550617c387..e65a29d8a6f 100644
--- a/vendor/github.com/fxamacker/cbor/v2/encode.go
+++ b/vendor/github.com/fxamacker/cbor/v2/encode.go
@@ -30,7 +30,7 @@ import (
// If value implements the Marshaler interface, Marshal calls its
// MarshalCBOR method.
//
-// If value implements encoding.BinaryMarshaler, Marhsal calls its
+// If value implements encoding.BinaryMarshaler, Marshal calls its
// MarshalBinary method and encode it as CBOR byte string.
//
// Boolean values encode as CBOR booleans (type 7).
@@ -343,7 +343,7 @@ const (
// non-UTC timezone then a "localtime - UTC" numeric offset will be included as specified in RFC3339.
// NOTE: User applications can avoid including the RFC3339 numeric offset by:
// - providing a time.Time value set to UTC, or
- // - using the TimeUnix, TimeUnixMicro, or TimeUnixDynamic option instead of TimeRFC3339.
+ // - using the TimeUnix, TimeUnixMicro, TimeUnixDynamic, or TimeRFC3339NanoUTC option.
TimeRFC3339
// TimeRFC3339Nano causes time.Time to encode to a CBOR time (tag 0) with a text string content
@@ -351,9 +351,13 @@ const (
// non-UTC timezone then a "localtime - UTC" numeric offset will be included as specified in RFC3339.
// NOTE: User applications can avoid including the RFC3339 numeric offset by:
// - providing a time.Time value set to UTC, or
- // - using the TimeUnix, TimeUnixMicro, or TimeUnixDynamic option instead of TimeRFC3339Nano.
+ // - using the TimeUnix, TimeUnixMicro, TimeUnixDynamic, or TimeRFC3339NanoUTC option.
TimeRFC3339Nano
+ // TimeRFC3339NanoUTC causes time.Time to encode to a CBOR time (tag 0) with a text string content
+ // representing UTC time using nanosecond precision in RFC3339 format.
+ TimeRFC3339NanoUTC
+
maxTimeMode
)
@@ -436,7 +440,7 @@ const (
// FieldNameToTextString encodes struct fields to CBOR text string (major type 3).
FieldNameToTextString FieldNameMode = iota
- // FieldNameToTextString encodes struct fields to CBOR byte string (major type 2).
+ // FieldNameToByteString encodes struct fields to CBOR byte string (major type 2).
FieldNameToByteString
maxFieldNameMode
@@ -567,7 +571,7 @@ type EncOptions struct {
// RFC3339 format gets tag number 0, and numeric epoch time tag number 1.
TimeTag EncTagMode
- // IndefLength specifies whether to allow indefinite length CBOR items.
+ // IndefLength specifies whether to allow indefinite-length CBOR items.
IndefLength IndefLengthMode
// NilContainers specifies how to encode nil slices and maps.
@@ -1132,10 +1136,11 @@ func encodeFloat(e *bytes.Buffer, em *encMode, v reflect.Value) error {
if fopt == ShortestFloat16 {
var f16 float16.Float16
p := float16.PrecisionFromfloat32(f32)
- if p == float16.PrecisionExact {
+ switch p {
+ case float16.PrecisionExact:
// Roundtrip float32->float16->float32 test isn't needed.
f16 = float16.Fromfloat32(f32)
- } else if p == float16.PrecisionUnknown {
+ case float16.PrecisionUnknown:
// Try roundtrip float32->float16->float32 to determine if float32 can fit into float16.
f16 = float16.Fromfloat32(f32)
if f16.Float32() == f32 {
@@ -1293,10 +1298,10 @@ func encodeByteString(e *bytes.Buffer, em *encMode, v reflect.Value) error {
if slen == 0 {
return e.WriteByte(byte(cborTypeByteString))
}
- encodeHead(e, byte(cborTypeByteString), uint64(slen))
+ encodeHead(e, byte(cborTypeByteString), uint64(slen)) //nolint:gosec
if vk == reflect.Array {
for i := 0; i < slen; i++ {
- e.WriteByte(byte(v.Index(i).Uint()))
+ e.WriteByte(byte(v.Index(i).Uint())) //nolint:gosec
}
return nil
}
@@ -1333,7 +1338,7 @@ func (ae arrayEncodeFunc) encode(e *bytes.Buffer, em *encMode, v reflect.Value)
if alen == 0 {
return e.WriteByte(byte(cborTypeArray))
}
- encodeHead(e, byte(cborTypeArray), uint64(alen))
+ encodeHead(e, byte(cborTypeArray), uint64(alen)) //nolint:gosec
for i := 0; i < alen; i++ {
if err := ae.f(e, em, v.Index(i)); err != nil {
return err
@@ -1364,7 +1369,7 @@ func (me mapEncodeFunc) encode(e *bytes.Buffer, em *encMode, v reflect.Value) er
return e.WriteByte(byte(cborTypeMap))
}
- encodeHead(e, byte(cborTypeMap), uint64(mlen))
+ encodeHead(e, byte(cborTypeMap), uint64(mlen)) //nolint:gosec
if em.sort == SortNone || em.sort == SortFastShuffle || mlen <= 1 {
return me.e(e, em, v, nil)
}
@@ -1427,7 +1432,7 @@ func (x *bytewiseKeyValueSorter) Swap(i, j int) {
func (x *bytewiseKeyValueSorter) Less(i, j int) bool {
kvi, kvj := x.kvs[i], x.kvs[j]
- return bytes.Compare(x.data[kvi.offset:kvi.valueOffset], x.data[kvj.offset:kvj.valueOffset]) <= 0
+ return bytes.Compare(x.data[kvi.offset:kvi.valueOffset], x.data[kvj.offset:kvj.valueOffset]) < 0
}
type lengthFirstKeyValueSorter struct {
@@ -1448,7 +1453,7 @@ func (x *lengthFirstKeyValueSorter) Less(i, j int) bool {
if keyLengthDifference := (kvi.valueOffset - kvi.offset) - (kvj.valueOffset - kvj.offset); keyLengthDifference != 0 {
return keyLengthDifference < 0
}
- return bytes.Compare(x.data[kvi.offset:kvi.valueOffset], x.data[kvj.offset:kvj.valueOffset]) <= 0
+ return bytes.Compare(x.data[kvi.offset:kvi.valueOffset], x.data[kvj.offset:kvj.valueOffset]) < 0
}
var keyValuePool = sync.Pool{}
@@ -1535,8 +1540,8 @@ func encodeStruct(e *bytes.Buffer, em *encMode, v reflect.Value) (err error) {
// Head is rewritten later if actual encoded field count is different from struct field count.
encodedHeadLen := encodeHead(e, byte(cborTypeMap), uint64(len(flds)))
- kvbegin := e.Len()
- kvcount := 0
+ kvBeginOffset := e.Len()
+ kvCount := 0
for offset := 0; offset < len(flds); offset++ {
f := flds[(start+offset)%len(flds)]
@@ -1582,10 +1587,10 @@ func encodeStruct(e *bytes.Buffer, em *encMode, v reflect.Value) (err error) {
return err
}
- kvcount++
+ kvCount++
}
- if len(flds) == kvcount {
+ if len(flds) == kvCount {
// Encoded element count in head is the same as actual element count.
return nil
}
@@ -1593,8 +1598,8 @@ func encodeStruct(e *bytes.Buffer, em *encMode, v reflect.Value) (err error) {
// Overwrite the bytes that were reserved for the head before encoding the map entries.
var actualHeadLen int
{
- headbuf := *bytes.NewBuffer(e.Bytes()[kvbegin-encodedHeadLen : kvbegin-encodedHeadLen : kvbegin])
- actualHeadLen = encodeHead(&headbuf, byte(cborTypeMap), uint64(kvcount))
+ headbuf := *bytes.NewBuffer(e.Bytes()[kvBeginOffset-encodedHeadLen : kvBeginOffset-encodedHeadLen : kvBeginOffset])
+ actualHeadLen = encodeHead(&headbuf, byte(cborTypeMap), uint64(kvCount))
}
if actualHeadLen == encodedHeadLen {
@@ -1607,8 +1612,8 @@ func encodeStruct(e *bytes.Buffer, em *encMode, v reflect.Value) (err error) {
// encoded. The encoded entries are offset to the right by the number of excess reserved
// bytes. Shift the entries left to remove the gap.
excessReservedBytes := encodedHeadLen - actualHeadLen
- dst := e.Bytes()[kvbegin-excessReservedBytes : e.Len()-excessReservedBytes]
- src := e.Bytes()[kvbegin:e.Len()]
+ dst := e.Bytes()[kvBeginOffset-excessReservedBytes : e.Len()-excessReservedBytes]
+ src := e.Bytes()[kvBeginOffset:e.Len()]
copy(dst, src)
// After shifting, the excess bytes are at the end of the output buffer and they are
@@ -1633,7 +1638,7 @@ func encodeTime(e *bytes.Buffer, em *encMode, v reflect.Value) error {
}
if em.timeTag == EncTagRequired {
tagNumber := 1
- if em.time == TimeRFC3339 || em.time == TimeRFC3339Nano {
+ if em.time == TimeRFC3339 || em.time == TimeRFC3339Nano || em.time == TimeRFC3339NanoUTC {
tagNumber = 0
}
encodeHead(e, byte(cborTypeTag), uint64(tagNumber))
@@ -1650,7 +1655,7 @@ func encodeTime(e *bytes.Buffer, em *encMode, v reflect.Value) error {
case TimeUnixDynamic:
t = t.UTC().Round(time.Microsecond)
- secs, nsecs := t.Unix(), uint64(t.Nanosecond())
+ secs, nsecs := t.Unix(), uint64(t.Nanosecond()) //nolint:gosec
if nsecs == 0 {
return encodeInt(e, em, reflect.ValueOf(secs))
}
@@ -1661,6 +1666,10 @@ func encodeTime(e *bytes.Buffer, em *encMode, v reflect.Value) error {
s := t.Format(time.RFC3339)
return encodeString(e, em, reflect.ValueOf(s))
+ case TimeRFC3339NanoUTC:
+ s := t.UTC().Format(time.RFC3339Nano)
+ return encodeString(e, em, reflect.ValueOf(s))
+
default: // TimeRFC3339Nano
s := t.Format(time.RFC3339Nano)
return encodeString(e, em, reflect.ValueOf(s))
diff --git a/vendor/github.com/fxamacker/cbor/v2/simplevalue.go b/vendor/github.com/fxamacker/cbor/v2/simplevalue.go
index 30f72814f60..9912e855c24 100644
--- a/vendor/github.com/fxamacker/cbor/v2/simplevalue.go
+++ b/vendor/github.com/fxamacker/cbor/v2/simplevalue.go
@@ -93,6 +93,6 @@ func (sv *SimpleValue) unmarshalCBOR(data []byte) error {
// It is safe to cast val to uint8 here because
// - data is already verified to be well-formed CBOR simple value and
// - val is <= math.MaxUint8.
- *sv = SimpleValue(val)
+ *sv = SimpleValue(val) //nolint:gosec
return nil
}
diff --git a/vendor/github.com/fxamacker/cbor/v2/stream.go b/vendor/github.com/fxamacker/cbor/v2/stream.go
index 7ac6d7d6712..282b3f7ddc9 100644
--- a/vendor/github.com/fxamacker/cbor/v2/stream.go
+++ b/vendor/github.com/fxamacker/cbor/v2/stream.go
@@ -6,6 +6,7 @@ package cbor
import (
"bytes"
"errors"
+ "fmt"
"io"
"reflect"
)
@@ -157,11 +158,32 @@ func (dec *Decoder) overwriteBuf(newBuf []byte) {
dec.off = 0
}
+// indefDataItem tracks open indefinite-length data item during encoding.
+// typ is the CBOR type of the indefinite-length data item.
+// count is the number of items written so far.
+// For indefinite-length maps, count must be even (key/value pairs) when
+// the container is closed.
+type indefDataItem struct {
+ typ cborType
+ count int
+}
+
+// IndefiniteLengthMapOddItemCountError indicates that EndIndefinite was
+// called on an open indefinite-length map with an odd number of items.
+type IndefiniteLengthMapOddItemCountError struct {
+ count int
+}
+
+func (e *IndefiniteLengthMapOddItemCountError) Error() string {
+ return fmt.Sprintf("cbor: cannot end indefinite-length map with %d item(s)", e.count)
+}
+
// Encoder writes CBOR values to io.Writer.
type Encoder struct {
- w io.Writer
- em *encMode
- indefTypes []cborType
+ w io.Writer
+ em *encMode
+ indefs []indefDataItem
+ scratch [1]byte // reused for single-byte writes (indefinite-length head and break code)
}
// NewEncoder returns a new encoder that writes to w using the default encoding options.
@@ -171,89 +193,166 @@ func NewEncoder(w io.Writer) *Encoder {
// Encode writes the CBOR encoding of v.
func (enc *Encoder) Encode(v any) error {
- if len(enc.indefTypes) > 0 && v != nil {
- indefType := enc.indefTypes[len(enc.indefTypes)-1]
- if indefType == cborTypeTextString {
- k := reflect.TypeOf(v).Kind()
- if k != reflect.String {
- return errors.New("cbor: cannot encode item type " + k.String() + " for indefinite-length text string")
- }
- } else if indefType == cborTypeByteString {
- t := reflect.TypeOf(v)
- k := t.Kind()
- if (k != reflect.Array && k != reflect.Slice) || t.Elem().Kind() != reflect.Uint8 {
- return errors.New("cbor: cannot encode item type " + k.String() + " for indefinite-length byte string")
- }
+ if len(enc.indefs) > 0 {
+ err := validateIndefiniteLengthChunkByType(enc.indefs[len(enc.indefs)-1].typ, v)
+ if err != nil {
+ return err
}
}
buf := getEncodeBuffer()
err := encode(buf, enc.em, reflect.ValueOf(v))
+
+ // Validate the encoded chunk against the indefinite-length data item using a byte-based check.
+ // This reliably detects chunks from cbor.Marshaler, registered tags, StringToByteString, etc.,
+ // which may produce a chunk inconsistent with the parent's major type.
+ // Applies only to indefinite-length byte/text string parents (RFC 8949 Section 3.2.3).
+ if err == nil && len(enc.indefs) > 0 {
+ err = validateIndefiniteLengthChunkByData(enc.indefs[len(enc.indefs)-1].typ, buf.Bytes(), v)
+ }
+
if err == nil {
_, err = enc.w.Write(buf.Bytes())
}
putEncodeBuffer(buf)
- return err
+
+ if err != nil {
+ return err
+ }
+
+ if len(enc.indefs) > 0 {
+ enc.indefs[len(enc.indefs)-1].count++
+ }
+
+ return nil
}
-// StartIndefiniteByteString starts byte string encoding of indefinite length.
+// StartIndefiniteByteString starts indefinite-length byte string encoding.
// Subsequent calls of (*Encoder).Encode() encodes definite length byte strings
// ("chunks") as one contiguous string until EndIndefinite is called.
func (enc *Encoder) StartIndefiniteByteString() error {
return enc.startIndefinite(cborTypeByteString)
}
-// StartIndefiniteTextString starts text string encoding of indefinite length.
+// StartIndefiniteTextString starts indefinite-length text string encoding.
// Subsequent calls of (*Encoder).Encode() encodes definite length text strings
// ("chunks") as one contiguous string until EndIndefinite is called.
func (enc *Encoder) StartIndefiniteTextString() error {
return enc.startIndefinite(cborTypeTextString)
}
-// StartIndefiniteArray starts array encoding of indefinite length.
+// StartIndefiniteArray starts indefinite-length array encoding.
// Subsequent calls of (*Encoder).Encode() encodes elements of the array
// until EndIndefinite is called.
func (enc *Encoder) StartIndefiniteArray() error {
return enc.startIndefinite(cborTypeArray)
}
-// StartIndefiniteMap starts array encoding of indefinite length.
+// StartIndefiniteMap starts indefinite-length map encoding.
// Subsequent calls of (*Encoder).Encode() encodes elements of the map
// until EndIndefinite is called.
func (enc *Encoder) StartIndefiniteMap() error {
return enc.startIndefinite(cborTypeMap)
}
-// EndIndefinite closes last opened indefinite length value.
+// EndIndefinite closes last opened indefinite-length value.
+// It returns *IndefiniteLengthMapOddItemCountError without writing the
+// "break" code if the open indefinite-length map has an odd number of
+// items; the encoder state is unchanged so the caller can write the
+// missing value and retry.
func (enc *Encoder) EndIndefinite() error {
- if len(enc.indefTypes) == 0 {
+ if len(enc.indefs) == 0 {
return errors.New("cbor: cannot encode \"break\" code outside indefinite length values")
}
- _, err := enc.w.Write([]byte{cborBreakFlag})
- if err == nil {
- enc.indefTypes = enc.indefTypes[:len(enc.indefTypes)-1]
+
+ // Verify that indefinite-length map has even number of elements
+ top := enc.indefs[len(enc.indefs)-1]
+ if top.typ == cborTypeMap && top.count%2 != 0 {
+ return &IndefiniteLengthMapOddItemCountError{count: top.count}
}
- return err
-}
-var cborIndefHeader = map[cborType][]byte{
- cborTypeByteString: {cborByteStringWithIndefiniteLengthHead},
- cborTypeTextString: {cborTextStringWithIndefiniteLengthHead},
- cborTypeArray: {cborArrayWithIndefiniteLengthHead},
- cborTypeMap: {cborMapWithIndefiniteLengthHead},
+ // Write break code
+ enc.scratch[0] = cborBreakFlag
+ _, err := enc.w.Write(enc.scratch[:])
+ if err != nil {
+ return err
+ }
+
+ enc.indefs = enc.indefs[:len(enc.indefs)-1]
+
+ // Increment parent container's item count because the child
+ // (indefinite-length data item) is fully written to the stream.
+ if len(enc.indefs) > 0 {
+ enc.indefs[len(enc.indefs)-1].count++
+ }
+
+ return nil
}
func (enc *Encoder) startIndefinite(typ cborType) error {
if enc.em.indefLength == IndefLengthForbidden {
return &IndefiniteLengthError{typ}
}
- _, err := enc.w.Write(cborIndefHeader[typ])
- if err == nil {
- enc.indefTypes = append(enc.indefTypes, typ)
+
+ // Verify that new indefinite-length data item is not a chunk in indefinite-length byte/text string.
+ if len(enc.indefs) > 0 {
+ parent := enc.indefs[len(enc.indefs)-1].typ
+ if parent == cborTypeByteString || parent == cborTypeTextString {
+ return errors.New("cbor: cannot encode indefinite-length " + typ.String() +
+ " as chunk of indefinite-length " + parent.String())
+ }
}
- return err
+
+ // Write indefinite-length head.
+ enc.scratch[0] = byte(typ) | additionalInformationAsIndefiniteLengthFlag
+ _, err := enc.w.Write(enc.scratch[:])
+ if err != nil {
+ return err
+ }
+
+ enc.indefs = append(enc.indefs, indefDataItem{typ: typ})
+ return nil
+}
+
+// validateIndefiniteLengthChunkByType rejects chunks based solely on their Go type.
+func validateIndefiniteLengthChunkByType(indefiniteLengthCborType cborType, v any) error {
+ if indefiniteLengthCborType != cborTypeByteString &&
+ indefiniteLengthCborType != cborTypeTextString {
+ return nil
+ }
+ if v == nil {
+ return errors.New("cbor: cannot encode nil for indefinite-length " + indefiniteLengthCborType.String())
+ }
+ return nil
+}
+
+// validateIndefiniteLengthChunkByData checks that chunk is a definite-length
+// CBOR data item with a matching major type.
+// No-op for indefinite-length array/map, where any data item is valid.
+func validateIndefiniteLengthChunkByData(indefiniteLengthCborType cborType, chunk []byte, v any) error {
+ if indefiniteLengthCborType != cborTypeByteString &&
+ indefiniteLengthCborType != cborTypeTextString {
+ return nil
+ }
+
+ if len(chunk) == 0 {
+ return errors.New("cbor: cannot encode item type " + reflect.TypeOf(v).Kind().String() +
+ " for indefinite-length " + indefiniteLengthCborType.String())
+ }
+
+ t, ai := parseInitialByte(chunk[0])
+ if t != indefiniteLengthCborType {
+ return errors.New("cbor: cannot encode item type " + reflect.TypeOf(v).Kind().String() +
+ " for indefinite-length " + indefiniteLengthCborType.String())
+ }
+
+ if ai == additionalInformationAsIndefiniteLengthFlag {
+ return errors.New("cbor: cannot encode indefinite-length " + indefiniteLengthCborType.String() +
+ " as chunk of indefinite-length " + indefiniteLengthCborType.String())
+ }
+ return nil
}
// RawMessage is a raw encoded CBOR value.
@@ -262,7 +361,9 @@ type RawMessage []byte
// MarshalCBOR returns m or CBOR nil if m is nil.
func (m RawMessage) MarshalCBOR() ([]byte, error) {
if len(m) == 0 {
- return cborNil, nil
+ b := make([]byte, len(cborNil))
+ copy(b, cborNil)
+ return b, nil
}
return m, nil
}
diff --git a/vendor/github.com/fxamacker/cbor/v2/structfields.go b/vendor/github.com/fxamacker/cbor/v2/structfields.go
index cf0a922cd7c..b2d71f2e9aa 100644
--- a/vendor/github.com/fxamacker/cbor/v2/structfields.go
+++ b/vendor/github.com/fxamacker/cbor/v2/structfields.go
@@ -6,27 +6,43 @@ package cbor
import (
"reflect"
"sort"
+ "strconv"
"strings"
)
+// field holds shared struct field metadata returned by getFields().
type field struct {
- name string
- nameAsInt int64 // used to decoder to match field name with CBOR int
+ name string
+ nameAsInt int64 // used to match field name with CBOR int
+ idx []int
+ typ reflect.Type // used during cache building only
+ keyAsInt bool // used to encode/decode field name as int
+ tagged bool // used to choose dominant field (at the same level tagged fields dominate untagged fields)
+ omitEmpty bool // used to skip empty field
+ omitZero bool // used to skip zero field
+}
+
+type fields []*field
+
+// encodingField extends field with encoding-specific data.
+type encodingField struct {
+ field
cborName []byte
- cborNameByteString []byte // major type 2 name encoding iff cborName has major type 3
- idx []int
- typ reflect.Type
+ cborNameByteString []byte // major type 2 name encoding if cborName has major type 3
ef encodeFunc
ief isEmptyFunc
izf isZeroFunc
- typInfo *typeInfo // used to decoder to reuse type info
- tagged bool // used to choose dominant field (at the same level tagged fields dominate untagged fields)
- omitEmpty bool // used to skip empty field
- omitZero bool // used to skip zero field
- keyAsInt bool // used to encode/decode field name as int
}
-type fields []*field
+type encodingFields []*encodingField
+
+// decodingField extends field with decoding-specific data.
+type decodingField struct {
+ field
+ typInfo *typeInfo // used by decoder to reuse type info
+}
+
+type decodingFields []*decodingField
// indexFieldSorter sorts fields by field idx at each level, breaking ties with idx depth.
type indexFieldSorter struct {
@@ -48,7 +64,7 @@ func (x *indexFieldSorter) Less(i, j int) bool {
return iIdx[k] < jIdx[k]
}
}
- return len(iIdx) <= len(jIdx)
+ return len(iIdx) < len(jIdx)
}
// nameLevelAndTagFieldSorter sorts fields by field name, idx depth, and presence of tag.
@@ -69,6 +85,10 @@ func (x *nameLevelAndTagFieldSorter) Less(i, j int) bool {
if fi.name != fj.name {
return fi.name < fj.name
}
+ // Fields with the same name but different keyAsInt are in separate namespaces.
+ if fi.keyAsInt != fj.keyAsInt {
+ return fi.keyAsInt
+ }
if len(fi.idx) != len(fj.idx) {
return len(fi.idx) < len(fj.idx)
}
@@ -117,22 +137,37 @@ func getFields(t reflect.Type) (flds fields, structOptions string) {
}
}
+ // Normalize keyasint field names to their canonical integer string form.
+ // This ensures that "01", "+1", and "1" are treated as the same key
+ // during deduplication.
+ for _, f := range flds {
+ if f.keyAsInt {
+ nameAsInt, err := strconv.Atoi(f.name)
+ if err != nil {
+ continue // Leave invalid names for callers to report.
+ }
+ f.nameAsInt = int64(nameAsInt)
+ f.name = strconv.Itoa(nameAsInt)
+ }
+ }
+
sort.Sort(&nameLevelAndTagFieldSorter{flds})
// Keep visible fields.
j := 0 // index of next unique field
for i := 0; i < len(flds); {
name := flds[i].name
+ keyAsInt := flds[i].keyAsInt
if i == len(flds)-1 || // last field
- name != flds[i+1].name || // field i has unique field name
+ name != flds[i+1].name || flds[i+1].keyAsInt != keyAsInt || // field i has unique (name, keyAsInt)
len(flds[i].idx) < len(flds[i+1].idx) || // field i is at a less nested level than field i+1
(flds[i].tagged && !flds[i+1].tagged) { // field i is tagged while field i+1 is not
flds[j] = flds[i]
j++
}
- // Skip fields with the same field name.
- for i++; i < len(flds) && name == flds[i].name; i++ { //nolint:revive
+ // Skip fields with the same (name, keyAsInt).
+ for i++; i < len(flds) && name == flds[i].name && keyAsInt == flds[i].keyAsInt; i++ { //nolint:revive
}
}
if j != len(flds) {
diff --git a/vendor/github.com/fxamacker/cbor/v2/tag.go b/vendor/github.com/fxamacker/cbor/v2/tag.go
index bd8b773f54b..ee46e742136 100644
--- a/vendor/github.com/fxamacker/cbor/v2/tag.go
+++ b/vendor/github.com/fxamacker/cbor/v2/tag.go
@@ -155,6 +155,7 @@ type TagSet interface {
Add(opts TagOptions, contentType reflect.Type, num uint64, nestedNum ...uint64) error
// Remove removes given tag content type from TagSet.
+ // Remove is a no-op if contentType is nil.
Remove(contentType reflect.Type)
tagProvider
@@ -245,7 +246,11 @@ func (t *syncTagSet) Add(opts TagOptions, contentType reflect.Type, num uint64,
}
// Remove removes given tag content type from TagSet.
+// Remove is a no-op if contentType is nil.
func (t *syncTagSet) Remove(contentType reflect.Type) {
+ if contentType == nil {
+ return
+ }
for contentType.Kind() == reflect.Pointer {
contentType = contentType.Elem()
}
diff --git a/vendor/github.com/fxamacker/cbor/v2/valid.go b/vendor/github.com/fxamacker/cbor/v2/valid.go
index b40793b95e3..850b95019c5 100644
--- a/vendor/github.com/fxamacker/cbor/v2/valid.go
+++ b/vendor/github.com/fxamacker/cbor/v2/valid.go
@@ -54,7 +54,7 @@ func (e *MaxMapPairsError) Error() string {
return "cbor: exceeded max number of key-value pairs " + strconv.Itoa(e.maxMapPairs) + " for CBOR map"
}
-// IndefiniteLengthError indicates found disallowed indefinite length items.
+// IndefiniteLengthError indicates found disallowed indefinite-length items.
type IndefiniteLengthError struct {
t cborType
}
@@ -113,7 +113,7 @@ func (d *decoder) wellformedInternal(depth int, checkBuiltinTags bool) (int, err
}
return d.wellformedIndefiniteString(t, depth, checkBuiltinTags)
}
- valInt := int(val)
+ valInt := int(val) //nolint:gosec
if valInt < 0 {
// Detect integer overflow
return 0, errors.New("cbor: " + t.String() + " length " + strconv.FormatUint(val, 10) + " is too large, causing integer overflow")
@@ -136,7 +136,7 @@ func (d *decoder) wellformedInternal(depth int, checkBuiltinTags bool) (int, err
return d.wellformedIndefiniteArrayOrMap(t, depth, checkBuiltinTags)
}
- valInt := int(val)
+ valInt := int(val) //nolint:gosec
if valInt < 0 {
// Detect integer overflow
return 0, errors.New("cbor: " + t.String() + " length " + strconv.FormatUint(val, 10) + " is too large, it would cause integer overflow")
@@ -212,7 +212,7 @@ func (d *decoder) wellformedInternal(depth int, checkBuiltinTags bool) (int, err
return depth, nil
}
-// wellformedIndefiniteString checks indefinite length byte/text string's well-formedness and returns max depth and error.
+// wellformedIndefiniteString checks indefinite-length byte/text string's well-formedness and returns max depth and error.
func (d *decoder) wellformedIndefiniteString(t cborType, depth int, checkBuiltinTags bool) (int, error) {
var err error
for {
@@ -223,7 +223,7 @@ func (d *decoder) wellformedIndefiniteString(t cborType, depth int, checkBuiltin
d.off++
break
}
- // Peek ahead to get next type and indefinite length status.
+ // Peek ahead to get next type and indefinite-length status.
nt, ai := parseInitialByte(d.data[d.off])
if t != nt {
return 0, &SyntaxError{"cbor: wrong element type " + nt.String() + " for indefinite-length " + t.String()}
@@ -238,7 +238,7 @@ func (d *decoder) wellformedIndefiniteString(t cborType, depth int, checkBuiltin
return depth, nil
}
-// wellformedIndefiniteArrayOrMap checks indefinite length array/map's well-formedness and returns max depth and error.
+// wellformedIndefiniteArrayOrMap checks indefinite-length array/map's well-formedness and returns max depth and error.
func (d *decoder) wellformedIndefiniteArrayOrMap(t cborType, depth int, checkBuiltinTags bool) (int, error) {
var err error
maxDepth := depth
@@ -326,7 +326,7 @@ func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error)
val = uint64(binary.BigEndian.Uint16(d.data[d.off : d.off+argumentSize]))
d.off += argumentSize
if t == cborTypePrimitives {
- if err := d.acceptableFloat(float64(float16.Frombits(uint16(val)).Float32())); err != nil {
+ if err := d.acceptableFloat(float64(float16.Frombits(uint16(val)).Float32())); err != nil { //nolint:gosec
return 0, 0, 0, err
}
}
@@ -341,7 +341,7 @@ func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error)
val = uint64(binary.BigEndian.Uint32(d.data[d.off : d.off+argumentSize]))
d.off += argumentSize
if t == cborTypePrimitives {
- if err := d.acceptableFloat(float64(math.Float32frombits(uint32(val)))); err != nil {
+ if err := d.acceptableFloat(float64(math.Float32frombits(uint32(val)))); err != nil { //nolint:gosec
return 0, 0, 0, err
}
}
@@ -379,12 +379,12 @@ func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error)
func (d *decoder) acceptableFloat(f float64) error {
switch {
- case d.dm.nanDec == NaNDecodeForbidden && math.IsNaN(f):
+ case d.dm.nan == NaNDecodeForbidden && math.IsNaN(f):
return &UnacceptableDataItemError{
CBORType: cborTypePrimitives.String(),
Message: "floating-point NaN",
}
- case d.dm.infDec == InfDecodeForbidden && math.IsInf(f, 0):
+ case d.dm.inf == InfDecodeForbidden && math.IsInf(f, 0):
return &UnacceptableDataItemError{
CBORType: cborTypePrimitives.String(),
Message: "floating-point infinity",
diff --git a/vendor/github.com/go-openapi/analysis/.gitignore b/vendor/github.com/go-openapi/analysis/.gitignore
index d8f4186fe59..20c4e0fa048 100644
--- a/vendor/github.com/go-openapi/analysis/.gitignore
+++ b/vendor/github.com/go-openapi/analysis/.gitignore
@@ -3,3 +3,5 @@
.idea
.env
.mcp.json
+go.work.sum
+.worktrees
diff --git a/vendor/github.com/go-openapi/analysis/CONTRIBUTORS.md b/vendor/github.com/go-openapi/analysis/CONTRIBUTORS.md
index 2f85f1c0504..d86830a0f3d 100644
--- a/vendor/github.com/go-openapi/analysis/CONTRIBUTORS.md
+++ b/vendor/github.com/go-openapi/analysis/CONTRIBUTORS.md
@@ -4,24 +4,31 @@
| Total Contributors | Total Contributions |
| --- | --- |
-| 15 | 207 |
+| 22 | 267 |
| Username | All Time Contribution Count | All Commits |
| --- | --- | --- |
-| @fredbi | 104 | |
-| @casualjim | 70 | |
+| @fredbi | 127 | |
+| @casualjim | 91 | |
| @keramix | 9 | |
| @youyuanwu | 8 | |
-| @msample | 3 | |
+| @wjase | 7 | |
| @kul-amr | 3 | |
+| @schafle | 3 | |
+| @msample | 3 | |
| @mbohlool | 2 | |
-| @Copilot | 1 | |
-| @danielfbm | 1 | |
-| @gregmarr | 1 | |
-| @guillemj | 1 | |
-| @knweiss | 1 | |
-| @tklauser | 1 | |
-| @cuishuang | 1 | |
+| @zmay2030 | 2 | |
| @ujjwalsh | 1 | |
+| @itengfei | 1 | |
+| @nrnrk | 1 | |
+| @cuishuang | 1 | |
+| @tklauser | 1 | |
+| @Shimizu1111 | 1 | |
+| @thaJeztah | 1 | |
+| @knweiss | 1 | |
+| @guillemj | 1 | |
+| @gregmarr | 1 | |
+| @danielfbm | 1 | |
+| @Copilot | 1 | |
_this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_
diff --git a/vendor/github.com/go-openapi/analysis/README.md b/vendor/github.com/go-openapi/analysis/README.md
index 82c782fcdd4..e4e3086598e 100644
--- a/vendor/github.com/go-openapi/analysis/README.md
+++ b/vendor/github.com/go-openapi/analysis/README.md
@@ -12,7 +12,7 @@
---
-A foundational library to analyze an OAI specification document for easier reasoning about the content.
+A foundational library to analyze, diff, flatten, merge, and fix OAI specification documents for easier reasoning about the content.
## Announcements
@@ -38,6 +38,7 @@ go get github.com/go-openapi/analysis
* An analyzer providing methods to walk the functional content of a specification
* A spec flattener producing a self-contained document bundle, while preserving `$ref`s
+* A spec differ ("diff") to compare two specs and report structural and compatibility changes
* A spec merger ("mixin") to merge several spec documents into a primary spec
* A spec "fixer" ensuring that response descriptions are non empty
diff --git a/vendor/github.com/go-openapi/analysis/analyzer.go b/vendor/github.com/go-openapi/analysis/analyzer.go
index 1c91b8c5507..c24811aaeb5 100644
--- a/vendor/github.com/go-openapi/analysis/analyzer.go
+++ b/vendor/github.com/go-openapi/analysis/analyzer.go
@@ -145,19 +145,27 @@ type Spec struct {
enums enumAnalysis
allSchemas map[string]SchemaRef
allOfs map[string]SchemaRef
+ mangler mangling.NameMangler
}
// New takes a swagger spec object and returns an analyzed spec document.
// The analyzed document contains a number of indices that make it easier to
// reason about semantics of a swagger specification for use in code generation
// or validation etc.
-func New(doc *spec.Swagger) *Spec {
+func New(doc *spec.Swagger, opts ...Option) *Spec {
+ o := &analyzerOptions{}
+ for _, opt := range opts {
+ opt(o)
+ }
+
a := &Spec{
spec: doc,
references: referenceAnalysis{},
patterns: patternAnalysis{},
enums: enumAnalysis{},
+ mangler: mangling.NewNameMangler(o.manglerOpts...),
}
+
a.reset()
a.initialize()
@@ -288,20 +296,6 @@ func (s *Spec) ProducesFor(operation *spec.Operation) []string {
return s.structMapKeys(prod)
}
-func mapKeyFromParam(param *spec.Parameter) string {
- return fmt.Sprintf("%s#%s", param.In, fieldNameFromParam(param))
-}
-
-func fieldNameFromParam(param *spec.Parameter) string {
- // TODO: this should be x-go-name
- if nm, ok := param.Extensions.GetString("go-name"); ok {
- return nm
- }
- mangler := mangling.NewNameMangler()
-
- return mangler.ToGoName(param.Name)
-}
-
// ErrorOnParamFunc is a callback function to be invoked
// whenever an error is encountered while resolving references
// on parameters.
@@ -651,6 +645,19 @@ func (s *Spec) AllEnums() map[string][]any {
return cloneEnumMap(s.enums.allEnums)
}
+func (s *Spec) mapKeyFromParam(param *spec.Parameter) string {
+ return fmt.Sprintf("%s#%s", param.In, s.fieldNameFromParam(param))
+}
+
+func (s *Spec) fieldNameFromParam(param *spec.Parameter) string {
+ // TODO: this should be x-go-name
+ if nm, ok := param.Extensions.GetString("go-name"); ok {
+ return nm
+ }
+
+ return s.mangler.ToGoName(param.Name)
+}
+
func (s *Spec) structMapKeys(mp map[string]struct{}) []string {
if len(mp) == 0 {
return nil
@@ -668,7 +675,7 @@ func (s *Spec) paramsAsMap(parameters []spec.Parameter, res map[string]spec.Para
for _, param := range parameters {
pr := param
if pr.Ref.String() == "" {
- res[mapKeyFromParam(&pr)] = pr
+ res[s.mapKeyFromParam(&pr)] = pr
continue
}
@@ -699,7 +706,7 @@ func (s *Spec) paramsAsMap(parameters []spec.Parameter, res map[string]spec.Para
}
pr = objAsParam
- res[mapKeyFromParam(&pr)] = pr
+ res[s.mapKeyFromParam(&pr)] = pr
}
}
diff --git a/vendor/github.com/go-openapi/analysis/flatten.go b/vendor/github.com/go-openapi/analysis/flatten.go
index d7ee0064b6f..1e5016664dc 100644
--- a/vendor/github.com/go-openapi/analysis/flatten.go
+++ b/vendor/github.com/go-openapi/analysis/flatten.go
@@ -554,6 +554,7 @@ func updateRefParents(allRefs map[string]spec.Ref, r *newRef) {
}
}
+//nolint:gocognit,gocyclo,cyclop // legacy from a lot of design choices that led to concentrate the complexity just here.
func stripOAIGenForRef(opts *FlattenOpts, k string, r *newRef) (bool, error) {
replacedWithComplex := false
diff --git a/vendor/github.com/go-openapi/analysis/flatten_name.go b/vendor/github.com/go-openapi/analysis/flatten_name.go
index 922cae55c5e..9d732171840 100644
--- a/vendor/github.com/go-openapi/analysis/flatten_name.go
+++ b/vendor/github.com/go-openapi/analysis/flatten_name.go
@@ -273,9 +273,9 @@ func mangler(o *FlattenOpts) func(string) string {
if o.KeepNames {
return func(in string) string { return in }
}
- mangler := mangling.NewNameMangler()
+ m := mangling.NewNameMangler(o.ManglerOpts...)
- return mangler.ToJSONName
+ return m.ToJSONName
}
func nameFromRef(ref spec.Ref, o *FlattenOpts) string {
diff --git a/vendor/github.com/go-openapi/analysis/flatten_options.go b/vendor/github.com/go-openapi/analysis/flatten_options.go
index 23a57ea1aca..0984941fdea 100644
--- a/vendor/github.com/go-openapi/analysis/flatten_options.go
+++ b/vendor/github.com/go-openapi/analysis/flatten_options.go
@@ -7,6 +7,7 @@ import (
"log"
"github.com/go-openapi/spec"
+ "github.com/go-openapi/swag/mangling"
)
// FlattenOpts configuration for flattening a swagger specification.
@@ -24,12 +25,13 @@ type FlattenOpts struct {
BasePath string // The location of the root document for this spec to resolve relative $ref
// Flattening options
- Expand bool // When true, skip flattening the spec and expand it instead (if Minimal is false)
- Minimal bool // When true, do not decompose complex structures such as allOf
- Verbose bool // enable some reporting on possible name conflicts detected
- RemoveUnused bool // When true, remove unused parameters, responses and definitions after expansion/flattening
- ContinueOnError bool // Continue when spec expansion issues are found
- KeepNames bool // Do not attempt to jsonify names from references when flattening
+ Expand bool // When true, skip flattening the spec and expand it instead (if Minimal is false)
+ Minimal bool // When true, do not decompose complex structures such as allOf
+ Verbose bool // enable some reporting on possible name conflicts detected
+ RemoveUnused bool // When true, remove unused parameters, responses and definitions after expansion/flattening
+ ContinueOnError bool // Continue when spec expansion issues are found
+ KeepNames bool // Do not attempt to jsonify names from references when flattening
+ ManglerOpts []mangling.Option // Options for the name mangler used to jsonify names
/* Extra keys */
_ struct{} // require keys
diff --git a/vendor/github.com/go-openapi/analysis/go.work.sum b/vendor/github.com/go-openapi/analysis/go.work.sum
deleted file mode 100644
index 899a68976e7..00000000000
--- a/vendor/github.com/go-openapi/analysis/go.work.sum
+++ /dev/null
@@ -1,47 +0,0 @@
-github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
-github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
-github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
-github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
-github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
-github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30 h1:BHT1/DKsYDGkUgQ2jmMaozVcdk+sVfz0+1ZJq4zkWgw=
-github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
-github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
-github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
-github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
-github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
-github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss=
-go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
-golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
-golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
-golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
-golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
-golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
-golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
-golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
-golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
-golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
-golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
-golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
-golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
-golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
-golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 h1:bTLqdHv7xrGlFbvf5/TXNxy/iUwwdkjhqQTJDjW7aj0=
-golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4/go.mod h1:g5NllXBEermZrmR51cJDQxmJUHUOfRAaNyWBM+R+548=
-golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
-golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
-golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
-golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
-golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
-golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
-golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
-golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
-golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
-golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
diff --git a/vendor/github.com/go-openapi/analysis/mixin.go b/vendor/github.com/go-openapi/analysis/mixin.go
index a7a9306cb37..ab15644f680 100644
--- a/vendor/github.com/go-openapi/analysis/mixin.go
+++ b/vendor/github.com/go-openapi/analysis/mixin.go
@@ -11,37 +11,66 @@ import (
"github.com/go-openapi/spec"
)
-// Mixin modifies the primary swagger spec by adding the paths and
-// definitions from the mixin specs. Top level parameters and
-// responses from the mixins are also carried over. Operation id
-// collisions are avoided by appending "Mixin" but only if
-// needed.
+// Mixin merges one or more Swagger 2.0 documents into a primary document.
//
-// The following parts of primary are subject to merge, filling empty details
+// # Argument order and precedence
//
-// - Info
+// The first argument is the primary spec, which Mixin modifies in place.
+// Subsequent arguments are mixins, listed in decreasing order of priority.
+// On any collision, the primary always wins; among mixins, the earliest one
+// wins.
+//
+// Example: given a primary spec with host "a.example.com" and a mixin with
+// host "b.example.com", the merged result keeps "a.example.com" (primary
+// wins, the mixin value is dropped). Given a primary without a host and a
+// mixin with host "b.example.com", the merged result uses "b.example.com"
+// (the mixin fills in the empty field on the primary).
+//
+// # What gets merged
+//
+// Top-level scalar fields on the primary are filled from the first mixin
+// that provides them, but only if the primary's value is the zero value:
+//
+// - Info (including the nested Contact and License)
// - BasePath
// - Host
// - ExternalDocs
//
-// Consider calling [FixEmptyResponseDescriptions]() on the modified primary
-// if you read them from storage and they are valid to start with.
+// Map and slice fields are merged entry by entry. This covers:
+//
+// - paths, definitions, parameters, responses
+// - securityDefinitions, security, tags
+// - top-level and Info extensions
+//
+// Duplicate keys (or equal security requirements, or equal tag names) are
+// skipped with a warning; warnings are returned as a slice and intended to
+// be inspected by the caller (e.g. compared to an expected collision count
+// in build scripts).
+//
+// Schemes, consumes and produces are merged as the union of distinct
+// values. Duplicates there are silently dropped, no warning is emitted.
+//
+// Operation id collisions are auto-resolved by appending "Mixin" to the
+// mixin operation id (N is the mixin index), so the merged spec keeps
+// unique operation ids.
+//
+// # Notes and limitations
//
-// Entries in "paths", "definitions", "parameters" and "responses" are
-// added to the primary in the order of the given mixins. If the entry
-// already exists in primary it is skipped with a warning message.
+// Consider calling [FixEmptyResponseDescriptions] on the modified primary
+// if you read responses from storage and they are valid to start with.
//
-// The count of skipped entries (from collisions) is returned so any
-// deviation from the number expected can flag a warning in your build
-// scripts. Carefully review the collisions before accepting them;
-// consider renaming things if possible.
+// No key normalization takes place. Ensure paths, type names, etc. are
+// canonical if your downstream tools rely on normalized forms.
//
-// No key normalization takes place (paths, type defs,
-// etc). Ensure they are canonical if your downstream tools do
-// key normalization of any form.
+// YAML anchors (& / *) are resolved by the YAML parser before Mixin sees
+// the document, so they are not preserved in the merged output, and they
+// cannot be shared across input files. Use $ref for cross-file reuse. See
+// https://goswagger.io/go-swagger/faq/faq_swagger/#does-swagger-mixin-preserve-yaml-anchors
//
-// Merging schemes ([http], https), and consumers/producers do not account for
-// collisions.
+// The order of paths and definitions in the merged output is alphabetical:
+// the underlying spec model stores them as Go maps, which serialize with
+// sorted keys. Source-file order is not preserved. See
+// https://goswagger.io/go-swagger/faq/faq_swagger/#can-i-control-the-path-or-operation-order-in-swagger-mixin-output
func Mixin(primary *spec.Swagger, mixins ...*spec.Swagger) []string {
skipped := make([]string, 0, len(mixins))
opIDs := getOpIDs(primary)
diff --git a/vendor/github.com/go-openapi/analysis/options.go b/vendor/github.com/go-openapi/analysis/options.go
new file mode 100644
index 00000000000..b46cd2ca693
--- /dev/null
+++ b/vendor/github.com/go-openapi/analysis/options.go
@@ -0,0 +1,21 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package analysis
+
+import "github.com/go-openapi/swag/mangling"
+
+// Option configures the behavior of a new [Spec] analyzer.
+type Option func(*analyzerOptions)
+
+type analyzerOptions struct {
+ manglerOpts []mangling.Option
+}
+
+// WithManglerOptions sets the name mangler options used when building
+// Go identifiers from specification names (e.g. parameter names).
+func WithManglerOptions(opts ...mangling.Option) Option {
+ return func(o *analyzerOptions) {
+ o.manglerOpts = append(o.manglerOpts, opts...)
+ }
+}
diff --git a/vendor/github.com/go-openapi/errors/.gitignore b/vendor/github.com/go-openapi/errors/.gitignore
index 9364443a6f0..96c4149a0b1 100644
--- a/vendor/github.com/go-openapi/errors/.gitignore
+++ b/vendor/github.com/go-openapi/errors/.gitignore
@@ -3,5 +3,4 @@
.idea
.env
.mcp.json
-.claude/
settings.local.json
diff --git a/vendor/github.com/go-openapi/errors/CONTRIBUTORS.md b/vendor/github.com/go-openapi/errors/CONTRIBUTORS.md
index d49e377a135..68b716b5688 100644
--- a/vendor/github.com/go-openapi/errors/CONTRIBUTORS.md
+++ b/vendor/github.com/go-openapi/errors/CONTRIBUTORS.md
@@ -4,12 +4,12 @@
| Total Contributors | Total Contributions |
| --- | --- |
-| 13 | 110 |
+| 13 | 115 |
| Username | All Time Contribution Count | All Commits |
| --- | --- | --- |
| @casualjim | 58 | |
-| @fredbi | 36 | |
+| @fredbi | 41 | |
| @youyuanwu | 5 | |
| @alexandear | 2 | |
| @fiorix | 1 | |
@@ -22,4 +22,4 @@
| @aokumasan | 1 | |
| @ujjwalsh | 1 | |
- _this file was generated by the [Contributors GitHub Action](https://github.com/github/contributors)_
+ _this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_
diff --git a/vendor/github.com/go-openapi/errors/README.md b/vendor/github.com/go-openapi/errors/README.md
index d9f4a3f1514..35e6b69ba82 100644
--- a/vendor/github.com/go-openapi/errors/README.md
+++ b/vendor/github.com/go-openapi/errors/README.md
@@ -106,7 +106,7 @@ Maintainers can cut a new release by either:
[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM
[slack-url]: https://goswagger.slack.com/archives/C04R30YMU
[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue
-[discord-url]: https://discord.gg/twZ9BwT3
+[discord-url]: https://discord.gg/FfnFYaC3k5
[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
diff --git a/vendor/github.com/go-openapi/jsonpointer/.cliff.toml b/vendor/github.com/go-openapi/jsonpointer/.cliff.toml
deleted file mode 100644
index 702629f5dc3..00000000000
--- a/vendor/github.com/go-openapi/jsonpointer/.cliff.toml
+++ /dev/null
@@ -1,181 +0,0 @@
-# git-cliff ~ configuration file
-# https://git-cliff.org/docs/configuration
-
-[changelog]
-header = """
-"""
-
-footer = """
-
------
-
-**[{{ remote.github.repo }}]({{ self::remote_url() }}) license terms**
-
-[![License][license-badge]][license-url]
-
-[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
-[license-url]: {{ self::remote_url() }}/?tab=Apache-2.0-1-ov-file#readme
-
-{%- macro remote_url() -%}
- https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
-{%- endmacro -%}
-"""
-
-body = """
-{%- if version %}
-## [{{ version | trim_start_matches(pat="v") }}]({{ self::remote_url() }}/tree/{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
-{%- else %}
-## [unreleased]
-{%- endif %}
-{%- if message %}
- {%- raw %}\n{% endraw %}
-{{ message }}
- {%- raw %}\n{% endraw %}
-{%- endif %}
-{%- if version %}
- {%- if previous.version %}
-
-**Full Changelog**: <{{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }}>
- {%- endif %}
-{%- else %}
- {%- raw %}\n{% endraw %}
-{%- endif %}
-
-{%- if statistics %}{% if statistics.commit_count %}
- {%- raw %}\n{% endraw %}
-{{ statistics.commit_count }} commits in this release.
- {%- raw %}\n{% endraw %}
-{%- endif %}{% endif %}
------
-
-{%- for group, commits in commits | group_by(attribute="group") %}
- {%- raw %}\n{% endraw %}
-### {{ group | upper_first }}
- {%- raw %}\n{% endraw %}
- {%- for commit in commits %}
- {%- if commit.remote.pr_title %}
- {%- set commit_message = commit.remote.pr_title %}
- {%- else %}
- {%- set commit_message = commit.message %}
- {%- endif %}
-* {{ commit_message | split(pat="\n") | first | trim }}
- {%- if commit.remote.username %}
-{%- raw %} {% endraw %}by [@{{ commit.remote.username }}](https://github.com/{{ commit.remote.username }})
- {%- endif %}
- {%- if commit.remote.pr_number %}
-{%- raw %} {% endraw %}in [#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }})
- {%- endif %}
-{%- raw %} {% endraw %}[...]({{ self::remote_url() }}/commit/{{ commit.id }})
- {%- endfor %}
-{%- endfor %}
-
-{%- if github %}
-{%- raw %}\n{% endraw -%}
- {%- set all_contributors = github.contributors | length %}
- {%- if github.contributors | filter(attribute="username", value="dependabot[bot]") | length < all_contributors %}
------
-
-### People who contributed to this release
- {% endif %}
- {%- for contributor in github.contributors | filter(attribute="username") | sort(attribute="username") %}
- {%- if contributor.username != "dependabot[bot]" and contributor.username != "github-actions[bot]" %}
-* [@{{ contributor.username }}](https://github.com/{{ contributor.username }})
- {%- endif %}
- {%- endfor %}
-
- {% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
------
- {%- raw %}\n{% endraw %}
-
-### New Contributors
- {%- endif %}
-
- {%- for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
- {%- if contributor.username != "dependabot[bot]" and contributor.username != "github-actions[bot]" %}
-* @{{ contributor.username }} made their first contribution
- {%- if contributor.pr_number %}
- in [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
- {%- endif %}
- {%- endif %}
- {%- endfor %}
-{%- endif %}
-
-{%- raw %}\n{% endraw %}
-
-{%- macro remote_url() -%}
- https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
-{%- endmacro -%}
-"""
-# Remove leading and trailing whitespaces from the changelog's body.
-trim = true
-# Render body even when there are no releases to process.
-render_always = true
-# An array of regex based postprocessors to modify the changelog.
-postprocessors = [
- # Replace the placeholder with a URL.
- #{ pattern = '', replace = "https://github.com/orhun/git-cliff" },
-]
-# output file path
-# output = "test.md"
-
-[git]
-# Parse commits according to the conventional commits specification.
-# See https://www.conventionalcommits.org
-conventional_commits = false
-# Exclude commits that do not match the conventional commits specification.
-filter_unconventional = false
-# Require all commits to be conventional.
-# Takes precedence over filter_unconventional.
-require_conventional = false
-# Split commits on newlines, treating each line as an individual commit.
-split_commits = false
-# An array of regex based parsers to modify commit messages prior to further processing.
-commit_preprocessors = [
- # Replace issue numbers with link templates to be updated in `changelog.postprocessors`.
- #{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))"},
- # Check spelling of the commit message using https://github.com/crate-ci/typos.
- # If the spelling is incorrect, it will be fixed automatically.
- #{ pattern = '.*', replace_command = 'typos --write-changes -' }
-]
-# Prevent commits that are breaking from being excluded by commit parsers.
-protect_breaking_commits = false
-# An array of regex based parsers for extracting data from the commit message.
-# Assigns commits to groups.
-# Optionally sets the commit's scope and can decide to exclude commits from further processing.
-commit_parsers = [
- { message = "^[Cc]hore\\([Rr]elease\\): prepare for", skip = true },
- { message = "(^[Mm]erge)|([Mm]erge conflict)", skip = true },
- { field = "author.name", pattern = "dependabot*", group = "Updates" },
- { message = "([Ss]ecurity)|([Vv]uln)", group = "Security" },
- { body = "(.*[Ss]ecurity)|([Vv]uln)", group = "Security" },
- { message = "([Cc]hore\\(lint\\))|(style)|(lint)|(codeql)|(golangci)", group = "Code quality" },
- { message = "(^[Dd]oc)|((?i)readme)|(badge)|(typo)|(documentation)", group = "Documentation" },
- { message = "(^[Ff]eat)|(^[Ee]nhancement)", group = "Implemented enhancements" },
- { message = "(^ci)|(\\(ci\\))|(fixup\\s+ci)|(fix\\s+ci)|(license)|(example)", group = "Miscellaneous tasks" },
- { message = "^test", group = "Testing" },
- { message = "(^fix)|(panic)", group = "Fixed bugs" },
- { message = "(^refact)|(rework)", group = "Refactor" },
- { message = "(^[Pp]erf)|(performance)", group = "Performance" },
- { message = "(^[Cc]hore)", group = "Miscellaneous tasks" },
- { message = "^[Rr]evert", group = "Reverted changes" },
- { message = "(upgrade.*?go)|(go\\s+version)", group = "Updates" },
- { message = ".*", group = "Other" },
-]
-# Exclude commits that are not matched by any commit parser.
-filter_commits = false
-# An array of link parsers for extracting external references, and turning them into URLs, using regex.
-link_parsers = []
-# Include only the tags that belong to the current branch.
-use_branch_tags = false
-# Order releases topologically instead of chronologically.
-topo_order = false
-# Order releases topologically instead of chronologically.
-topo_order_commits = true
-# Order of commits in each group/release within the changelog.
-# Allowed values: newest, oldest
-sort_commits = "newest"
-# Process submodules commits
-recurse_submodules = false
-
-#[remote.github]
-#owner = "go-openapi"
diff --git a/vendor/github.com/go-openapi/jsonpointer/.gitignore b/vendor/github.com/go-openapi/jsonpointer/.gitignore
index 885dc27ab0b..d8f4186fe59 100644
--- a/vendor/github.com/go-openapi/jsonpointer/.gitignore
+++ b/vendor/github.com/go-openapi/jsonpointer/.gitignore
@@ -3,4 +3,3 @@
.idea
.env
.mcp.json
-.claude/
diff --git a/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md b/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md
index 2ebebedc150..9990f4a3542 100644
--- a/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md
+++ b/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md
@@ -4,11 +4,11 @@
| Total Contributors | Total Contributions |
| --- | --- |
-| 12 | 101 |
+| 13 | 111 |
| Username | All Time Contribution Count | All Commits |
| --- | --- | --- |
-| @fredbi | 54 | |
+| @fredbi | 63 | |
| @casualjim | 33 | |
| @magodo | 3 | |
| @youyuanwu | 3 | |
@@ -18,7 +18,8 @@
| @ianlancetaylor | 1 | |
| @mfleader | 1 | |
| @Neo2308 | 1 | |
+| @alexandear | 1 | |
| @olivierlemasle | 1 | |
| @testwill | 1 | |
- _this file was generated by the [Contributors GitHub Action](https://github.com/github/contributors)_
+ _this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_
diff --git a/vendor/github.com/go-openapi/jsonpointer/NOTICE b/vendor/github.com/go-openapi/jsonpointer/NOTICE
index f3b51939a95..201908d2f08 100644
--- a/vendor/github.com/go-openapi/jsonpointer/NOTICE
+++ b/vendor/github.com/go-openapi/jsonpointer/NOTICE
@@ -18,7 +18,7 @@ It ships with copies of other software which license terms are recalled below.
The original software was authored on 25-02-2013 by sigu-399 (https://github.com/sigu-399, sigu.399@gmail.com).
-github.com/sigh-399/jsonpointer
+github.com/sigu-399/jsonpointer
===========================
// SPDX-FileCopyrightText: Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
diff --git a/vendor/github.com/go-openapi/jsonpointer/README.md b/vendor/github.com/go-openapi/jsonpointer/README.md
index c52803e2e8f..24fbe1bf680 100644
--- a/vendor/github.com/go-openapi/jsonpointer/README.md
+++ b/vendor/github.com/go-openapi/jsonpointer/README.md
@@ -16,17 +16,25 @@ An implementation of JSON Pointer for golang, which supports go `struct`.
## Announcements
-* **2025-12-19** : new community chat on discord
- * a new discord community channel is available to be notified of changes and support users
- * our venerable Slack channel remains open, and will be eventually discontinued on **2026-03-31**
-
-You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url]
-
-Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url]
+* **2026-04-15** : added support for trailing "-" for arrays (v0.23.0)
+ * this brings full support of [RFC6901][RFC6901]
+ * this is supported for types relying on the reflection-based implemented
+ * API semantics remain essentially unaltered. Exception: `Pointer.Set(document any,value any) (document any, err error)`
+ can only perform a best-effort to mutate the input document in place. In the case of adding elements to an array with a
+ trailing "-", either pass a mutable array (`*[]T`) as the input document, or use the returned updated document instead.
+ * types that implement the `JSONSetable` interface may not implement the mutation implied by the trailing "-"
+
+* **2026-04-15** : added support for optional alternate JSON name providers
+ * for struct support the defaults might not suit all situations: there are known limitations
+ when it comes to handle untagged fields or embedded types.
+ * the default name provider in use is not fully aligned with go JSON stdlib
+ * exposed an option (or global setting) to change the provider that resolves a struct into json keys
+ * the default behavior is not altered
+ * a new alternate name provider is added (imported from `go-openapi/swag/jsonname`), aligned with JSON stdlib behavior
## Status
-API is stable.
+API is stable and feature-complete.
## Import this library in your project
@@ -88,7 +96,7 @@ See
-also known as [RFC6901](https://www.rfc-editor.org/rfc/rfc6901)
+also known as [RFC6901][RFC6901].
## Licensing
@@ -99,19 +107,19 @@ on top of which it has been built.
## Limitations
-The 4.Evaluation part of the previous reference, starting with 'If the currently referenced value is a JSON array,
-the reference token MUST contain either...' is not implemented.
-
-That is because our implementation of the JSON pointer only supports explicit references to array elements:
-the provision in the spec to resolve non-existent members as "the last element in the array",
-using the special trailing character "-" is not implemented.
+* [RFC6901][RFC6901] is now fully supported, including trailing "-" semantics for arrays (for `Set` operations).
+* Default behavior: JSON name detection in go `struct`s
+ - Unlike go standard marshaling, untagged fields do not default to the go field name and are ignored.
+ - anonymous fields are not traversed if untagged
+ - the above limitations may be overcome by calling `UseGoNameProvider()` at initialization time.
+ - alternatively, users may inject the desired custom behavior for naming fields as an option.
## Other documentation
* [All-time contributors](./CONTRIBUTORS.md)
-* [Contributing guidelines](.github/CONTRIBUTING.md)
-* [Maintainers documentation](docs/MAINTAINERS.md)
-* [Code style](docs/STYLE.md)
+* [Contributing guidelines][contributing-doc-site]
+* [Maintainers documentation][maintainers-doc-site]
+* [Code style][style-doc-site]
## Cutting a new release
@@ -142,11 +150,8 @@ Maintainers can cut a new release by either:
[godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/jsonpointer
[godoc-url]: http://pkg.go.dev/github.com/go-openapi/jsonpointer
-[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png
-[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM
-[slack-url]: https://goswagger.slack.com/archives/C04R30YMU
[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue
-[discord-url]: https://discord.gg/twZ9BwT3
+[discord-url]: https://discord.gg/FfnFYaC3k5
[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
@@ -156,3 +161,8 @@ Maintainers can cut a new release by either:
[goversion-url]: https://github.com/go-openapi/jsonpointer/blob/master/go.mod
[top-badge]: https://img.shields.io/github/languages/top/go-openapi/jsonpointer
[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/jsonpointer/latest
+[RFC6901]: https://www.rfc-editor.org/rfc/rfc6901
+
+[contributing-doc-site]: https://go-openapi.github.io/doc-site/contributing/contributing/index.html
+[maintainers-doc-site]: https://go-openapi.github.io/doc-site/maintainers/index.html
+[style-doc-site]: https://go-openapi.github.io/doc-site/contributing/style/index.html
diff --git a/vendor/github.com/go-openapi/jsonpointer/errors.go b/vendor/github.com/go-openapi/jsonpointer/errors.go
index 8c50dde8bcf..8813474d447 100644
--- a/vendor/github.com/go-openapi/jsonpointer/errors.go
+++ b/vendor/github.com/go-openapi/jsonpointer/errors.go
@@ -16,12 +16,24 @@ const (
ErrPointer pointerError = "JSON pointer error"
// ErrInvalidStart states that a JSON pointer must start with a separator ("/").
- ErrInvalidStart pointerError = `JSON pointer must be empty or start with a "` + pointerSeparator
+ ErrInvalidStart pointerError = `JSON pointer must be empty or start with a "` + pointerSeparator + `"`
// ErrUnsupportedValueType indicates that a value of the wrong type is being set.
ErrUnsupportedValueType pointerError = "only structs, pointers, maps and slices are supported for setting values"
+
+ // ErrDashToken indicates use of the RFC 6901 "-" reference token
+ // in a context where it cannot be resolved.
+ //
+ // Per RFC 6901 §4 the "-" token refers to the (nonexistent) element
+ // after the last array element. It may only be used as the terminal
+ // token of a [Pointer.Set] against a slice, where it means "append".
+ // Any other use (get, offset, intermediate traversal, non-slice target)
+ // is an error condition that wraps this sentinel.
+ ErrDashToken pointerError = `the "-" array token cannot be resolved here` //nolint:gosec // G101 false positive: this is a JSON Pointer reference token, not a credential.
)
+const dashToken = "-"
+
func errNoKey(key string) error {
return fmt.Errorf("object has no key %q: %w", key, ErrPointer)
}
@@ -33,3 +45,15 @@ func errOutOfBounds(length, idx int) error {
func errInvalidReference(token string) error {
return fmt.Errorf("invalid token reference %q: %w", token, ErrPointer)
}
+
+func errDashOnGet() error {
+ return fmt.Errorf("cannot resolve %q token on get: %w: %w", dashToken, ErrDashToken, ErrPointer)
+}
+
+func errDashIntermediate() error {
+ return fmt.Errorf("the %q token may only appear as the terminal token of a pointer: %w: %w", dashToken, ErrDashToken, ErrPointer)
+}
+
+func errDashOnOffset() error {
+ return fmt.Errorf("cannot compute offset for %q token (nonexistent element): %w: %w", dashToken, ErrDashToken, ErrPointer)
+}
diff --git a/vendor/github.com/go-openapi/jsonpointer/ifaces.go b/vendor/github.com/go-openapi/jsonpointer/ifaces.go
new file mode 100644
index 00000000000..1e56ac0442d
--- /dev/null
+++ b/vendor/github.com/go-openapi/jsonpointer/ifaces.go
@@ -0,0 +1,47 @@
+// SPDX-FileCopyrightText: Copyright (c) 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package jsonpointer
+
+import "reflect"
+
+// JSONPointable is an interface for structs to implement,
+// when they need to customize the json pointer process or want to avoid the use of reflection.
+type JSONPointable interface {
+ // JSONLookup returns a value pointed at this (unescaped) key.
+ JSONLookup(key string) (any, error)
+}
+
+// JSONSetable is an interface for structs to implement,
+// when they need to customize the json pointer process or want to avoid the use of reflection.
+//
+// # Handling of the RFC 6901 "-" token
+//
+// When a type implementing JSONSetable is the terminal parent of a [Pointer.Set]
+// call, the library passes the raw reference token to JSONSet without
+// interpretation. In particular, the RFC 6901 "-" token (which conventionally
+// means "append" for arrays, per RFC 6902) is forwarded verbatim as the key
+// argument. Implementations that model an array-like container are expected
+// to give "-" the append semantics; implementations that do not should return
+// an error wrapping [ErrDashToken] (or [ErrPointer]) for clarity.
+//
+// Implementations are responsible for any in-place mutation: the library does
+// not attempt to rebind the result of JSONSet into a parent container.
+type JSONSetable interface {
+ // JSONSet sets the value pointed at the (unescaped) key.
+ //
+ // The key may be the RFC 6901 "-" token when the pointer targets a
+ // slice-like member; see the interface documentation for details.
+ JSONSet(key string, value any) error
+}
+
+// NameProvider knows how to resolve go struct fields into json names.
+//
+// The default provider is brought by [github.com/go-openapi/swag/jsonname.DefaultJSONNameProvider].
+type NameProvider interface {
+ // GetGoName gets the go name for a json property name
+ GetGoName(subject any, name string) (string, bool)
+
+ // GetGoNameForType gets the go name for a given type for a json property name
+ GetGoNameForType(tpe reflect.Type, name string) (string, bool)
+}
diff --git a/vendor/github.com/go-openapi/jsonpointer/options.go b/vendor/github.com/go-openapi/jsonpointer/options.go
new file mode 100644
index 00000000000..d52caab2224
--- /dev/null
+++ b/vendor/github.com/go-openapi/jsonpointer/options.go
@@ -0,0 +1,86 @@
+// SPDX-FileCopyrightText: Copyright (c) 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package jsonpointer
+
+import (
+ "sync"
+
+ "github.com/go-openapi/swag/jsonname"
+)
+
+// Option to tune the behavior of a JSON [Pointer].
+type Option func(*options)
+
+var (
+ //nolint:gochecknoglobals // package level defaults are provided as a convenient, backward-compatible way to adopt options.
+ defaultOptions = options{
+ provider: jsonname.DefaultJSONNameProvider,
+ }
+ //nolint:gochecknoglobals // guards defaultOptions against concurrent SetDefaultNameProvider / read races (testing)
+ defaultOptionsMu sync.RWMutex
+)
+
+// SetDefaultNameProvider sets the [NameProvider] as a package-level default.
+//
+// By default, the default provider is [jsonname.DefaultJSONNameProvider].
+//
+// It is safe to call concurrently with [Pointer.Get], [Pointer.Set],
+// [GetForToken] and [SetForToken]. The typical usage is to call it once
+// at initialization time.
+//
+// A nil provider is ignored.
+func SetDefaultNameProvider(provider NameProvider) {
+ if provider == nil {
+ return
+ }
+
+ defaultOptionsMu.Lock()
+ defer defaultOptionsMu.Unlock()
+
+ defaultOptions.provider = provider
+}
+
+// UseGoNameProvider sets the [NameProvider] as a package-level default
+// to the alternative provider [jsonname.GoNameProvider], that covers a few areas
+// not supported by the default name provider.
+//
+// This implementation supports untagged exported fields and embedded types in go struct.
+// It follows strictly the behavior of the JSON standard library regarding field naming conventions.
+//
+// It is safe to call concurrently with [Pointer.Get], [Pointer.Set],
+// [GetForToken] and [SetForToken]. The typical usage is to call it once
+// at initialization time.
+func UseGoNameProvider() {
+ SetDefaultNameProvider(jsonname.NewGoNameProvider())
+}
+
+// DefaultNameProvider returns the current package-level [NameProvider].
+func DefaultNameProvider() NameProvider { //nolint:ireturn // returning the interface is the point — callers pick their own implementation.
+ defaultOptionsMu.RLock()
+ defer defaultOptionsMu.RUnlock()
+
+ return defaultOptions.provider
+}
+
+// WithNameProvider injects a custom [NameProvider] to resolve json names from go struct types.
+func WithNameProvider(provider NameProvider) Option {
+ return func(o *options) {
+ o.provider = provider
+ }
+}
+
+type options struct {
+ provider NameProvider
+}
+
+func optionsWithDefaults(opts []Option) options {
+ var o options
+ o.provider = DefaultNameProvider()
+
+ for _, apply := range opts {
+ apply(&o)
+ }
+
+ return o
+}
diff --git a/vendor/github.com/go-openapi/jsonpointer/pointer.go b/vendor/github.com/go-openapi/jsonpointer/pointer.go
index 7df49af3b96..2369c1827e8 100644
--- a/vendor/github.com/go-openapi/jsonpointer/pointer.go
+++ b/vendor/github.com/go-openapi/jsonpointer/pointer.go
@@ -11,8 +11,6 @@ import (
"reflect"
"strconv"
"strings"
-
- "github.com/go-openapi/swag/jsonname"
)
const (
@@ -20,20 +18,6 @@ const (
pointerSeparator = `/`
)
-// JSONPointable is an interface for structs to implement,
-// when they need to customize the json pointer process or want to avoid the use of reflection.
-type JSONPointable interface {
- // JSONLookup returns a value pointed at this (unescaped) key.
- JSONLookup(key string) (any, error)
-}
-
-// JSONSetable is an interface for structs to implement,
-// when they need to customize the json pointer process or want to avoid the use of reflection.
-type JSONSetable interface {
- // JSONSet sets the value pointed at the (unescaped) key.
- JSONSet(key string, value any) error
-}
-
// Pointer is a representation of a json pointer.
//
// Use [Pointer.Get] to retrieve a value or [Pointer.Set] to set a value.
@@ -41,7 +25,7 @@ type JSONSetable interface {
// It works with any go type interpreted as a JSON document, which means:
//
// - if a type implements [JSONPointable], its [JSONPointable.JSONLookup] method is used to resolve [Pointer.Get]
-// - if a type implements [JSONSetable], its [JSONPointable.JSONSet] method is used to resolve [Pointer.Set]
+// - if a type implements [JSONSetable], its [JSONSetable.JSONSet] method is used to resolve [Pointer.Set]
// - a go map[K]V is interpreted as an object, with type K assignable to a string
// - a go slice []T is interpreted as an array
// - a go struct is interpreted as an object, with exported fields interpreted as keys
@@ -71,16 +55,35 @@ func New(jsonPointerString string) (Pointer, error) {
// Get uses the pointer to retrieve a value from a JSON document.
//
// It returns the value with its type as a [reflect.Kind] or an error.
-func (p *Pointer) Get(document any) (any, reflect.Kind, error) {
- return p.get(document, jsonname.DefaultJSONNameProvider)
+func (p *Pointer) Get(document any, opts ...Option) (any, reflect.Kind, error) {
+ o := optionsWithDefaults(opts)
+
+ return p.get(document, o.provider)
}
// Set uses the pointer to set a value from a data type
// that represent a JSON document.
//
-// It returns the updated document.
-func (p *Pointer) Set(document any, value any) (any, error) {
- return document, p.set(document, value, jsonname.DefaultJSONNameProvider)
+// # Mutation contract
+//
+// Set mutates the provided document in place whenever Go's type system allows
+// it: when document is a map, a pointer, or when the targeted value is reached
+// through an addressable ancestor (e.g. a struct field traversed via a pointer,
+// a slice element). Callers that rely on this in-place behavior may continue
+// to ignore the returned document.
+//
+// The returned document is only load-bearing when Set cannot mutate in place.
+// This happens in one specific case: appending to a top-level slice passed by
+// value (e.g. document of type []T rather than *[]T) via the RFC 6901 "-"
+// terminal token. reflect.Append produces a new slice header that the library
+// cannot rebind into the caller's variable; the updated document is returned
+// instead. Pass *[]T if you want in-place rebind for that case as well.
+//
+// See [ErrDashToken] for the semantics of the "-" token.
+func (p *Pointer) Set(document any, value any, opts ...Option) (any, error) {
+ o := optionsWithDefaults(opts)
+
+ return p.set(document, value, o.provider)
}
// DecodedTokens returns the decoded (unescaped) tokens of this JSON pointer.
@@ -109,6 +112,46 @@ func (p *Pointer) String() string {
return pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
}
+// Offset returns the byte offset, in the raw JSON text of document, of the
+// location referenced by this pointer's terminal token.
+//
+// Unlike [Pointer.Get] and [Pointer.Set], which operate on a decoded Go value,
+// Offset operates directly on the textual JSON source. It drives an
+// [encoding/json.Decoder] over the string and stops at the terminal token,
+// returning the position at which the decoder was about to read that token.
+//
+// It is primarily intended for tooling that needs to map a pointer back to a
+// region of the original source: reporting line/column for validation or
+// parse diagnostics, extracting a sub-document by slicing the raw bytes, or
+// highlighting the referenced span in an editor.
+//
+// # Offset semantics
+//
+// The meaning of the returned offset depends on whether the terminal token
+// addresses an object property or an array element:
+//
+// - Object property: the offset points to the first byte of the key (its
+// opening quote character), not to the associated value. For example,
+// pointer "/foo/bar" against {"foo": {"bar": 21}} returns 9, the index of
+// the opening quote of "bar".
+// - Array element: the offset points to the first byte of the value at that
+// index. For example, pointer "/0/1" against [[1,2], [3,4]] returns 4,
+// the index of the digit 2.
+//
+// # Errors
+//
+// Offset returns an error in any of these cases:
+//
+// - document is not syntactically valid JSON;
+// - the structure of document does not match the pointer (e.g. traversing
+// into a scalar, or a token that is neither a valid key nor a valid
+// numeric index);
+// - a referenced key or index does not exist in document;
+// - the pointer's terminal token is the RFC 6901 "-" array token, which
+// designates a nonexistent element and therefore has no offset in the
+// source. The returned error wraps [ErrDashToken].
+//
+// All errors wrap [ErrPointer].
func (p *Pointer) Offset(document string) (int64, error) {
dec := json.NewDecoder(strings.NewReader(document))
var offset int64
@@ -137,7 +180,35 @@ func (p *Pointer) Offset(document string) (int64, error) {
return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer)
}
}
- return offset, nil
+ return skipJSONSeparator(document, offset), nil
+}
+
+// skipJSONSeparator advances offset past trailing JSON whitespace and at most
+// one value separator (comma) in document, so the result points at the first
+// byte of the next JSON token.
+//
+// The streaming decoder's InputOffset sits right after the most recently
+// consumed token, which between values is the comma (or whitespace) — not
+// the following token. Normalizing here keeps Offset's contract uniform:
+// for both object keys and array elements, and regardless of position within
+// the parent container, the returned offset always points at the first byte
+// of the addressed token.
+func skipJSONSeparator(document string, offset int64) int64 {
+ n := int64(len(document))
+ for offset < n && isJSONWhitespace(document[offset]) {
+ offset++
+ }
+ if offset < n && document[offset] == ',' {
+ offset++
+ }
+ for offset < n && isJSONWhitespace(document[offset]) {
+ offset++
+ }
+ return offset
+}
+
+func isJSONWhitespace(c byte) bool {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r'
}
// "Constructor", parses the given string JSON pointer.
@@ -157,9 +228,9 @@ func (p *Pointer) parse(jsonPointerString string) error {
return nil
}
-func (p *Pointer) get(node any, nameProvider *jsonname.NameProvider) (any, reflect.Kind, error) {
+func (p *Pointer) get(node any, nameProvider NameProvider) (any, reflect.Kind, error) {
if nameProvider == nil {
- nameProvider = jsonname.DefaultJSONNameProvider
+ nameProvider = defaultOptions.provider
}
kind := reflect.Invalid
@@ -185,50 +256,130 @@ func (p *Pointer) get(node any, nameProvider *jsonname.NameProvider) (any, refle
return node, kind, nil
}
-func (p *Pointer) set(node, data any, nameProvider *jsonname.NameProvider) error {
+func (p *Pointer) set(node, data any, nameProvider NameProvider) (any, error) {
knd := reflect.ValueOf(node).Kind()
if knd != reflect.Pointer && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
- return errors.Join(
+ return node, errors.Join(
fmt.Errorf("unexpected type: %T", node), //nolint:err113 // err wrapping is carried out by errors.Join, not fmt.Errorf.
ErrUnsupportedValueType,
ErrPointer,
)
}
- l := len(p.referenceTokens)
-
// full document when empty
- if l == 0 {
- return nil
+ if len(p.referenceTokens) == 0 {
+ return node, nil
}
if nameProvider == nil {
- nameProvider = jsonname.DefaultJSONNameProvider
+ nameProvider = defaultOptions.provider
}
- var decodedToken string
- lastIndex := l - 1
+ return p.setAt(node, p.referenceTokens, data, nameProvider)
+}
- if lastIndex > 0 { // skip if we only have one token in pointer
- for _, token := range p.referenceTokens[:lastIndex] {
- decodedToken = Unescape(token)
- next, err := p.resolveNodeForToken(node, decodedToken, nameProvider)
- if err != nil {
- return err
- }
+// setAt recursively walks the token list, setting the data at the terminal
+// token and rebinding any new child reference (e.g. a slice header returned
+// by an "-" append) into its parent on the way back up.
+//
+// Returning the (possibly new) node at each level is what makes append work
+// at any depth without requiring the caller to pass a pointer to the
+// containing slice: the new slice header propagates up and each parent
+// rebinds it via the appropriate kind-specific setter.
+func (p *Pointer) setAt(node any, tokens []string, data any, nameProvider NameProvider) (any, error) {
+ decodedToken := Unescape(tokens[0])
+
+ if len(tokens) == 1 {
+ return setSingleImpl(node, data, decodedToken, nameProvider)
+ }
- node = next
- }
+ child, err := p.resolveNodeForToken(node, decodedToken, nameProvider)
+ if err != nil {
+ return node, err
+ }
+
+ newChild, err := p.setAt(child, tokens[1:], data, nameProvider)
+ if err != nil {
+ return node, err
}
- // last token
- decodedToken = Unescape(p.referenceTokens[lastIndex])
+ return rebindChild(node, decodedToken, newChild, nameProvider)
+}
+
+// rebindChild writes newChild back into node at decodedToken.
+//
+// For cases where the child was already mutated in place (pointer aliasing,
+// addressable slice elements) the rebind is a safe no-op. For cases where
+// the child was returned by value (map entries holding a slice, slices
+// reached through a non-addressable ancestor), the rebind propagates the
+// new value into the parent.
+//
+// Parents implementing [JSONPointable] are left alone: they took ownership
+// of the child via JSONLookup and did not opt into a JSONSet-based rebind
+// on intermediate tokens.
+func rebindChild(node any, decodedToken string, newChild any, nameProvider NameProvider) (any, error) {
+ if _, ok := node.(JSONPointable); ok {
+ return node, nil
+ }
+
+ rValue := reflect.Indirect(reflect.ValueOf(node))
+
+ switch rValue.Kind() {
+ case reflect.Struct:
+ nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
+ if !ok {
+ return node, fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer)
+ }
+ fld := rValue.FieldByName(nm)
+ if !fld.CanSet() {
+ return node, nil
+ }
+ assignReflectValue(fld, newChild)
+ return node, nil
+
+ case reflect.Map:
+ rValue.SetMapIndex(reflect.ValueOf(decodedToken), reflect.ValueOf(newChild))
+ return node, nil
+
+ case reflect.Slice:
+ if decodedToken == dashToken {
+ return node, errDashIntermediate()
+ }
+ idx, err := strconv.Atoi(decodedToken)
+ if err != nil {
+ return node, errors.Join(err, ErrPointer)
+ }
+ elem := rValue.Index(idx)
+ if !elem.CanSet() {
+ return node, nil
+ }
+ assignReflectValue(elem, newChild)
+ return node, nil
+
+ default:
+ return node, errInvalidReference(decodedToken)
+ }
+}
- return setSingleImpl(node, data, decodedToken, nameProvider)
+// assignReflectValue assigns src into dst, unwrapping a pointer when dst
+// expects the pointee type. This tolerates the pointer-wrapping performed
+// by [typeFromValue] for addressable fields.
+func assignReflectValue(dst reflect.Value, src any) {
+ nv := reflect.ValueOf(src)
+ if !nv.IsValid() {
+ return
+ }
+ if nv.Type().AssignableTo(dst.Type()) {
+ dst.Set(nv)
+ return
+ }
+ if nv.Kind() == reflect.Pointer && nv.Elem().Type().AssignableTo(dst.Type()) {
+ dst.Set(nv.Elem())
+ }
}
-func (p *Pointer) resolveNodeForToken(node any, decodedToken string, nameProvider *jsonname.NameProvider) (next any, err error) {
+func (p *Pointer) resolveNodeForToken(node any, decodedToken string, nameProvider NameProvider) (next any, err error) {
// check for nil during traversal
if isNil(node) {
return nil, fmt.Errorf("cannot traverse through nil value at %q: %w", decodedToken, ErrPointer)
@@ -272,6 +423,9 @@ func (p *Pointer) resolveNodeForToken(node any, decodedToken string, nameProvide
return typeFromValue(mv), nil
case reflect.Slice:
+ if decodedToken == dashToken {
+ return nil, errDashIntermediate()
+ }
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return nil, errors.Join(err, ErrPointer)
@@ -312,16 +466,23 @@ func typeFromValue(v reflect.Value) any {
}
// GetForToken gets a value for a json pointer token 1 level deep.
-func GetForToken(document any, decodedToken string) (any, reflect.Kind, error) {
- return getSingleImpl(document, decodedToken, jsonname.DefaultJSONNameProvider)
+func GetForToken(document any, decodedToken string, opts ...Option) (any, reflect.Kind, error) {
+ o := optionsWithDefaults(opts)
+
+ return getSingleImpl(document, decodedToken, o.provider)
}
// SetForToken sets a value for a json pointer token 1 level deep.
-func SetForToken(document any, decodedToken string, value any) (any, error) {
- return document, setSingleImpl(document, value, decodedToken, jsonname.DefaultJSONNameProvider)
+//
+// See [Pointer.Set] for the mutation contract, in particular the handling of
+// the RFC 6901 "-" token on slices.
+func SetForToken(document any, decodedToken string, value any, opts ...Option) (any, error) {
+ o := optionsWithDefaults(opts)
+
+ return setSingleImpl(document, value, decodedToken, o.provider)
}
-func getSingleImpl(node any, decodedToken string, nameProvider *jsonname.NameProvider) (any, reflect.Kind, error) {
+func getSingleImpl(node any, decodedToken string, nameProvider NameProvider) (any, reflect.Kind, error) {
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
if isNil(node) {
@@ -361,6 +522,9 @@ func getSingleImpl(node any, decodedToken string, nameProvider *jsonname.NamePro
return nil, kind, errNoKey(decodedToken)
case reflect.Slice:
+ if decodedToken == dashToken {
+ return nil, kind, errDashOnGet()
+ }
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return nil, kind, errors.Join(err, ErrPointer)
@@ -378,14 +542,14 @@ func getSingleImpl(node any, decodedToken string, nameProvider *jsonname.NamePro
}
}
-func setSingleImpl(node, data any, decodedToken string, nameProvider *jsonname.NameProvider) error {
+func setSingleImpl(node, data any, decodedToken string, nameProvider NameProvider) (any, error) {
// check for nil to prevent panic when calling rValue.Type()
if isNil(node) {
- return fmt.Errorf("cannot set field %q on nil value: %w", decodedToken, ErrPointer)
+ return node, fmt.Errorf("cannot set field %q on nil value: %w", decodedToken, ErrPointer)
}
if ns, ok := node.(JSONSetable); ok {
- return ns.JSONSet(decodedToken, data)
+ return node, ns.JSONSet(decodedToken, data)
}
rValue := reflect.Indirect(reflect.ValueOf(node))
@@ -394,12 +558,12 @@ func setSingleImpl(node, data any, decodedToken string, nameProvider *jsonname.N
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
- return fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer)
+ return node, fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer)
}
fld := rValue.FieldByName(nm)
if !fld.CanSet() {
- return fmt.Errorf("can't set struct field %s to %v: %w", nm, data, ErrPointer)
+ return node, fmt.Errorf("can't set struct field %s to %v: %w", nm, data, ErrPointer)
}
value := reflect.ValueOf(data)
@@ -407,33 +571,51 @@ func setSingleImpl(node, data any, decodedToken string, nameProvider *jsonname.N
assignedType := fld.Type()
if !valueType.AssignableTo(assignedType) {
- return fmt.Errorf("can't set value with type %T to field %s with type %v: %w", data, nm, assignedType, ErrPointer)
+ return node, fmt.Errorf("can't set value with type %T to field %s with type %v: %w", data, nm, assignedType, ErrPointer)
}
fld.Set(value)
- return nil
+ return node, nil
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
rValue.SetMapIndex(kv, reflect.ValueOf(data))
- return nil
+ return node, nil
case reflect.Slice:
+ if decodedToken == dashToken {
+ // RFC 6901 §4 / RFC 6902 append semantics: terminal "-" appends
+ // the value to the slice. We rebind in place when the slice is
+ // reachable via an addressable ancestor; otherwise we return the
+ // new slice header for the parent (or the public Set) to rebind.
+ value := reflect.ValueOf(data)
+ elemType := rValue.Type().Elem()
+ if !value.Type().AssignableTo(elemType) {
+ return node, fmt.Errorf("can't append value of type %T to slice of %v: %w", data, elemType, ErrPointer)
+ }
+ newSlice := reflect.Append(rValue, value)
+ if rValue.CanSet() {
+ rValue.Set(newSlice)
+ return node, nil
+ }
+ return newSlice.Interface(), nil
+ }
+
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
- return errors.Join(err, ErrPointer)
+ return node, errors.Join(err, ErrPointer)
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
- return errOutOfBounds(sLength, tokenIndex)
+ return node, errOutOfBounds(sLength, tokenIndex)
}
elem := rValue.Index(tokenIndex)
if !elem.CanSet() {
- return fmt.Errorf("can't set slice index %s to %v: %w", decodedToken, data, ErrPointer)
+ return node, fmt.Errorf("can't set slice index %s to %v: %w", decodedToken, data, ErrPointer)
}
value := reflect.ValueOf(data)
@@ -441,15 +623,15 @@ func setSingleImpl(node, data any, decodedToken string, nameProvider *jsonname.N
assignedType := elem.Type()
if !valueType.AssignableTo(assignedType) {
- return fmt.Errorf("can't set value with type %T to slice element %d with type %v: %w", data, tokenIndex, assignedType, ErrPointer)
+ return node, fmt.Errorf("can't set value with type %T to slice element %d with type %v: %w", data, tokenIndex, assignedType, ErrPointer)
}
elem.Set(value)
- return nil
+ return node, nil
default:
- return errInvalidReference(decodedToken)
+ return node, errInvalidReference(decodedToken)
}
}
@@ -460,24 +642,27 @@ func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) {
if err != nil {
return 0, err
}
- switch tk := tk.(type) {
- case json.Delim:
- switch tk {
- case '{':
- if err = drainSingle(dec); err != nil {
- return 0, err
- }
- case '[':
+ key, ok := tk.(string)
+ if !ok {
+ return 0, fmt.Errorf("invalid key token %#v: %w", tk, ErrPointer)
+ }
+ if key == decodedToken {
+ return offset, nil
+ }
+
+ // Consume the associated value. Scalars are fully read by a single
+ // Token() call; composite values must be drained.
+ tk, err = dec.Token()
+ if err != nil {
+ return 0, err
+ }
+ if delim, isDelim := tk.(json.Delim); isDelim {
+ switch delim {
+ case '{', '[':
if err = drainSingle(dec); err != nil {
return 0, err
}
}
- case string:
- if tk == decodedToken {
- return offset, nil
- }
- default:
- return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer)
}
}
@@ -485,6 +670,9 @@ func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) {
}
func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) {
+ if decodedToken == dashToken {
+ return 0, errDashOnOffset()
+ }
idx, err := strconv.Atoi(decodedToken)
if err != nil {
return 0, fmt.Errorf("token reference %q is not a number: %w: %w", decodedToken, err, ErrPointer)
diff --git a/vendor/github.com/go-openapi/jsonreference/.gitignore b/vendor/github.com/go-openapi/jsonreference/.gitignore
index 885dc27ab0b..d8f4186fe59 100644
--- a/vendor/github.com/go-openapi/jsonreference/.gitignore
+++ b/vendor/github.com/go-openapi/jsonreference/.gitignore
@@ -3,4 +3,3 @@
.idea
.env
.mcp.json
-.claude/
diff --git a/vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.md b/vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.md
index 7faeb83a77d..3cfbca6a6a3 100644
--- a/vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.md
+++ b/vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.md
@@ -4,18 +4,18 @@
| Total Contributors | Total Contributions |
| --- | --- |
-| 9 | 73 |
+| 9 | 79 |
| Username | All Time Contribution Count | All Commits |
| --- | --- | --- |
-| @fredbi | 36 | https://github.com/go-openapi/jsonreference/commits?author=fredbi |
-| @casualjim | 25 | https://github.com/go-openapi/jsonreference/commits?author=casualjim |
-| @youyuanwu | 5 | https://github.com/go-openapi/jsonreference/commits?author=youyuanwu |
-| @olivierlemasle | 2 | https://github.com/go-openapi/jsonreference/commits?author=olivierlemasle |
-| @apelisse | 1 | https://github.com/go-openapi/jsonreference/commits?author=apelisse |
-| @gbjk | 1 | https://github.com/go-openapi/jsonreference/commits?author=gbjk |
-| @honza | 1 | https://github.com/go-openapi/jsonreference/commits?author=honza |
-| @Neo2308 | 1 | https://github.com/go-openapi/jsonreference/commits?author=Neo2308 |
-| @erraggy | 1 | https://github.com/go-openapi/jsonreference/commits?author=erraggy |
+| @fredbi | 42 | |
+| @casualjim | 25 | |
+| @youyuanwu | 5 | |
+| @olivierlemasle | 2 | |
+| @apelisse | 1 | |
+| @gbjk | 1 | |
+| @honza | 1 | |
+| @Neo2308 | 1 | |
+| @erraggy | 1 | |
- _this file was generated by the [Contributors GitHub Action](https://github.com/github/contributors)_
+ _this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_
diff --git a/vendor/github.com/go-openapi/jsonreference/README.md b/vendor/github.com/go-openapi/jsonreference/README.md
index adea1606197..43d05b05069 100644
--- a/vendor/github.com/go-openapi/jsonreference/README.md
+++ b/vendor/github.com/go-openapi/jsonreference/README.md
@@ -14,15 +14,9 @@
An implementation of JSON Reference for golang.
+
## Status
@@ -74,9 +68,9 @@ on top of which it has been built.
## Other documentation
* [All-time contributors](./CONTRIBUTORS.md)
-* [Contributing guidelines](.github/CONTRIBUTING.md)
-* [Maintainers documentation](docs/MAINTAINERS.md)
-* [Code style](docs/STYLE.md)
+* [Contributing guidelines][contributing-doc-site]
+* [Maintainers documentation][maintainers-doc-site]
+* [Code style][style-doc-site]
## Cutting a new release
@@ -115,7 +109,7 @@ Maintainers can cut a new release by either:
[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM
[slack-url]: https://goswagger.slack.com/archives/C04R30YMU
[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue
-[discord-url]: https://discord.gg/twZ9BwT3
+[discord-url]: https://discord.gg/FfnFYaC3k5
[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
@@ -125,3 +119,7 @@ Maintainers can cut a new release by either:
[goversion-url]: https://github.com/go-openapi/jsonreference/blob/master/go.mod
[top-badge]: https://img.shields.io/github/languages/top/go-openapi/jsonreference
[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/jsonreference/latest
+
+[contributing-doc-site]: https://go-openapi.github.io/doc-site/contributing/contributing/index.html
+[maintainers-doc-site]: https://go-openapi.github.io/doc-site/maintainers/index.html
+[style-doc-site]: https://go-openapi.github.io/doc-site/contributing/style/index.html
diff --git a/vendor/github.com/go-openapi/loads/.gitignore b/vendor/github.com/go-openapi/loads/.gitignore
index d8f4186fe59..fbb78de2c34 100644
--- a/vendor/github.com/go-openapi/loads/.gitignore
+++ b/vendor/github.com/go-openapi/loads/.gitignore
@@ -3,3 +3,4 @@
.idea
.env
.mcp.json
+.worktrees
diff --git a/vendor/github.com/go-openapi/loads/.golangci.yml b/vendor/github.com/go-openapi/loads/.golangci.yml
index 83968f3faeb..272b14e545d 100644
--- a/vendor/github.com/go-openapi/loads/.golangci.yml
+++ b/vendor/github.com/go-openapi/loads/.golangci.yml
@@ -7,6 +7,8 @@ linters:
- gochecknoglobals # on this repo, it is hard to refactor without globals/inits and no breaking change
- gochecknoinits
- godox
+ - gomodguard
+ - gomodguard_v2
- exhaustruct
- nlreturn
- nonamedreturns
diff --git a/vendor/github.com/go-openapi/loads/CONTRIBUTORS.md b/vendor/github.com/go-openapi/loads/CONTRIBUTORS.md
index 36b836a3d5a..6ab26b8dd76 100644
--- a/vendor/github.com/go-openapi/loads/CONTRIBUTORS.md
+++ b/vendor/github.com/go-openapi/loads/CONTRIBUTORS.md
@@ -4,12 +4,12 @@
| Total Contributors | Total Contributions |
| --- | --- |
-| 14 | 123 |
+| 14 | 133 |
| Username | All Time Contribution Count | All Commits |
| --- | --- | --- |
+| @fredbi | 55 | |
| @casualjim | 48 | |
-| @fredbi | 45 | |
| @youyuanwu | 6 | |
| @vburenin | 4 | |
| @keramix | 4 | |
@@ -23,4 +23,4 @@
| @kreativka | 1 | |
| @petrkotas | 1 | |
- _this file was generated by the [Contributors GitHub Action](https://github.com/github/contributors)_
+ _this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_
diff --git a/vendor/github.com/go-openapi/loads/README.md b/vendor/github.com/go-openapi/loads/README.md
index d92e62a040d..293f79bb6a0 100644
--- a/vendor/github.com/go-openapi/loads/README.md
+++ b/vendor/github.com/go-openapi/loads/README.md
@@ -20,12 +20,9 @@ Supports JSON and YAML documents.
* **2025-12-19** : new community chat on discord
* a new discord community channel is available to be notified of changes and support users
- * our venerable Slack channel remains open, and will be eventually discontinued on **2026-03-31**
You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url]
-Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url]
-
## Status
API is stable.
@@ -58,6 +55,41 @@ go get github.com/go-openapi/loads
See also the provided [examples](https://pkg.go.dev/github.com/go-openapi/loads#pkg-examples).
+## Security
+
+This library does not enforce a security policy of its own: it reads whatever the configured
+loader is allowed to read.
+
+This is deliberate — like `go-openapi/swag/loading`, it is a base utility,
+and sanitizing or containing untrusted input is the caller's responsibility,
+just as sanitizing a file name before passing it to `os.ReadFile` is not that function's job.
+
+When a spec — its path or its `$ref` contents — may come from an untrusted source, confine
+loading explicitly (e.g. `loading.WithRoot` for local files and a restricted
+`loading.WithHTTPClient` for remote URLs, passed via `loads.WithLoadingOptions`).
+
+For the common case, the pre-baked `loads.SpecRestricted` / `loads.JSONSpecRestricted` loaders
+bundle a trusted root with a network-restricted client (`loads.RestrictedHTTPClient`) and apply
+the confinement to `$ref` resolution as well:
+
+```go
+doc, err := loads.SpecRestricted(path, trustedRoot)
+```
+
+To harden the package-level default in one call — so even callers that rely on the global
+loader (including cross-package `$ref` resolution via `spec.PathLoader`) are confined, with no
+unconfined fallback left — use `loads.SetRestrictedLoaders` at startup:
+
+```go
+loads.SetRestrictedLoaders(trustedRoot)
+```
+
+Note that `loads.AddLoader` only *prepends* to the default chain, leaving the unconfined loader
+reachable; use `loads.SetLoaders` / `loads.SetRestrictedLoaders` to replace it.
+
+See the [Security section of the package documentation][security-doc] for the threat model and
+runnable examples. For the project's vulnerability reporting policy, see [SECURITY.md](./SECURITY.md).
+
## Change log
See
@@ -69,9 +101,9 @@ This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
## Other documentation
* [All-time contributors](./CONTRIBUTORS.md)
-* [Contributing guidelines](.github/CONTRIBUTING.md)
-* [Maintainers documentation](docs/MAINTAINERS.md)
-* [Code style](docs/STYLE.md)
+* [Contributing guidelines][contributing-doc-site]
+* [Maintainers documentation][maintainers-doc-site]
+* [Code style][style-doc-site]
## Cutting a new release
@@ -102,11 +134,8 @@ Maintainers can cut a new release by either:
[godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/loads
[godoc-url]: http://pkg.go.dev/github.com/go-openapi/loads
-[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png
-[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM
-[slack-url]: https://goswagger.slack.com/archives/C04R30YMU
[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue
-[discord-url]: https://discord.gg/twZ9BwT3
+[discord-url]: https://discord.gg/FfnFYaC3k5
[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
@@ -116,3 +145,9 @@ Maintainers can cut a new release by either:
[goversion-url]: https://github.com/go-openapi/loads/blob/master/go.mod
[top-badge]: https://img.shields.io/github/languages/top/go-openapi/loads
[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/loads/latest
+
+[security-doc]: https://pkg.go.dev/github.com/go-openapi/loads#hdr-Security
+
+[contributing-doc-site]: https://go-openapi.github.io/doc-site/contributing/contributing/index.html
+[maintainers-doc-site]: https://go-openapi.github.io/doc-site/maintainers/index.html
+[style-doc-site]: https://go-openapi.github.io/doc-site/contributing/style/index.html
diff --git a/vendor/github.com/go-openapi/loads/doc.go b/vendor/github.com/go-openapi/loads/doc.go
index 67a5e2f8d95..0fafe4f4683 100644
--- a/vendor/github.com/go-openapi/loads/doc.go
+++ b/vendor/github.com/go-openapi/loads/doc.go
@@ -6,4 +6,72 @@
// It is used by other go-openapi packages to load and run analysis on local or remote spec documents.
//
// Loaders support JSON and YAML documents.
+//
+// # Security
+//
+// This package does not enforce a security policy of its own: like the underlying
+// [github.com/go-openapi/swag/loading] utilities, it reads whatever the configured loader is
+// allowed to read.
+//
+// When a spec — its path or its contents — may derive from untrusted input, the caller must confine loading explicitly.
+//
+// This is a deliberate design choice.
+// Both this package and the [github.com/go-openapi/swag/loading] utilities are base building blocks:
+// deciding which sources are legitimate, and containing access to them,
+// requires application context that a general-purpose loader does not have.
+//
+// Just as sanitizing a file name before handing it to [os.ReadFile] is the caller's
+// responsibility and not that function's, sanitizing and containing the path and references
+// resolved here is the responsibility of the code that may feed them untrusted input.
+//
+// There are two distinct attack surfaces:
+//
+// - The path passed to [Spec], [JSONSpec], or [Embedded]. By default a local path is read
+// with no confinement, so a caller-controlled path (including an absolute path or a
+// "file:///etc/passwd" URI) may read any file the process can access. A remote path is
+// fetched with [net/http.DefaultClient], which follows redirects and performs no
+// destination filtering, so a caller-controlled URL may reach internal services or cloud
+// metadata endpoints (server-side request forgery).
+//
+// - The contents of the spec, when references are resolved. [Document.Expanded] follows the
+// "$ref" pointers found inside the document by calling the same loader recursively. A spec
+// obtained even from a trusted path can therefore drive arbitrary local reads
+// ("$ref": "file:///etc/passwd") or SSRF ("$ref": "http://169.254.169.254/...") through
+// its own contents. This amplification is specific to reference resolution and does not
+// exist in the raw loading utilities.
+//
+// Mitigation. Pass [github.com/go-openapi/swag/loading] options through [WithLoadingOptions];
+// they are attached to the document's loader and so apply both to the initial load and to
+// every "$ref" resolved during expansion:
+//
+// - [github.com/go-openapi/swag/loading.WithRoot] confines local reads to a trusted
+// directory, rejecting absolute paths, ".." traversal, and symlinks that escape it. Prefer
+// it over a [github.com/go-openapi/swag/loading.WithFS] built from [os.DirFS], which does
+// not block symlink escapes.
+//
+// - [github.com/go-openapi/swag/loading.WithHTTPClient] allows to supply a restricted HTTP client.
+// Enforce the network policy at dial time (a [net.Dialer] Control hook), so it also covers
+// redirects and DNS rebinding, which a URL-string allowlist cannot. See the example on
+// [Spec].
+//
+// Pre-baked loaders. When the opinionated defaults fit, [SpecRestricted], [JSONSpecRestricted]
+// and [JSONDocRestricted] bundle a trusted root with a network-restricted client
+// ([RestrictedHTTPClient]), and apply the confinement to "$ref" resolution as well — so the
+// common case needs no manual wiring. To harden the global default in one call (so even callers
+// that rely on the package-level loader are confined), use [SetRestrictedLoaders]. Reach for the
+// options above when you need a custom policy; [IsForbiddenAddress] exposes the default network
+// policy so you can reuse it as the base of your own HTTP client.
+//
+// Caveats:
+//
+// - The package-level default loader (also installed as [github.com/go-openapi/spec.PathLoader])
+// carries no loading options and is therefore unconfined. It is used as a fallback when
+// expansion runs without a document loader, and by other go-openapi packages that resolve
+// references on their own. [AddLoader] does not fix this — it only prepends, leaving the
+// unconfined fallback reachable. Either build a confined loader per call, or replace the
+// global default outright with [SetLoaders] / [SetRestrictedLoaders].
+//
+// - A custom loader installed via [WithDocLoader] or [AddLoader] only honors these
+// protections if its loading function actually applies the [github.com/go-openapi/swag/loading]
+// options it is given.
package loads
diff --git a/vendor/github.com/go-openapi/loads/errors.go b/vendor/github.com/go-openapi/loads/errors.go
index 14a8186b6ca..e94f038f947 100644
--- a/vendor/github.com/go-openapi/loads/errors.go
+++ b/vendor/github.com/go-openapi/loads/errors.go
@@ -15,4 +15,8 @@ const (
// ErrNoLoader indicates that no configured loader matched the input.
ErrNoLoader loaderError = "no loader matched"
+
+ // ErrForbiddenAddress is returned by [RestrictedHTTPClient] when a connection is attempted
+ // to a non-public address (loopback, private, link-local, or unspecified).
+ ErrForbiddenAddress loaderError = "blocked dial to a non-public address"
)
diff --git a/vendor/github.com/go-openapi/loads/loaders.go b/vendor/github.com/go-openapi/loads/loaders.go
index ac8adfe8b20..f8a2a9438de 100644
--- a/vendor/github.com/go-openapi/loads/loaders.go
+++ b/vendor/github.com/go-openapi/loads/loaders.go
@@ -21,6 +21,15 @@ import (
var loaders *loader
func init() {
+ loaders = defaultLoaders()
+
+ // sets the global default loader for go-openapi/spec
+ spec.PathLoader = loaders.Load
+}
+
+// defaultLoaders builds the built-in loader chain: a YAML matcher first, with a JSON loader as
+// the catch-all fallback.
+func defaultLoaders() *loader {
jsonLoader := &loader{
DocLoaderWithMatch: DocLoaderWithMatch{
Match: func(_ string) bool {
@@ -30,15 +39,35 @@ func init() {
},
}
- loaders = jsonLoader.WithHead(&loader{
+ return jsonLoader.WithHead(&loader{
DocLoaderWithMatch: DocLoaderWithMatch{
Match: loading.YAMLMatcher,
Fn: loading.YAMLDoc,
},
})
+}
- // sets the global default loader for go-openapi/spec
- spec.PathLoader = loaders.Load
+// buildLoaderChain links a list of [DocLoaderWithMatch] into a loader chain, preserving order.
+// Entries with a nil Fn are skipped. Returns nil when no usable loader is provided.
+func buildLoaderChain(ldrs ...DocLoaderWithMatch) *loader {
+ var final, prev *loader
+ for _, ldr := range ldrs {
+ if ldr.Fn == nil {
+ continue
+ }
+
+ node := &loader{DocLoaderWithMatch: ldr}
+ if prev == nil {
+ final = node
+ prev = node
+
+ continue
+ }
+
+ prev = prev.WithNext(node)
+ }
+
+ return final
}
// DocLoader represents a doc loader type.
@@ -141,6 +170,17 @@ func JSONDoc(path string, opts ...loading.Option) (json.RawMessage, error) {
//
// This function updates the default loader used by [github.com/go-openapi/spec].
// Since this sets package level globals, you shouldn't call this concurrently.
+//
+// # Security
+//
+// AddLoader only *prepends* to the default chain: the previous loaders — including the
+// unconfined JSON fallback — remain reachable, both here and via cross-package "$ref"
+// resolution. It is therefore the wrong tool for hardening the global default. To replace the
+// chain entirely (leaving no unconfined fallback) use [SetLoaders], or [SetRestrictedLoaders]
+// for a one-call confined setup. For a single load, prefer a confined per-call loader via
+// [WithLoadingOptions] or [WithDocLoaderMatches]. A custom loader registered here only honors
+// the protections if its loading function applies the [github.com/go-openapi/swag/loading]
+// options it is given. See the package documentation on Security.
func AddLoader(predicate DocMatcher, load DocLoader) {
loaders = loaders.WithHead(&loader{
DocLoaderWithMatch: DocLoaderWithMatch{
@@ -152,3 +192,36 @@ func AddLoader(predicate DocMatcher, load DocLoader) {
// sets the global default loader for go-openapi/spec
spec.PathLoader = loaders.Load
}
+
+// SetLoaders replaces the package-level default loader chain with the given loaders, tried in
+// order, and re-points [github.com/go-openapi/spec.PathLoader] at it.
+//
+// Unlike [AddLoader], nothing of the previous default survives — so when the replacement is
+// confined, no unconfined fallback remains for any caller relying on the global default
+// (including cross-package "$ref" resolution). An entry with a nil Match is a catch-all; you
+// are responsible for providing a suitable fallback. Calling SetLoaders with no usable loader
+// restores the built-in default (a YAML matcher with a JSON fallback).
+//
+// # Concurrency
+//
+// This sets package-level globals and the [github.com/go-openapi/spec] global loader. It is
+// not safe to call concurrently with other loads or with [AddLoader]; configure it once at
+// startup, before serving.
+//
+// # Security
+//
+// This is the way to harden the global default in one place. For a ready-made confined setup,
+// see [SetRestrictedLoaders]. As with [AddLoader], a custom loader only honors the protections
+// if its loading function applies the [github.com/go-openapi/swag/loading] options it is given.
+// See the package documentation on Security.
+func SetLoaders(ldrs ...DocLoaderWithMatch) {
+ chain := buildLoaderChain(ldrs...)
+ if chain == nil {
+ chain = defaultLoaders()
+ }
+
+ loaders = chain
+
+ // sets the global default loader for go-openapi/spec
+ spec.PathLoader = loaders.Load
+}
diff --git a/vendor/github.com/go-openapi/loads/options.go b/vendor/github.com/go-openapi/loads/options.go
index 045ece5e095..fec20520b4d 100644
--- a/vendor/github.com/go-openapi/loads/options.go
+++ b/vendor/github.com/go-openapi/loads/options.go
@@ -51,25 +51,16 @@ func WithDocLoader(l DocLoader) LoaderOption {
// Loaders are executed in the order of provided [DocLoaderWithMatch] 'es.
func WithDocLoaderMatches(l ...DocLoaderWithMatch) LoaderOption {
return func(opt *options) {
- var final, prev *loader
- for _, ldr := range l {
- if ldr.Fn == nil {
- continue
- }
-
- if prev == nil {
- final = &loader{DocLoaderWithMatch: ldr}
- prev = final
- continue
- }
-
- prev = prev.WithNext(&loader{DocLoaderWithMatch: ldr})
- }
- opt.loader = final
+ opt.loader = buildLoaderChain(l...)
}
}
// WithLoadingOptions adds some [loading.Option] to be added when calling a registered loader.
+//
+// The options are attached to the document's loader, so they apply both to the initial load
+// and to every "$ref" resolved during [Document.Expanded]. This is the recommended place to
+// confine loading of untrusted input, for example with [loading.WithRoot] (local) and
+// [loading.WithHTTPClient] (remote). See the package documentation on Security.
func WithLoadingOptions(loadingOptions ...loading.Option) LoaderOption {
return func(opt *options) {
opt.loadingOptions = loadingOptions
diff --git a/vendor/github.com/go-openapi/loads/restricted.go b/vendor/github.com/go-openapi/loads/restricted.go
new file mode 100644
index 00000000000..022a9a8572a
--- /dev/null
+++ b/vendor/github.com/go-openapi/loads/restricted.go
@@ -0,0 +1,185 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package loads
+
+import (
+ "encoding/json"
+ "net"
+ "net/http"
+ "net/netip"
+ "syscall"
+ "time"
+
+ "github.com/go-openapi/swag/loading"
+)
+
+const (
+ // numConfinementOptions is the count of loading options appended to enforce confinement
+ // (WithRoot + WithHTTPClient), used to size the bundled option slice.
+ numConfinementOptions = 2
+
+ defaultTLSHandshakeTimeout = 10 * time.Second
+)
+
+// RestrictedHTTPClient returns an [http.Client] that refuses, at dial time, to connect to
+// loopback, private, link-local (including cloud-metadata endpoints such as 169.254.169.254),
+// or unspecified addresses. A blocked connection fails with an error wrapping
+// [ErrForbiddenAddress].
+//
+// The check runs in the dialer Control hook, after DNS resolution and before connect, so it
+// also covers HTTP redirects and DNS rebinding — which a URL-string allowlist cannot. The
+// client does not honor proxy environment variables, so the guard always inspects the real
+// destination rather than a proxy address.
+//
+// This is the network half of the restricted loaders ([JSONDocRestricted],
+// [JSONSpecRestricted], [SpecRestricted]). It may also be used directly with
+// [github.com/go-openapi/swag/loading.WithHTTPClient].
+//
+// The policy is opinionated and deliberately simple. For a different one (a custom allow/deny
+// list, an explicit proxy, mutual TLS, ...), build your own client and pass it with
+// [github.com/go-openapi/swag/loading.WithHTTPClient]. To keep the default address policy as a
+// base, reuse [IsForbiddenAddress] in your own dialer Control hook — see the package examples
+// for the pattern.
+func RestrictedHTTPClient() *http.Client {
+ control := func(_, address string, _ syscall.RawConn) error {
+ host, _, err := net.SplitHostPort(address)
+ if err != nil {
+ return err
+ }
+ addr, err := netip.ParseAddr(host)
+ if err != nil {
+ return err
+ }
+ if IsForbiddenAddress(addr) {
+ return ErrForbiddenAddress
+ }
+
+ return nil
+ }
+
+ return &http.Client{
+ Transport: &http.Transport{
+ Proxy: nil, // dial the real destination so the guard inspects it
+ DialContext: (&net.Dialer{Control: control}).DialContext,
+ ForceAttemptHTTP2: true,
+ TLSHandshakeTimeout: defaultTLSHandshakeTimeout,
+ },
+ }
+}
+
+// IsForbiddenAddress reports whether addr is one that [RestrictedHTTPClient] refuses to dial:
+// a loopback, private, link-local (including cloud-metadata endpoints such as 169.254.169.254),
+// or unspecified address. IPv4-mapped IPv6 addresses are unmapped before the check.
+//
+// It is exported so callers can reuse or extend the default policy when building their own
+// dialer Control hook, for example to also reject a CGNAT range or to carve out a single
+// trusted internal host:
+//
+// control := func(_, address string, _ syscall.RawConn) error {
+// host, _, err := net.SplitHostPort(address)
+// if err != nil {
+// return err
+// }
+// addr, err := netip.ParseAddr(host)
+// if err != nil {
+// return err
+// }
+// if loads.IsForbiddenAddress(addr) && host != allowedInternalHost {
+// return loads.ErrForbiddenAddress
+// }
+// return nil
+// }
+func IsForbiddenAddress(addr netip.Addr) bool {
+ a := addr.Unmap()
+
+ return a.IsLoopback() || a.IsPrivate() || a.IsLinkLocalUnicast() || a.IsUnspecified()
+}
+
+// restrictedLoadingOptions bundles caller-supplied options with the confinement options,
+// appended last so that local rooting and the restricted client always take precedence
+// (the loading options are last-wins).
+func restrictedLoadingOptions(root string, extra []loading.Option) []loading.Option {
+ out := make([]loading.Option, 0, len(extra)+numConfinementOptions)
+ out = append(out, extra...)
+ out = append(out, loading.WithRoot(root), loading.WithHTTPClient(RestrictedHTTPClient()))
+
+ return out
+}
+
+// JSONDocRestricted returns a JSON [DocLoader] that confines local reads to root (via
+// [github.com/go-openapi/swag/loading.WithRoot]) and restricts remote fetches with
+// [RestrictedHTTPClient].
+//
+// The returned loader may be registered with [WithDocLoader] or [AddLoader]. The confinement
+// always takes precedence over any option passed here or at call time, so a caller cannot
+// loosen it through [WithLoadingOptions].
+//
+// Like [JSONDoc], it loads JSON only: it does not convert YAML. For specs whose references may
+// point at YAML documents, prefer [SpecRestricted], which keeps the default JSON/YAML chain.
+func JSONDocRestricted(root string, opts ...loading.Option) DocLoader {
+ // one restricted client, reused for every path and $ref
+ return restrictedDocLoader(JSONDoc, restrictedLoadingOptions(root, opts))
+}
+
+// restrictedDocLoader wraps a [DocLoader] so that the confinement options in base are always
+// applied, appended after any call-time options so they take precedence (loading options are
+// last-wins).
+func restrictedDocLoader(fn DocLoader, base []loading.Option) DocLoader {
+ return func(path string, callOpts ...loading.Option) (json.RawMessage, error) {
+ if len(callOpts) == 0 {
+ return fn(path, base...)
+ }
+
+ all := make([]loading.Option, 0, len(callOpts)+len(base))
+ all = append(all, callOpts...)
+ all = append(all, base...) // confinement (tail of base) still wins
+
+ return fn(path, all...)
+ }
+}
+
+// JSONSpecRestricted loads a JSON spec like [JSONSpec], but confines local reads to root and
+// restricts remote fetches with [RestrictedHTTPClient].
+//
+// The confinement is attached to the document's loader, so it also applies to every "$ref"
+// resolved by [Document.Expanded]. Extra [github.com/go-openapi/swag/loading] options (custom
+// headers, basic auth, timeout, ...) may be supplied; the confinement always wins over them.
+func JSONSpecRestricted(path, root string, opts ...loading.Option) (*Document, error) {
+ return JSONSpec(path, WithLoadingOptions(restrictedLoadingOptions(root, opts)...))
+}
+
+// SpecRestricted loads a spec like [Spec] — with JSON/YAML auto-detection — but confines local
+// reads to root and restricts remote fetches with [RestrictedHTTPClient].
+//
+// The confinement is attached to the document's loader, so it also applies to every "$ref"
+// resolved by [Document.Expanded]. Extra [github.com/go-openapi/swag/loading] options (custom
+// headers, basic auth, timeout, ...) may be supplied; the confinement always wins over them.
+func SpecRestricted(path, root string, opts ...loading.Option) (*Document, error) {
+ return Spec(path, WithLoadingOptions(restrictedLoadingOptions(root, opts)...))
+}
+
+// SetRestrictedLoaders hardens the package-level default in a single call: it installs a
+// confined JSON/YAML loader chain — local reads rooted at root, remote fetches through
+// [RestrictedHTTPClient] — as the global default and as
+// [github.com/go-openapi/spec.PathLoader].
+//
+// After this call, every load that relies on the package default ([Spec], [JSONSpec], and any
+// cross-package "$ref" resolution) is confined, with no unconfined fallback left behind. It is
+// the global counterpart of [SpecRestricted]; a single restricted client is shared across the
+// chain. Extra [github.com/go-openapi/swag/loading] options may be supplied; the confinement
+// always wins over them.
+//
+// # Concurrency
+//
+// Like [SetLoaders], this mutates package-level and [github.com/go-openapi/spec] globals and is
+// not safe to call concurrently. Configure it once at startup, before serving. To revert, call
+// [SetLoaders] with no arguments.
+func SetRestrictedLoaders(root string, opts ...loading.Option) {
+ base := restrictedLoadingOptions(root, opts) // one restricted client shared by the whole chain
+
+ SetLoaders(
+ NewDocLoaderWithMatch(restrictedDocLoader(loading.YAMLDoc, base), loading.YAMLMatcher),
+ NewDocLoaderWithMatch(restrictedDocLoader(JSONDoc, base), nil), // nil matcher: JSON catch-all fallback
+ )
+}
diff --git a/vendor/github.com/go-openapi/loads/spec.go b/vendor/github.com/go-openapi/loads/spec.go
index 606a01d8e9f..40eaff2c73b 100644
--- a/vendor/github.com/go-openapi/loads/spec.go
+++ b/vendor/github.com/go-openapi/loads/spec.go
@@ -77,6 +77,14 @@ func Embedded(orig, flat json.RawMessage, opts ...LoaderOption) (*Document, erro
// Spec loads a new spec document from a local or remote path.
//
// By default it uses a JSON or YAML loader, with auto-detection based on the resource extension.
+//
+// Security: by default the path is read with no confinement (local) and fetched with
+// [net/http.DefaultClient] (remote), and any "$ref" later resolved by [Document.Expanded] is
+// loaded the same way. When the path or the spec contents may derive from untrusted input,
+// confine loading with [WithLoadingOptions] (for example
+// [github.com/go-openapi/swag/loading.WithRoot] and
+// [github.com/go-openapi/swag/loading.WithHTTPClient]). See the package documentation on
+// Security.
func Spec(path string, opts ...LoaderOption) (*Document, error) {
ldr := loaderFromOptions(opts)
@@ -157,6 +165,14 @@ func trimData(in json.RawMessage) (json.RawMessage, error) {
}
// Expanded expands the $ref fields in the spec [Document] and returns a new expanded [Document].
+//
+// Security: expansion resolves every "$ref" by calling the document's loader recursively, so
+// the spec contents drive further loads. A spec from an untrusted source can thus trigger
+// arbitrary local reads or SSRF through its references. The loader carries the
+// [github.com/go-openapi/swag/loading] options supplied via [WithLoadingOptions] at load time;
+// configure confinement there so it applies to expansion as well. When no document loader is
+// set, expansion falls back to the unconfined package-level loader. See the package
+// documentation on Security.
func (d *Document) Expanded(options ...*spec.ExpandOptions) (*Document, error) {
swspec := new(spec.Swagger)
if err := json.Unmarshal(d.raw, swspec); err != nil {
diff --git a/vendor/github.com/go-openapi/runtime/.codecov.yml b/vendor/github.com/go-openapi/runtime/.codecov.yml
new file mode 100644
index 00000000000..a5ba8e96d8e
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/.codecov.yml
@@ -0,0 +1,9 @@
+codecov:
+ notify:
+ after_n_builds: 2
+
+coverage:
+ status:
+ patch:
+ default:
+ target: 80%
diff --git a/vendor/github.com/go-openapi/runtime/.gitignore b/vendor/github.com/go-openapi/runtime/.gitignore
index d8f4186fe59..c0bc15bebe6 100644
--- a/vendor/github.com/go-openapi/runtime/.gitignore
+++ b/vendor/github.com/go-openapi/runtime/.gitignore
@@ -3,3 +3,5 @@
.idea
.env
.mcp.json
+go.work.sum
+.worktrees/
diff --git a/vendor/github.com/go-openapi/runtime/.golangci.yml b/vendor/github.com/go-openapi/runtime/.golangci.yml
index 0087ed31130..ef2ff12bea3 100644
--- a/vendor/github.com/go-openapi/runtime/.golangci.yml
+++ b/vendor/github.com/go-openapi/runtime/.golangci.yml
@@ -2,13 +2,9 @@ version: "2"
linters:
default: all
disable:
- - cyclop
- depguard
- err113 # disabled temporarily: there are just too many issues to address
- - errchkjson
- - errorlint
- exhaustruct
- - forcetypeassert
- funlen
- gochecknoglobals
- gochecknoinits
@@ -16,12 +12,12 @@ linters:
- godot
- godox
- gomoddirectives # moved to mono-repo, multi-modules, so replace directives are needed
+ - gomodguard
+ - gomodguard_v2
- gosmopolitan
- inamedparam
- - ireturn
- - lll
+ - ireturn # this repo adopted a pattern where there are quite many returned interfaces. To be challenged with v2
- musttag
- - nestif
- nilerr # nilerr crashes on this repo
- nlreturn
- noinlineerr
@@ -31,7 +27,6 @@ linters:
- testpackage
- thelper
- tparallel
- - unparam
- varnamelen
- whitespace
- wrapcheck
@@ -43,8 +38,17 @@ linters:
goconst:
min-len: 2
min-occurrences: 3
+ cyclop:
+ max-complexity: 25
gocyclo:
- min-complexity: 45
+ min-complexity: 25
+ gocognit:
+ min-complexity: 35
+ exhaustive:
+ default-signifies-exhaustive: true
+ default-case-required: true
+ lll:
+ line-length: 180
exclusions:
generated: lax
presets:
@@ -53,6 +57,7 @@ linters:
- legacy
- std-error-handling
paths:
+ - .worktrees
- third_party$
- builtin$
- examples$
@@ -60,12 +65,17 @@ formatters:
enable:
- gofmt
- goimports
+ settings:
+ # local prefixes regroup imports from these packages
+ goimports:
+ local-prefixes:
+ - github.com/go-openapi
exclusions:
generated: lax
paths:
+ - .worktrees
- third_party$
- builtin$
- - examples$
issues:
# Maximum issues count per one linter.
# Set to 0 to disable.
diff --git a/vendor/github.com/go-openapi/runtime/CONTRIBUTORS.md b/vendor/github.com/go-openapi/runtime/CONTRIBUTORS.md
new file mode 100644
index 00000000000..0ef327861d0
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/CONTRIBUTORS.md
@@ -0,0 +1,83 @@
+# Contributors
+
+- Repository: ['go-openapi/runtime']
+
+| Total Contributors | Total Contributions |
+| --- | --- |
+| 71 | 565 |
+
+| Username | All Time Contribution Count | All Commits |
+| --- | --- | --- |
+| @casualjim | 268 | |
+| @fredbi | 140 | |
+| @youyuanwu | 19 | |
+| @josephwoodward | 13 | |
+| @kenjones-cisco | 12 | |
+| @GlenDC | 7 | |
+| @moenning | 6 | |
+| @mstoykov | 6 | |
+| @elakito | 6 | |
+| @ifraixedes | 5 | |
+| @zeitlinger | 4 | |
+| @Copilot | 3 | |
+| @jkawamoto | 3 | |
+| @stoyanr | 3 | |
+| @keramix | 2 | |
+| @Equanox | 2 | |
+| @ederavilaprado | 2 | |
+| @nan0tube | 2 | |
+| @thomdixon | 2 | |
+| @deborggraever | 2 | |
+| @MakarandNsd | 2 | |
+| @Vadskye | 2 | |
+| @jsilland | 2 | |
+| @Kunde21 | 2 | |
+| @bcomnes | 2 | |
+| @galaxie | 2 | |
+| @anfernee | 2 | |
+| @wahabmk | 1 | |
+| @vearutop | 1 | |
+| @tschaub | 1 | |
+| @pytlesk4 | 1 | |
+| @tgraf | 1 | |
+| @seanprince | 1 | |
+| @rodriguise | 1 | |
+| @petrkotas | 1 | |
+| @maxatome | 1 | |
+| @maxkarelov | 1 | |
+| @tooolbox | 1 | |
+| @akutz | 1 | |
+| @yabberyabber | 1 | |
+| @elv-gilles | 1 | |
+| @gregmarr | 1 | |
+| @jwalter1-quest | 1 | |
+| @s4s7 | 1 | |
+| @stingshen | 1 | |
+| @tamalsaha | 1 | |
+| @tte | 1 | |
+| @martian4202 | 1 | |
+| @yan-zhuang | 1 | |
+| @aleksandr-vin | 1 | |
+| @azylman | 1 | |
+| @anasmuhmd | 1 | |
+| @ArFe | 1 | |
+| @CodeLingoBot | 1 | |
+| @dlmiddlecote | 1 | |
+| @danny-cheung | 1 | |
+| @calavera | 1 | |
+| @EdwardBetts | 1 | |
+| @etsangsplk | 1 | |
+| @ericzsplk | 1 | |
+| @faguirre1 | 1 | |
+| @florindragos | 1 | |
+| @gbjk | 1 | |
+| @taisho6339 | 1 | |
+| @jbowes | 1 | |
+| @JoakimSoderberg | 1 | |
+| @robbert229 | 1 | |
+| @jonathaningram | 1 | |
+| @KuaaMU | 1 | |
+| @germanhs | 1 | |
+| @pracucci | 1 | |
+
+ _this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_
diff --git a/vendor/github.com/go-openapi/runtime/README.md b/vendor/github.com/go-openapi/runtime/README.md
index dd7f5039a79..134d930cd9f 100644
--- a/vendor/github.com/go-openapi/runtime/README.md
+++ b/vendor/github.com/go-openapi/runtime/README.md
@@ -8,8 +8,7 @@
[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url]
-[![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge]
-
+[![Doc][doc-badge]][doc-url] [![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge]
---
A runtime for go OpenAPI toolkit.
@@ -18,13 +17,44 @@ The runtime component for use in code generation or as untyped usage.
## Announcements
-* **2025-12-19** : new community chat on discord
- * a new discord community channel is available to be notified of changes and support users
- * our venerable Slack channel remains open, and will be eventually discontinued on **2026-03-31**
+[**Complete documentation as github pages**][doc-url]
+
+**Changes to the API surface in `v0.30.0`**:
+
+* utility package `header` has now moved to `github.com/go-openapi/runtime/server-middleware/negotiate/header`
+
+> A shim is provided to support existing programs, with a deprecation notice.
+
+**Changes in semantics in `v0.30.0`**:
+
+Function `negotiate.NegotiateContentType` (available as an alias for backward compatibility as `middleware.NegotiateContentType`
+now performs a full match considering MIME parameters.
+
+The previous behavior (matching in order of appearance after stripping parameters) may be enabled explicitly with
+option `negotiate.WithIgnoreParameters`.
+
+* **2026-05-07** : exposed UI and Spec middleware as a separate, dependency-free module.
+
+> Newly available package: `github.com/go-openapi/runtime/server-middleware/docui` that now holds our
+> UI and spec serve middleware.
+>
+> A shim is available in `github.com/go-openapi/runtime/middleware` to bridge the older UI options to the new ones,
+> with a deprecation notice.
+>
+> Methods that were unduly exported and purely used to manipulate options (e.g. `SwaggerUIOpts.EnsureDefaults`) have been
+> removed. New options in `docui` should be used instead.
+
+> Users may reuse this middleware to serve a Redoc, Rapidoc or SwaggerUI documentation without
+> importing the complete go-openapi scaffolding.
-You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url]
+* **2026-05-05** : exposed content negotiation methods as a separate, dependency-free module
-Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url]
+> Users may reuse these utilities to support content-negotiation without extra dependencies.
+>
+> Newly available module: `github.com/go-openapi/runtime/server-middleware`
+>
+> Newly available packages: `github.com/go-openapi/runtime/server-middleware/negotiate` and
+> `github.com/go-openapi/runtime/server-middleware/mediatype`.
## Status
@@ -40,18 +70,21 @@ go get github.com/go-openapi/runtime
See
-For pre-v0.30.0 releases see [release notes](docs/NOTES.md).
+For v0.29.0 release see [release notes](docs/NOTES.md).
+From that release onwards, changes are tracked in the github release notes.
**What coming next?**
Moving forward, we want to :
-* [ ] continue narrowing down the scope of dependencies:
- * yaml support in an independent module
+* [x] fix a few known issues with some file upload requests (e.g. #286)
+* [] continue narrowing down the scope of dependencies:
+ * [x] split middleware and other useful utilities as a separate dependency-free module
+ * yaml support in an independent module (v2)
* introduce more up-to-date support for opentelemetry as a separate module that evolves
independently from the main package (to avoid breaking changes, the existing API
- will remain maintained, but evolve at a slower pace than opentelemetry).
-* [ ] fix a few known issues with some file upload requests (e.g. #286)
+ will remain maintained, but evolve at a slower pace than opentelemetry). (v2)
+* [] publish proper documentation and examples
## Licensing
@@ -62,11 +95,11 @@ on top of which it has been built.
## Other documentation
-* [FAQ](docs/FAQ.md)
+* [FAQ](https://go-openapi.github.io/runtime/tutorials/faq/) · [Media-type selection](https://go-openapi.github.io/runtime/tutorials/media-types/) · [Client keep-alive](https://go-openapi.github.io/runtime/tutorials/keep-alive/)
* [All-time contributors](./CONTRIBUTORS.md)
-* [Contributing guidelines](.github/CONTRIBUTING.md)
-* [Maintainers documentation](docs/MAINTAINERS.md)
-* [Code style](docs/STYLE.md)
+* [Contributing guidelines][contributing-doc-site]
+* [Maintainers documentation][maintainers-doc-site]
+* [Code style][style-doc-site]
## Cutting a new release
@@ -95,13 +128,12 @@ Maintainers can cut a new release by either:
[codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/runtime
[codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/runtime
+[doc-badge]: https://img.shields.io/badge/doc-site-blue?link=https%3A%2F%2Fgo-openapi.github.io%2Fruntime%2F
+[doc-url]: https://go-openapi.github.io/runtime
[godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/runtime
[godoc-url]: http://pkg.go.dev/github.com/go-openapi/runtime
-[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png
-[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM
-[slack-url]: https://goswagger.slack.com/archives/C04R30YMU
[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue
-[discord-url]: https://discord.gg/twZ9BwT3
+[discord-url]: https://discord.gg/FfnFYaC3k5
[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
@@ -111,3 +143,7 @@ Maintainers can cut a new release by either:
[goversion-url]: https://github.com/go-openapi/runtime/blob/master/go.mod
[top-badge]: https://img.shields.io/github/languages/top/go-openapi/runtime
[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/runtime/latest
+
+[contributing-doc-site]: https://go-openapi.github.io/doc-site/contributing/contributing/index.html
+[maintainers-doc-site]: https://go-openapi.github.io/doc-site/maintainers/index.html
+[style-doc-site]: https://go-openapi.github.io/doc-site/contributing/style/index.html
diff --git a/vendor/github.com/go-openapi/runtime/bytestream.go b/vendor/github.com/go-openapi/runtime/bytestream.go
index 8701c8e3d66..9371ea4ea1f 100644
--- a/vendor/github.com/go-openapi/runtime/bytestream.go
+++ b/vendor/github.com/go-openapi/runtime/bytestream.go
@@ -97,7 +97,7 @@ func ByteStreamConsumer(opts ...byteStreamOpt) Consumer {
}
default:
// check for the underlying type to be pointer to []byte or string,
- if ptr := reflect.TypeOf(data); ptr.Kind() != reflect.Ptr {
+ if ptr := reflect.TypeOf(data); ptr.Kind() != reflect.Pointer {
return errors.New("destination must be a pointer")
}
@@ -126,13 +126,13 @@ func ByteStreamConsumer(opts ...byteStreamOpt) Consumer {
//
// Supported input underlying types and interfaces, prioritized in this order:
//
-// - [io.WriterTo] (for maximum control)
-// - [io.Reader] (performs [io.Copy]). A ReadCloser is closed before exiting.
-// - [encoding.BinaryMarshaler]
-// - error (writes as a string)
-// - []byte
-// - string
-// - struct, other slices: writes as JSON.
+// - [io.WriterTo] (for maximum control)
+// - [io.Reader] (performs [io.Copy]). A ReadCloser is closed before exiting.
+// - [encoding.BinaryMarshaler]
+// - error (writes as a string)
+// - []byte
+// - string
+// - struct, other slices: writes as JSON.
func ByteStreamProducer(opts ...byteStreamOpt) Producer {
var vals byteStreamOpts
for _, opt := range opts {
diff --git a/vendor/github.com/go-openapi/runtime/client/httptrace.go b/vendor/github.com/go-openapi/runtime/client/httptrace.go
new file mode 100644
index 00000000000..5bdea4e2418
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/client/httptrace.go
@@ -0,0 +1,520 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package client
+
+import (
+ "context"
+ "crypto/tls"
+ "fmt"
+ "io"
+ "net/http/httptrace"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/go-openapi/runtime/logger"
+)
+
+// traceSession owns the per-request state for [Runtime.Trace].
+//
+// It tracks the t=0 anchor for the connection phase, accumulates
+// per-phase timestamps (for the trailing summary), and emits each
+// event to the runtime logger as it fires. One session per
+// SubmitContext call.
+type traceSession struct {
+ logger logger.Logger
+ method string
+ url string
+
+ // tlsCfg points at the *tls.Config of the http.Transport that
+ // will run the request, when introspectable (i.e. the transport
+ // is an *http.Transport). Used by the TLS diagnostic mode to
+ // cross-check user configuration against what the handshake
+ // actually attempted. Nil when the transport is custom and
+ // the config cannot be reached.
+ tlsCfg *tls.Config
+
+ mu sync.Mutex
+ start time.Time
+ last time.Time // last printed event, for relative-dt rendering
+ phases phaseTimings
+ gotConn httptrace.GotConnInfo
+ tlsDone tlsResult
+
+ dnsStartAt time.Time
+ connectStartAt time.Time
+ tlsHandshakeStartAt time.Time
+ wait100StartAt time.Time
+ gotConnAt time.Time
+ wroteHeadersAt time.Time
+ wroteRequestAt time.Time
+ ttfbAt time.Time
+
+ statusCode int
+ rtError error
+}
+
+// phaseTimings holds the per-phase durations for the trailing
+// summary line. Zero values mean "phase did not occur" (e.g. no
+// DNS lookup on a reused conn, no TLS on http://).
+type phaseTimings struct {
+ dns time.Duration
+ dial time.Duration
+ tls time.Duration
+ ttfb time.Duration // time from GotConn to first response byte
+}
+
+// tlsResult captures whatever we learned from TLSHandshakeDone.
+// On the happy path err is nil and state is fully populated; on
+// failure state may be partial (and is what the TLS diagnostic
+// mode in httptrace_tls.go works from).
+type tlsResult struct {
+ state tls.ConnectionState
+ err error
+ done bool
+}
+
+const tracePrefix = "[trace] "
+
+// staleIdleThreshold is the idle duration above which a reused
+// pooled connection earns a HEADS-UP annotation. Per-runtime
+// configurability is deferred to v2; 30s matches the issue #336
+// territory (typical NAT idle timeouts start in the 60–350s
+// range, so a 30s reuse is already in "could be stale" zone).
+const staleIdleThreshold = 30 * time.Second
+
+// newTraceSession allocates a session and pre-renders the opening
+// line (method + url). The session is not yet attached to a
+// context — that's the caller's responsibility via session.attach.
+//
+// tlsCfg may be nil; when non-nil it is used by the TLS diagnostic
+// mode to cross-check user-configured constraints (MinVersion,
+// CipherSuites, custom RootCAs) against handshake failures.
+func newTraceSession(log logger.Logger, method, url string, tlsCfg *tls.Config) *traceSession {
+ s := &traceSession{
+ logger: log,
+ method: method,
+ url: url,
+ tlsCfg: tlsCfg,
+ start: time.Now(),
+ }
+ s.last = s.start
+ s.emitf("%s %s", method, url)
+ return s
+}
+
+// attach installs the session's ClientTrace on ctx and returns the
+// derived context. Callers pass the returned context to
+// http.Client.Do (typically by setting it on req via
+// req.WithContext) so the transport fires the hooks.
+func (s *traceSession) attach(ctx context.Context) context.Context {
+ return httptrace.WithClientTrace(ctx, s.clientTrace())
+}
+
+// clientTrace wires every httptrace hook to the corresponding
+// session method. Each callback is responsible for its own
+// locking; the stdlib does not serialize trace callbacks.
+func (s *traceSession) clientTrace() *httptrace.ClientTrace {
+ return &httptrace.ClientTrace{
+ GetConn: s.onGetConn,
+ GotConn: s.onGotConn,
+ PutIdleConn: s.onPutIdleConn,
+ GotFirstResponseByte: s.onGotFirstResponseByte,
+ Got100Continue: s.onGot100Continue,
+ DNSStart: s.onDNSStart,
+ DNSDone: s.onDNSDone,
+ ConnectStart: s.onConnectStart,
+ ConnectDone: s.onConnectDone,
+ TLSHandshakeStart: s.onTLSHandshakeStart,
+ TLSHandshakeDone: s.onTLSHandshakeDone,
+ WroteHeaders: s.onWroteHeaders,
+ Wait100Continue: s.onWait100Continue,
+ WroteRequest: s.onWroteRequest,
+ }
+}
+
+// ---------------------------------------------------------------
+// Phase callbacks (stdlib httptrace hooks)
+// ---------------------------------------------------------------
+
+func (s *traceSession) onGetConn(hostPort string) {
+ s.emitTf("GetConn(%s)", hostPort)
+}
+
+func (s *traceSession) onGotConn(info httptrace.GotConnInfo) {
+ s.mu.Lock()
+ s.gotConn = info
+ s.gotConnAt = time.Now()
+ s.mu.Unlock()
+
+ if info.Reused {
+ s.emitTf("GotConn(reused=true, idle=%t, idle-time=%s)",
+ info.WasIdle, info.IdleTime.Round(time.Millisecond))
+ } else {
+ s.emitTf("GotConn(reused=false)")
+ }
+
+ if isStaleIdleReuse(info) {
+ s.emitf("# HEADS-UP: reused idle connection (idle for %s).",
+ info.IdleTime.Round(time.Second))
+ s.emitf("# If this request fails with EOF/connection reset, the server")
+ s.emitf("# or an in-path NAT may have dropped the conn silently.")
+ }
+}
+
+// isStaleIdleReuse reports whether a GotConn info indicates the
+// connection came from the idle pool after sitting idle for
+// longer than [staleIdleThreshold]. This is the issue #336
+// pattern: long-idle pooled conns are the ones most likely to be
+// dead by the time the next request tries to use them.
+func isStaleIdleReuse(info httptrace.GotConnInfo) bool {
+ return info.Reused && info.WasIdle && info.IdleTime > staleIdleThreshold
+}
+
+func (s *traceSession) onPutIdleConn(err error) {
+ if err != nil {
+ s.emitTf("PutIdleConn(err=%v)", err)
+ return
+ }
+ s.emitTf("PutIdleConn")
+}
+
+func (s *traceSession) onGotFirstResponseByte() {
+ s.mu.Lock()
+ s.ttfbAt = time.Now()
+ if !s.gotConnAt.IsZero() {
+ s.phases.ttfb = s.ttfbAt.Sub(s.gotConnAt)
+ }
+ s.mu.Unlock()
+ s.emitTf("GotFirstResponseByte (TTFB)")
+}
+
+func (s *traceSession) onGot100Continue() {
+ s.emitTf("Got100Continue")
+}
+
+func (s *traceSession) onDNSStart(info httptrace.DNSStartInfo) {
+ s.mu.Lock()
+ s.dnsStartAt = time.Now()
+ s.mu.Unlock()
+ s.emitTf("DNSStart(host=%s)", info.Host)
+}
+
+func (s *traceSession) onDNSDone(info httptrace.DNSDoneInfo) {
+ s.mu.Lock()
+ if !s.dnsStartAt.IsZero() {
+ s.phases.dns = time.Since(s.dnsStartAt)
+ }
+ s.mu.Unlock()
+
+ addrs := make([]string, 0, len(info.Addrs))
+ for _, a := range info.Addrs {
+ addrs = append(addrs, a.String())
+ }
+ if info.Err != nil {
+ s.emitTf("DNSDone(err=%v, addrs=[%s], coalesced=%t)",
+ info.Err, strings.Join(addrs, " "), info.Coalesced)
+ return
+ }
+ s.emitTf("DNSDone(addrs=[%s], coalesced=%t)",
+ strings.Join(addrs, " "), info.Coalesced)
+}
+
+func (s *traceSession) onConnectStart(network, addr string) {
+ s.mu.Lock()
+ s.connectStartAt = time.Now()
+ s.mu.Unlock()
+ s.emitTf("ConnectStart(%s %s)", network, addr)
+}
+
+func (s *traceSession) onConnectDone(network, addr string, err error) {
+ s.mu.Lock()
+ if !s.connectStartAt.IsZero() {
+ s.phases.dial = time.Since(s.connectStartAt)
+ }
+ s.mu.Unlock()
+
+ if err != nil {
+ s.emitTf("ConnectDone(%s %s, err=%v)", network, addr, err)
+ return
+ }
+ s.emitTf("ConnectDone(%s %s)", network, addr)
+}
+
+func (s *traceSession) onTLSHandshakeStart() {
+ s.mu.Lock()
+ s.tlsHandshakeStartAt = time.Now()
+ s.mu.Unlock()
+ s.emitTf("TLSHandshakeStart")
+}
+
+func (s *traceSession) onTLSHandshakeDone(state tls.ConnectionState, err error) {
+ s.mu.Lock()
+ if !s.tlsHandshakeStartAt.IsZero() {
+ s.phases.tls = time.Since(s.tlsHandshakeStartAt)
+ }
+ s.tlsDone = tlsResult{state: state, err: err, done: true}
+ s.mu.Unlock()
+
+ if err != nil {
+ s.emitTf("TLSHandshakeDone(err=%v)", err)
+ s.emitTLSDiagnostic(state, err)
+ return
+ }
+ s.emitTf("TLSHandshakeDone(tls=%s, cipher=%s, server=%s%s)",
+ tlsVersionName(state.Version),
+ tls.CipherSuiteName(state.CipherSuite),
+ state.ServerName,
+ certExpiryFragment(state),
+ )
+}
+
+func (s *traceSession) onWroteHeaders() {
+ s.mu.Lock()
+ s.wroteHeadersAt = time.Now()
+ s.mu.Unlock()
+ s.emitTf("WroteHeaders")
+}
+
+func (s *traceSession) onWait100Continue() {
+ s.mu.Lock()
+ s.wait100StartAt = time.Now()
+ s.mu.Unlock()
+ s.emitTf("Wait100Continue")
+}
+
+func (s *traceSession) onWroteRequest(info httptrace.WroteRequestInfo) {
+ s.mu.Lock()
+ s.wroteRequestAt = time.Now()
+ s.mu.Unlock()
+
+ if info.Err != nil {
+ s.emitTf("WroteRequest(err=%v)", info.Err)
+ return
+ }
+ s.emitTf("WroteRequest")
+}
+
+// ---------------------------------------------------------------
+// Body wrapping
+// ---------------------------------------------------------------
+
+// bodySide identifies which direction an instrumented body is on.
+type bodySide string
+
+const (
+ bodySend bodySide = "Sent"
+ bodyRecv bodySide = "Received"
+)
+
+// instrumentedBody wraps an [io.ReadCloser] and emits a
+// BodyChunk{Sent,Received} trace event per Read call. Tracks the
+// inter-read delay in `dt` so users can see streaming-body
+// cadence.
+//
+// Read granularity: bytes returned by the underlying body, not
+// HTTP/1.1 chunked-framing units. For wire-level chunking, use
+// [Runtime.Debug] instead.
+//
+// Concurrency: a single body is read from a single goroutine in
+// practice (http.Transport for request bodies, the application
+// for response bodies), so no internal locking is needed beyond
+// what the underlying ReadCloser provides.
+type instrumentedBody struct {
+ wrapped io.ReadCloser
+ sess *traceSession
+ side bodySide
+ last time.Time
+}
+
+func (b *instrumentedBody) Read(p []byte) (int, error) {
+ n, err := b.wrapped.Read(p)
+ if n > 0 {
+ first := b.last.IsZero()
+ var dt time.Duration
+ if !first {
+ dt = time.Since(b.last)
+ }
+ b.last = time.Now()
+ b.sess.onBodyChunk(b.side, n, dt, first)
+ }
+ return n, err
+}
+
+func (b *instrumentedBody) Close() error {
+ return b.wrapped.Close()
+}
+
+// wrapRequestBody returns an instrumented wrapper around the
+// outgoing request body, or the original body if nil (which is
+// the common case for GET requests). The wrapper observes
+// Transport-side reads, so BodyChunkSent events appear between
+// WroteHeaders and WroteRequest in the trace timeline.
+func (s *traceSession) wrapRequestBody(body io.ReadCloser) io.ReadCloser {
+ if body == nil {
+ return nil
+ }
+ return &instrumentedBody{wrapped: body, sess: s, side: bodySend}
+}
+
+// wrapResponseBody returns an instrumented wrapper around the
+// incoming response body. Stacks cleanly above
+// [KeepAliveTransport]'s drain-on-close behavior.
+func (s *traceSession) wrapResponseBody(body io.ReadCloser) io.ReadCloser {
+ if body == nil {
+ return nil
+ }
+ return &instrumentedBody{wrapped: body, sess: s, side: bodyRecv}
+}
+
+// onBodyChunk renders a single BodyChunk{Sent,Received} event.
+// dt is the duration since the previous Read on the same body and
+// is meaningful only when `first` is false. The first chunk has no
+// preceding read, so the dt= field is suppressed; every subsequent
+// chunk emits dt= unconditionally — even when the measured value
+// rounds to zero (common on Windows, where the system clock
+// resolution is coarser than a fast loopback read loop).
+func (s *traceSession) onBodyChunk(side bodySide, n int, dt time.Duration, first bool) {
+ if first {
+ s.emitTf("BodyChunk%s(n=%d)", side, n)
+ return
+ }
+ s.emitTf("BodyChunk%s(n=%d, dt=%s)", side, n, round(dt))
+}
+
+// ---------------------------------------------------------------
+// Submit-level lifecycle hooks (called from SubmitContext)
+// ---------------------------------------------------------------
+
+// onRoundTripError is called by SubmitContext when http.Client.Do
+// returns an error. It records the error for the summary line.
+func (s *traceSession) onRoundTripError(err error) {
+ s.mu.Lock()
+ s.rtError = err
+ s.mu.Unlock()
+ s.emitTf("! error: %v", err)
+}
+
+// onResponse is called when http.Client.Do returns successfully.
+// It records the status code for the summary line.
+func (s *traceSession) onResponse(statusCode int) {
+ s.mu.Lock()
+ s.statusCode = statusCode
+ s.mu.Unlock()
+}
+
+// finish renders the trailing single-line summary and is called
+// by SubmitContext after the response body has been consumed (or
+// on error path, after the error was recorded). When a round-trip
+// error happened on a stale-idle reused connection, a tail block
+// flags the issue #336 pattern explicitly.
+func (s *traceSession) finish() {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ total := time.Since(s.start)
+ var b strings.Builder
+ fmt.Fprintf(&b, "Summary: %s — ", s.method)
+ if s.rtError != nil {
+ fmt.Fprintf(&b, "FAILED (%v)", s.rtError)
+ } else {
+ fmt.Fprintf(&b, "%d", s.statusCode)
+ }
+ if s.phases.dns > 0 {
+ fmt.Fprintf(&b, ", dns=%s", round(s.phases.dns))
+ }
+ if s.phases.dial > 0 {
+ fmt.Fprintf(&b, ", dial=%s", round(s.phases.dial))
+ }
+ if s.phases.tls > 0 {
+ fmt.Fprintf(&b, ", tls=%s", round(s.phases.tls))
+ }
+ if s.phases.ttfb > 0 {
+ fmt.Fprintf(&b, ", ttfb=%s", round(s.phases.ttfb))
+ }
+ fmt.Fprintf(&b, ", total=%s", round(total))
+
+ s.emitRaw(b.String())
+
+ // issue #336 tail annotation: a round-trip failure on a
+ // stale-idle reused conn is the canonical pattern.
+ if s.rtError != nil && isStaleIdleReuse(s.gotConn) {
+ s.emitf("# FAILED on a reused idle conn (%s idle).",
+ s.gotConn.IdleTime.Round(time.Second))
+ s.emitf("# Silently closed the conn while it sat in the idle pool.")
+ s.emitf("# Consider lowering http.Transport.IdleConnTimeout to evict")
+ s.emitf("# pooled conns before the NAT/server side does.")
+ }
+}
+
+// ---------------------------------------------------------------
+// Emission helpers
+// ---------------------------------------------------------------
+
+// emitf prints a plain event line (no t= timestamp). Used for the
+// opening line and the summary.
+func (s *traceSession) emitf(format string, args ...any) {
+ s.logger.Debugf(tracePrefix+format, args...)
+}
+
+// emitRaw is like emitf but takes an already-rendered string. Used
+// by finish() which builds its line via strings.Builder.
+func (s *traceSession) emitRaw(line string) {
+ s.logger.Debugf("%s", tracePrefix+line)
+}
+
+// emitTf prints a phase event with a cumulative t=... offset from
+// the session start.
+func (s *traceSession) emitTf(format string, args ...any) {
+ t := round(time.Since(s.start))
+ msg := fmt.Sprintf(format, args...)
+ s.logger.Debugf(tracePrefix+"%s (t=%s)", msg, t)
+}
+
+// traceRoundUnit is the rounding granularity for >=1ms durations
+// rendered in trace output. 100µs keeps lines readable while
+// preserving enough resolution to spot millisecond-scale phase
+// differences.
+const traceRoundUnit = 100 * time.Microsecond
+
+// round trims durations for human-readable trace output.
+// Sub-millisecond durations round to 1µs (preserves visibility on
+// fast loopback servers); >=1ms durations round to [traceRoundUnit].
+func round(d time.Duration) time.Duration {
+ if d <= 0 {
+ return 0
+ }
+ if d < time.Millisecond {
+ return d.Round(time.Microsecond)
+ }
+ return d.Round(traceRoundUnit)
+}
+
+// ---------------------------------------------------------------
+// TLS rendering helpers
+// ---------------------------------------------------------------
+
+func tlsVersionName(v uint16) string {
+ switch v {
+ case tls.VersionTLS10:
+ return "1.0"
+ case tls.VersionTLS11:
+ return "1.1"
+ case tls.VersionTLS12:
+ return "1.2"
+ case tls.VersionTLS13:
+ return "1.3"
+ default:
+ return fmt.Sprintf("0x%04x", v)
+ }
+}
+
+// certExpiryFragment renders ", expires=YYYY-MM-DD" for the leaf
+// cert when available, or an empty string otherwise.
+func certExpiryFragment(state tls.ConnectionState) string {
+ if len(state.PeerCertificates) == 0 {
+ return ""
+ }
+ return ", expires=" + state.PeerCertificates[0].NotAfter.UTC().Format("2006-01-02")
+}
diff --git a/vendor/github.com/go-openapi/runtime/client/httptrace_tls.go b/vendor/github.com/go-openapi/runtime/client/httptrace_tls.go
new file mode 100644
index 00000000000..063fb259272
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/client/httptrace_tls.go
@@ -0,0 +1,353 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package client
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "net/http"
+ "strings"
+ "time"
+)
+
+// TLS alert codes used by the diagnostic to classify handshake
+// failures. The crypto/tls package does not export named constants
+// for individual alerts, so we declare the ones we care about.
+// Values are from RFC 8446 §6 (the TLS 1.3 alert protocol; the
+// numbering is shared with earlier TLS versions for these alerts).
+//
+// The `err`-prefixed names satisfy the errname linter — tls.AlertError
+// implements error, so these are sentinel errors.
+const (
+ errTLSAlertHandshakeFailure tls.AlertError = 40
+ errTLSAlertProtocolVersion tls.AlertError = 70
+)
+
+// introspectTLSConfig returns the *tls.Config of the http.Transport
+// that will run a request, when reachable, or nil otherwise.
+//
+// Reachable means the client's Transport is an *http.Transport
+// (the default and most common case). Custom transports — wrappers
+// around the default, or entirely user-provided — break introspection;
+// the TLS diagnostic falls back to "configured: not introspectable"
+// in that case.
+//
+// A nil client (zero value) or nil Transport falls through to
+// [http.DefaultTransport], whose TLSClientConfig is also nil; the
+// function returns nil and the diagnostic reports defaults.
+func introspectTLSConfig(client *http.Client) *tls.Config {
+ if client == nil {
+ return nil
+ }
+ transport := client.Transport
+ if transport == nil {
+ transport = http.DefaultTransport
+ }
+ t, ok := transport.(*http.Transport)
+ if !ok {
+ return nil
+ }
+ return t.TLSClientConfig
+}
+
+// emitTLSDiagnostic renders the failure-mode TLS diagnostic block.
+// Called from [traceSession.onTLSHandshakeDone] when err != nil.
+//
+// The block covers three axes (per the plan):
+//
+// 1. Protocol-version negotiation — detected from
+// [errTLSAlertProtocolVersion] or a "protocol version" substring.
+// 2. Cipher-suite negotiation — detected from
+// [errTLSAlertHandshakeFailure] when the user pinned CipherSuites.
+// 3. Certificate-chain validity — detected from
+// [x509.CertificateInvalidError], [x509.UnknownAuthorityError]
+// or [x509.HostnameError].
+//
+// When none of the specific axes match, a generic fallback emits
+// the raw error and whatever inspectable config the session holds.
+func (s *traceSession) emitTLSDiagnostic(state tls.ConnectionState, err error) {
+ s.emitf("# TLS DIAGNOSTIC")
+
+ // tlsAxisGeneric is handled by the default branch.
+ switch axis := classifyTLSError(err); axis {
+ case tlsAxisProtocolVersion:
+ s.diagnoseProtocolVersion(state, err)
+ case tlsAxisCipher:
+ s.diagnoseCipher(err)
+ case tlsAxisCertChain:
+ s.diagnoseCertChain(err)
+ default:
+ s.diagnoseTLSGeneric(err)
+ }
+}
+
+// tlsAxis is the diagnostic dimension a TLS handshake error maps
+// to. Axes are mutually exclusive at classification time.
+type tlsAxis int
+
+const (
+ tlsAxisGeneric tlsAxis = iota
+ tlsAxisProtocolVersion
+ tlsAxisCipher
+ tlsAxisCertChain
+)
+
+// classifyTLSError maps a TLS handshake error to one of the
+// diagnostic axes. The ordering matters: cert-chain errors win
+// over the generic handshake_failure alert because the alert is
+// what the server sends back, but the local error type carries
+// the more specific reason.
+func classifyTLSError(err error) tlsAxis {
+ if err == nil {
+ return tlsAxisGeneric
+ }
+
+ // Cert-chain errors are the most specific local diagnostic
+ // and should be reported even if a generic alert is also
+ // present in the chain.
+ var certInvalid x509.CertificateInvalidError
+ if errors.As(err, &certInvalid) {
+ return tlsAxisCertChain
+ }
+ var unknownAuth x509.UnknownAuthorityError
+ if errors.As(err, &unknownAuth) {
+ return tlsAxisCertChain
+ }
+ var hostnameErr x509.HostnameError
+ if errors.As(err, &hostnameErr) {
+ return tlsAxisCertChain
+ }
+
+ // TLS alert classification.
+ var alert tls.AlertError
+ if errors.As(err, &alert) {
+ switch alert {
+ case errTLSAlertProtocolVersion:
+ return tlsAxisProtocolVersion
+ case errTLSAlertHandshakeFailure:
+ return tlsAxisCipher
+ }
+ }
+
+ // Fall back on substring detection for protocol-version
+ // failures that arrive via the local error path rather than
+ // a server-side alert (e.g. when the client refuses the
+ // server's offered version).
+ msg := err.Error()
+ if strings.Contains(msg, "protocol version") || strings.Contains(msg, "unsupported protocol") {
+ return tlsAxisProtocolVersion
+ }
+
+ return tlsAxisGeneric
+}
+
+// ---------------------------------------------------------------
+// Axis renderers
+// ---------------------------------------------------------------
+
+func (s *traceSession) diagnoseProtocolVersion(state tls.ConnectionState, err error) {
+ s.emitf("# axis: protocol-version")
+ s.emitf("# error: %v", err)
+
+ configuredMin, configuredMax := configuredVersionRange(s.tlsCfg)
+ s.emitf("# client offered: TLS %s — TLS %s",
+ tlsVersionName(configuredMin), tlsVersionName(configuredMax))
+
+ if state.Version != 0 {
+ s.emitf("# negotiated up to: TLS %s", tlsVersionName(state.Version))
+ }
+ s.emitf("# suggested: widen TLSClientOptions.MinVersion/MaxVersion,")
+ s.emitf("# or pin to a version the server speaks.")
+}
+
+func (s *traceSession) diagnoseCipher(err error) {
+ s.emitf("# axis: cipher-suite")
+ s.emitf("# error: %v", err)
+
+ if s.tlsCfg != nil && len(s.tlsCfg.CipherSuites) > 0 {
+ s.emitf("# client configured: [%s]",
+ strings.Join(cipherSuiteNames(s.tlsCfg.CipherSuites), ", "))
+ s.emitf("# server set: not exposed by Go stdlib")
+ s.emitf("# (capture with: openssl s_client -cipher ALL)")
+ s.emitf("# suggested: drop the explicit CipherSuites restriction,")
+ s.emitf("# or align it with the server's policy.")
+ return
+ }
+ // No client-side restriction. The handshake_failure alert
+ // is generic; without more info we can only surface the
+ // fact and suggest investigation.
+ s.emitf("# client configured: defaults (no CipherSuites restriction)")
+ s.emitf("# note: alert 40 is generic; the server may have rejected")
+ s.emitf("# the handshake for a non-cipher reason. Try")
+ s.emitf("# openssl s_client to capture details.")
+}
+
+func (s *traceSession) diagnoseCertChain(err error) {
+ s.emitf("# axis: cert-chain")
+
+ var certInvalid x509.CertificateInvalidError
+ if errors.As(err, &certInvalid) {
+ s.diagnoseCertInvalid(certInvalid)
+ return
+ }
+
+ var unknownAuth x509.UnknownAuthorityError
+ if errors.As(err, &unknownAuth) {
+ s.diagnoseUnknownAuthority(unknownAuth)
+ return
+ }
+
+ var hostnameErr x509.HostnameError
+ if errors.As(err, &hostnameErr) {
+ s.diagnoseHostnameMismatch(hostnameErr)
+ return
+ }
+
+ // Defensive: should not happen — classifyTLSError already
+ // matched one of the three.
+ s.emitf("# error: %v", err)
+}
+
+func (s *traceSession) diagnoseCertInvalid(certInvalid x509.CertificateInvalidError) {
+ cert := certInvalid.Cert
+ s.emitf("# reason: %s", certInvalidReasonName(certInvalid.Reason))
+
+ switch certInvalid.Reason {
+ case x509.Expired:
+ s.emitf("# leaf: subject=%s", cert.Subject)
+ s.emitf("# NotBefore=%s", cert.NotBefore.UTC().Format(time.RFC3339))
+ s.emitf("# NotAfter=%s", cert.NotAfter.UTC().Format(time.RFC3339))
+ s.emitf("# now=%s", time.Now().UTC().Format(time.RFC3339))
+ delta := time.Since(cert.NotAfter).Round(time.Hour)
+ s.emitf("# expired %s ago", delta)
+ s.emitf("# suggested: renew the server cert.")
+ case x509.NameMismatch, x509.CANotAuthorizedForThisName:
+ s.emitf("# leaf: subject=%s", cert.Subject)
+ s.emitf("# DNS SANs=%v", cert.DNSNames)
+ s.emitf("# suggested: set TLSClientOptions.ServerName to match")
+ s.emitf("# one of the cert SANs, or fix the cert.")
+ default:
+ // Less-common reasons render via the default branch (issuer + NotAfter dump).
+ s.emitf("# leaf: subject=%s, issuer=%s", cert.Subject, cert.Issuer)
+ s.emitf("# NotBefore=%s", cert.NotBefore.UTC().Format(time.RFC3339))
+ s.emitf("# NotAfter=%s", cert.NotAfter.UTC().Format(time.RFC3339))
+ s.emitf("# error: %v", certInvalid)
+ }
+}
+
+func (s *traceSession) diagnoseUnknownAuthority(unknownAuth x509.UnknownAuthorityError) {
+ s.emitf("# reason: chain root not in trust store (unknown-CA)")
+ if cert := unknownAuth.Cert; cert != nil {
+ s.emitf("# offending: subject=%s", cert.Subject)
+ s.emitf("# issuer=%s", cert.Issuer)
+ s.emitf("# NotAfter=%s", cert.NotAfter.UTC().Format(time.RFC3339))
+ }
+
+ trust := "SystemCertPool"
+ if s.tlsCfg != nil && s.tlsCfg.RootCAs != nil {
+ trust = "TLSClientOptions.CA (custom RootCAs)"
+ }
+ s.emitf("# trust store in use: %s", trust)
+
+ s.emitf("# suggested: set TLSClientOptions.CA to a bundle that")
+ s.emitf("# includes the issuing CA, or add it to the")
+ s.emitf("# OS trust store.")
+}
+
+func (s *traceSession) diagnoseHostnameMismatch(hostnameErr x509.HostnameError) {
+ s.emitf("# reason: hostname mismatch")
+ s.emitf("# dialed: %s", hostnameErr.Host)
+ if cert := hostnameErr.Certificate; cert != nil {
+ s.emitf("# leaf: subject=%s", cert.Subject)
+ s.emitf("# DNS SANs=%v", cert.DNSNames)
+ s.emitf("# IP SANs=%v", cert.IPAddresses)
+ }
+ if s.tlsCfg != nil && s.tlsCfg.ServerName != "" {
+ s.emitf("# TLSClientOptions.ServerName=%q", s.tlsCfg.ServerName)
+ }
+ s.emitf("# suggested: dial the hostname listed in the cert SANs,")
+ s.emitf("# or set TLSClientOptions.ServerName to match.")
+}
+
+func (s *traceSession) diagnoseTLSGeneric(err error) {
+ s.emitf("# axis: unclassified")
+ s.emitf("# error: %v", err)
+ if s.tlsCfg != nil {
+ minV, maxV := configuredVersionRange(s.tlsCfg)
+ s.emitf("# configured: MinVersion=TLS %s, MaxVersion=TLS %s",
+ tlsVersionName(minV), tlsVersionName(maxV))
+ if s.tlsCfg.InsecureSkipVerify {
+ s.emitf("# note: TLSClientOptions.InsecureSkipVerify=true — yet")
+ s.emitf("# a TLS error still surfaced. Something deeper than")
+ s.emitf("# certificate verification is failing.")
+ }
+ }
+}
+
+// ---------------------------------------------------------------
+// Helpers
+// ---------------------------------------------------------------
+
+// configuredVersionRange returns the effective (Min, Max) TLS
+// version range a client config negotiates. Zero values in the
+// stdlib config mean "use Go default", which is TLS 1.2 .. 1.3 in
+// modern Go. We materialize those defaults for display.
+func configuredVersionRange(cfg *tls.Config) (uint16, uint16) {
+ const (
+ defaultMin = tls.VersionTLS12
+ defaultMax = tls.VersionTLS13
+ )
+ if cfg == nil {
+ return defaultMin, defaultMax
+ }
+ minV := cfg.MinVersion
+ if minV == 0 {
+ minV = defaultMin
+ }
+ maxV := cfg.MaxVersion
+ if maxV == 0 {
+ maxV = defaultMax
+ }
+ return minV, maxV
+}
+
+func cipherSuiteNames(ids []uint16) []string {
+ out := make([]string, 0, len(ids))
+ for _, id := range ids {
+ out = append(out, tls.CipherSuiteName(id))
+ }
+ return out
+}
+
+// certInvalidReasonName renders an x509.InvalidReason as a short
+// human-readable label. The stdlib does not expose a String()
+// method for these, so we keep a small table.
+//
+// Anything outside the listed cases falls through to the numeric default.
+func certInvalidReasonName(r x509.InvalidReason) string {
+ switch r {
+ case x509.NotAuthorizedToSign:
+ return "not-authorized-to-sign"
+ case x509.Expired:
+ return "expired"
+ case x509.CANotAuthorizedForThisName:
+ return "ca-not-authorized-for-this-name"
+ case x509.TooManyIntermediates:
+ return "too-many-intermediates"
+ case x509.IncompatibleUsage:
+ return "incompatible-usage"
+ case x509.NameMismatch:
+ return "name-mismatch"
+ case x509.NameConstraintsWithoutSANs:
+ return "name-constraints-without-sans"
+ case x509.TooManyConstraints:
+ return "too-many-constraints"
+ case x509.CANotAuthorizedForExtKeyUsage:
+ return "ca-not-authorized-for-ext-key-usage"
+ default:
+ return fmt.Sprintf("invalid-reason-%d", r)
+ }
+}
diff --git a/vendor/github.com/go-openapi/runtime/client/internal/request/request.go b/vendor/github.com/go-openapi/runtime/client/internal/request/request.go
new file mode 100644
index 00000000000..22d3f64c01b
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/client/internal/request/request.go
@@ -0,0 +1,945 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package request
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "mime"
+ "mime/multipart"
+ "net/http"
+ "net/textproto"
+ "net/url"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "github.com/go-openapi/runtime"
+ "github.com/go-openapi/strfmt"
+)
+
+var _ runtime.ClientRequest = new(Request) // ensure compliance to the interface
+
+// Request represents a swagger client request.
+// It binds parameters to a HTTP request.
+//
+// The main purpose of this struct is to hide the machinery of adding OpenAPI v2 parameters to a transport request.
+//
+// A generated client only implements what is necessary to turn a parameter into a valid value for these methods.
+//
+// There is no parameter validation here, it is assumed to be used after a spec has been validated.
+//
+// # Request binding
+//
+// The binding of parameters is carried out by method [Request.BuildHTTPContext].
+//
+// It analyzes parameters, which may come in different flavors:
+//
+// - a file or multipart form containing a file
+// - a body which is a [io.Reader]
+// - a buffered body (regular schema body, including urlencoded form)
+//
+// In all cases, we may also have query or path parameters encoded in the URL, or header parameters.
+//
+// The result is a [http.Request], with the following properties:
+//
+// - file, multipart form or [io.Reader] body: a streaming request with an attached go routine that consumes the [io.Reader].
+// - buffered body: a simple request
+//
+// The caller passes the parent [context.Context] to [Request.BuildHTTPContext] and receives back a cancel
+// function to release the resources held by the derived request context once the response is consumed.
+//
+// # Authentication
+//
+// Authentication is built in the request by using a [runtime.ClientAuthInfoWriter].
+// This helper may need to inspect the body of the request before sending authentication info.
+// To cover that case, streaming bodies use a copy of the body [io.Reader] for the [runtime.ClientAuthInfoWriter]
+// to consume if it wants to.
+//
+// # Content negotiation
+//
+// The [Request] detects `multipart/form-data` to switch to streamed request.
+//
+// `application/x-www-form-urlencoded` is also honored, even for file parameters, which are not streamed in this case.
+// File parameters default behavior is `multipart/form-data`.
+//
+// The natural way to define the `Content-Type` header is to use the `contentType` parameter to switch to the map of
+// available body producers.
+//
+// For buffered requests, this setting override any `Content-Type` header possibly set by calling [Request.SetHeaderParam].
+//
+// For streamed requests, users may want more flexibility, as we enter custom territory, with use-cases not supported by OpenAPI v2.
+//
+// The `Content-Type` header of a streamed request is defined using the following sequence:
+//
+// 1. if the caller sets an explicit value already in header — the user set it via
+// [Request.SetHeaderParam] during WriteToRequest, and we treat that as an intentional escape hatch
+// 2. use payload's [runtime.ContentTyper] declaration (in this case, the produced payload knows its content type)
+// 3. use `application/octet-stream` if it is available in the registered producers
+// 4. otherwise set the picker's mediaType
+//
+// For multi-part requests, the content type of each part is auto-detected using the following sequence:
+//
+// 1. use [runtime.ContentTyper] declaration (in this case, the file payload knows its content type)
+// 2. use [http.DetectContentType] on the first 512 bytes of the file
+//
+// # Concurrency
+//
+// A [Request] is a disposable object that is NOT intended to be reused or called concurrently.
+//
+// # Future evolutions
+//
+// There might be other similar structs that convert to other transports.
+type Request struct {
+ pathPattern string
+ method string
+ writer runtime.ClientRequestWriter
+
+ pathParams map[string]string
+ header http.Header
+ query url.Values
+ formFields url.Values
+ fileFields map[string][]runtime.NamedReadCloser
+ payload any
+ // consumes carries the operation's full ConsumesMediaTypes list so
+ // that buildHTTP — which runs after the writer populates the payload
+ // — can apply payload-aware fallback rules (see streamFallbackMime).
+ //
+ // This is set by Runtime.createHttpRequest.
+ consumes []string
+ timeout time.Duration
+ buf *bytes.Buffer
+
+ getBody func(r *Request) []byte
+}
+
+// New creates a new http client [Request] to handle OpenAPI v2 parameters.
+func New(method, pathPattern string, writer runtime.ClientRequestWriter) *Request {
+ return &Request{
+ pathPattern: pathPattern,
+ method: method,
+ writer: writer,
+ header: make(http.Header),
+ query: make(url.Values),
+ timeout: 0,
+ getBody: getRequestBuffer,
+ }
+}
+
+// GetMethod yields the method being used.
+func (r *Request) GetMethod() string {
+ return r.method
+}
+
+// GetPath yields the URL path being used.
+func (r *Request) GetPath() string {
+ pth := r.pathPattern
+ for k, v := range r.pathParams {
+ pth = strings.ReplaceAll(pth, "{"+k+"}", v)
+ }
+
+ return pth
+}
+
+// GetBody returns the request body, if any.
+//
+// For streaming requests, this is a copy of the original [io.Reader].
+func (r *Request) GetBody() []byte {
+ return r.getBody(r)
+}
+
+// SetHeaderParam adds a header parameter to the request.
+//
+// The header key is always canonicalized.
+//
+// - when there is only 1 value provided, it will set it.
+// - when there are several values provided, it will add all of those (no overriding).
+func (r *Request) SetHeaderParam(name string, values ...string) error {
+ if r.header == nil {
+ r.header = make(http.Header)
+ }
+ r.header[http.CanonicalHeaderKey(name)] = values
+
+ return nil
+}
+
+// GetHeaderParams returns all headers currently set for the request.
+func (r *Request) GetHeaderParams() http.Header {
+ return r.header
+}
+
+// SetQueryParam adds a query parameter to the request.
+//
+// - when there is only 1 value provided, it will set it.
+// - when there are several values provided, it will add all of those (no overriding).
+func (r *Request) SetQueryParam(name string, values ...string) error {
+ if r.query == nil {
+ r.query = make(url.Values)
+ }
+ r.query[name] = values
+
+ return nil
+}
+
+// GetQueryParams returns a copy of all query params currently set for the request.
+func (r *Request) GetQueryParams() url.Values {
+ result := make(url.Values, len(r.query))
+ for key, values := range r.query {
+ result[key] = append([]string{}, values...)
+ }
+
+ return result
+}
+
+// SetFormParam adds a form param to the request.
+//
+// - when there is only 1 value provided, it will set it.
+// - when there are several values provided, it will add all of those (no overriding).
+func (r *Request) SetFormParam(name string, values ...string) error {
+ if r.formFields == nil {
+ r.formFields = make(url.Values)
+ }
+ r.formFields[name] = values
+
+ return nil
+}
+
+// SetPathParam adds a path param to the request.
+func (r *Request) SetPathParam(name string, value string) error {
+ if r.pathParams == nil {
+ r.pathParams = make(map[string]string)
+ }
+
+ r.pathParams[name] = value
+
+ return nil
+}
+
+// SetFileParam adds a file parameter to the request.
+//
+// Files must implement [runtime.NamedReadCloser].
+//
+// [runtime.File] is proposed as the default concrete implementation.
+func (r *Request) SetFileParam(name string, files ...runtime.NamedReadCloser) error {
+ for _, file := range files {
+ if actualFile, ok := file.(*os.File); ok {
+ fi, err := os.Stat(actualFile.Name())
+ if err != nil {
+ return err
+ }
+
+ if fi.IsDir() {
+ return fmt.Errorf("%q is a directory, only files are supported", file.Name())
+ }
+ }
+ }
+
+ if r.fileFields == nil {
+ r.fileFields = make(map[string][]runtime.NamedReadCloser)
+ }
+
+ if r.formFields == nil {
+ r.formFields = make(url.Values)
+ }
+
+ r.fileFields[name] = files
+
+ return nil
+}
+
+// GetFileParam yields all file parameters.
+func (r *Request) GetFileParam() map[string][]runtime.NamedReadCloser {
+ return r.fileFields
+}
+
+// SetBodyParam sets a body parameter on the request.
+//
+// This does not yet serialize the object: actual serialization happens as late as possible.
+func (r *Request) SetBodyParam(payload any) error {
+ r.payload = payload
+
+ return nil
+}
+
+// GetBodyParam returns the body payload.
+func (r *Request) GetBodyParam() any {
+ return r.payload
+}
+
+// GetTimeout sets the timeout for a request.
+func (r *Request) GetTimeout() time.Duration {
+ return r.timeout
+}
+
+// SetTimeout sets the timeout for a request.
+func (r *Request) SetTimeout(timeout time.Duration) error {
+ r.timeout = timeout
+
+ return nil
+}
+
+// SetConsumes sets the list of registered consumed content for a request.
+func (r *Request) SetConsumes(consumers []string) {
+ r.consumes = consumers
+}
+
+// BuildHTTPContext binds the request parameters and returns a ready-to-send [http.Request].
+//
+// Dispatch picks one of two end-to-end builders based on whether:
+//
+// - the body source is a stream (multipart pipe or stream payload)
+// - or a buffer (urlencoded form, producer output, or no body)
+//
+// It starts by writing the request, then proceed with adding authentication,
+// then finally assembling URL or header parameters.
+//
+// The split mirrors the auth question: streaming bodies require a lazy body-copy closure during [AuthenticateRequest],
+// whereas buffered bodies do not.
+//
+// The returned [http.Request] carries a context derived from parentCtx that:
+//
+// - inherits any deadline or cancellation already set on parentCtx;
+// - additionally honors the per-request timeout set via [Request.SetTimeout]
+// (the [runtime.ClientRequestWriter] may override the runtime default during
+// WriteToRequest, which is why the derivation happens here rather than
+// at the call site).
+//
+// The returned cancel must be invoked by the caller (typically deferred)
+// once the response has been fully read; otherwise resources held by the
+// derived context — including any timeout timer — are leaked.
+//
+// On error the cancel is invoked internally and a no-op cancel is returned,
+// so callers can defer cancel unconditionally.
+func (r *Request) BuildHTTPContext(parentCtx context.Context, mediaType, basePath string,
+ producers map[string]runtime.Producer, registry strfmt.Registry, auth runtime.ClientAuthInfoWriter,
+) (*http.Request, context.CancelFunc, error) {
+ if err := r.writer.WriteToRequest(r, registry); err != nil {
+ return nil, noop, err
+ }
+
+ ctx, cancel := deriveRequestContext(parentCtx, r.timeout)
+ r.buf = bytes.NewBuffer(nil)
+
+ var (
+ httpReq *http.Request
+ err error
+ )
+ if r.usesStreamingBody(mediaType) {
+ httpReq, err = r.buildStreamingRequest(ctx, mediaType, basePath, producers, registry, auth)
+ } else {
+ httpReq, err = r.buildBufferedRequest(ctx, mediaType, basePath, producers, registry, auth)
+ }
+ if err != nil {
+ cancel()
+ return nil, noop, err
+ }
+ return httpReq, cancel, nil
+}
+
+func noop() {}
+
+// deriveRequestContext returns a child of parent bounded by timeout.
+// If timeout == 0 the child is only canceled when the caller invokes
+// cancel; any deadline already on parent is preserved. If timeout > 0
+// the child uses the shortest of timeout and parent's existing deadline.
+func deriveRequestContext(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
+ if timeout == 0 {
+ return context.WithCancel(parent)
+ }
+ return context.WithTimeout(parent, timeout)
+}
+
+// usesStreamingBody reports whether the request body must be assembled
+// as a stream (an io.Pipe for multipart, or the payload's own reader
+// for stream payloads).
+//
+// The complementary case is a fully buffered body in r.buf — urlencoded form, producer output, or no body at all.
+func (r *Request) usesStreamingBody(mediaType string) bool {
+ if (len(r.formFields) > 0 || len(r.fileFields) > 0) && r.isMultipart(mediaType) {
+ return true
+ }
+
+ if r.payload != nil {
+ if _, ok := r.payload.(io.Reader); ok {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (r *Request) isMultipart(mediaType string) bool {
+ // Strip media-type parameters before comparing: callers may legally
+ // pass `multipart/form-data; boundary=…` or
+ // `application/x-www-form-urlencoded; charset=utf-8` per RFC 7231,
+ // and a bare-string compare would route those to the wrong flow.
+ //
+ // mime.ParseMediaType lowercases the type/subtype and is
+ // case-insensitive on input, so plain == against our (lowercase)
+ // constants is sufficient on the happy path.
+ base, _, err := mime.ParseMediaType(mediaType)
+ if err != nil {
+ // Malformed mediaType: only the file-presence shortcut can
+ // fire — by definition we cannot recognize either canonical
+ // form mime in unparseable input.
+ return len(r.fileFields) > 0
+ }
+
+ // An explicit application/x-www-form-urlencoded choice is honored even when
+ // file fields are present: the spec allows files to travel as URL-encoded
+ // form values, although it does not stream and is discouraged. Without this
+ // short-circuit, picking urlencoded with files would silently fall back to
+ // multipart and emit an inconsistent Content-Type.
+ if base == runtime.URLencodedFormMime {
+ return false
+ }
+
+ if len(r.fileFields) > 0 {
+ return true
+ }
+
+ return base == runtime.MultipartFormMime
+}
+
+// buildBufferedRequest assembles a request whose body is fully
+// buffered in r.buf before AuthenticateRequest runs — urlencoded form,
+// producer-serialized payload, or no body.
+//
+// Auth is trivial in this flow because the buffer is already populated when the auth helper
+// asks for the body via r.GetBody().
+func (r *Request) buildBufferedRequest(ctx context.Context, mediaType, basePath string,
+ producers map[string]runtime.Producer, registry strfmt.Registry, auth runtime.ClientAuthInfoWriter,
+) (*http.Request, error) {
+ var body io.Reader
+ var err error
+
+ switch {
+ case len(r.formFields) > 0 || len(r.fileFields) > 0:
+ body, err = r.writeURLEncodedBody(mediaType)
+ case r.payload != nil:
+ body, err = r.writeNonStreamPayload(mediaType, producers)
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ if runtime.CanHaveBody(r.method) && body != nil && r.header.Get(runtime.HeaderContentType) == "" {
+ r.header.Set(runtime.HeaderContentType, mediaType)
+ }
+
+ if auth != nil {
+ if err := auth.AuthenticateRequest(r, registry); err != nil {
+ return nil, err
+ }
+ }
+
+ return r.assembleRequest(ctx, basePath, body)
+}
+
+// buildStreamingRequest assembles a request whose body is a stream —
+// either an io.Pipe filled by the multipart goroutine, or the
+// payload's own io.Reader.
+//
+// AuthenticateRequest consumes the body lazily through the getBody closure installed by
+// applyAuthWithBodyCopy, which buffers the stream into r.buf so the http.Request can use the buffered copy.
+//
+// On any error path before the http.Request takes ownership of body, we close the body to release
+// the underlying resource.
+//
+// For multipart this unblocks the spawned writer goroutine
+// (it would otherwise park forever on pw.Write with no reader).
+//
+// For stream payloads it closes the user-provided io.ReadCloser.
+func (r *Request) buildStreamingRequest(ctx context.Context, mediaType, basePath string,
+ producers map[string]runtime.Producer, registry strfmt.Registry, auth runtime.ClientAuthInfoWriter,
+) (req *http.Request, retErr error) {
+ var body io.Reader
+ if len(r.formFields) > 0 || len(r.fileFields) > 0 {
+ body = r.writeMultipartBody(ctx, mediaType)
+ } else {
+ body = r.writeStreamPayload(mediaType, producers)
+ }
+
+ defer func() {
+ if retErr == nil {
+ return
+ }
+ if c, ok := body.(io.Closer); ok {
+ _ = c.Close()
+ }
+ }()
+
+ if runtime.CanHaveBody(r.method) && body != nil && r.header.Get(runtime.HeaderContentType) == "" {
+ r.header.Set(runtime.HeaderContentType, mediaType)
+ }
+
+ body, err := r.applyAuthWithBodyCopy(auth, body, registry)
+ if err != nil {
+ return nil, err
+ }
+
+ return r.assembleRequest(ctx, basePath, body)
+}
+
+// assembleRequest is the shared tail of both flows: build the URL
+// path, create the http.Request, merge static query parameters, and
+// finalize headers/query.
+func (r *Request) assembleRequest(ctx context.Context, basePath string, body io.Reader) (*http.Request, error) {
+ urlPath, staticQueryParams, err := r.resolveURLPath(basePath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequestWithContext(ctx, r.method, urlPath, body)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := r.mergeStaticQuery(staticQueryParams); err != nil {
+ return nil, err
+ }
+
+ req.URL.RawQuery = r.query.Encode()
+ req.Header = r.header
+
+ return req, nil
+}
+
+// resolveURLPath builds the final url path string and returns the static
+// query parameters extracted from basePath and r.pathPattern.
+//
+// Static query parameters from the path pattern take precedence over those
+// from the base path; merging with r.query is the caller's responsibility
+// (see [request.mergeStaticQuery]).
+//
+// The path is assembled from basePath + pathPattern with path-param
+// substitution and trailing-slash preservation when the original
+// pathPattern carried one.
+func (r *Request) resolveURLPath(basePath string) (string, url.Values, error) {
+ basePathURL, err := url.Parse(basePath)
+ if err != nil {
+ return "", nil, err
+ }
+ staticQueryParams := basePathURL.Query()
+
+ pathPatternURL, err := url.Parse(r.pathPattern)
+ if err != nil {
+ return "", nil, err
+ }
+ for name, values := range pathPatternURL.Query() {
+ if _, present := staticQueryParams[name]; present {
+ staticQueryParams.Del(name)
+ }
+ for _, value := range values {
+ staticQueryParams.Add(name, value)
+ }
+ }
+
+ // path.Join strips trailing slashes; reinstate one whenever the
+ // pathPattern carried it, including the bare-root case ("/" under a
+ // non-empty basePath, which path.Join would collapse to "/basepath").
+ // The HasSuffix check on urlPath keeps the rewrite idempotent and
+ // avoids producing "//" when basePath is "/" or empty.
+ reinstateSlash := strings.HasSuffix(pathPatternURL.Path, "/")
+
+ urlPath := path.Join(basePathURL.Path, pathPatternURL.Path)
+ for k, v := range r.pathParams {
+ urlPath = strings.ReplaceAll(urlPath, "{"+k+"}", url.PathEscape(v))
+ }
+ if reinstateSlash && !strings.HasSuffix(urlPath, "/") {
+ urlPath += "/"
+ }
+
+ return urlPath, staticQueryParams, nil
+}
+
+// applyAuthWithBodyCopy runs auth.AuthenticateRequest for the
+// streaming flow, where the http.Request body is a pipe or a payload
+// reader rather than r.buf. If AuthenticateRequest asks for the body
+// via r.GetBody(), the lazy closure copies the stream into r.buf on
+// demand and reassigns body to r.buf so the post-auth source passed
+// to http.NewRequestWithContext is the buffered copy.
+//
+// The closure is registered lazily because there is no way to know
+// ahead of time whether AuthenticateRequest will read the body.
+//
+// On error precedence: a copy error is reported in preference to the
+// AuthenticateRequest error, because a mis-read body may have
+// interfered with auth.
+//
+// No-op when auth is nil; returns body unchanged.
+func (r *Request) applyAuthWithBodyCopy(auth runtime.ClientAuthInfoWriter, body io.Reader, registry strfmt.Registry) (io.Reader, error) {
+ if auth == nil {
+ return body, nil
+ }
+
+ var copyErr error
+ var copied bool
+ r.getBody = func(r *Request) []byte {
+ if copied {
+ return getRequestBuffer(r)
+ }
+
+ defer func() {
+ copied = true
+ }()
+
+ if _, copyErr = io.Copy(r.buf, body); copyErr != nil {
+ return nil
+ }
+
+ if closer, ok := body.(io.ReadCloser); ok {
+ if copyErr = closer.Close(); copyErr != nil {
+ return nil
+ }
+ }
+
+ body = r.buf
+ return getRequestBuffer(r)
+ }
+
+ authErr := auth.AuthenticateRequest(r, registry)
+
+ // On error we return body alongside the error so the caller's
+ // cleanup defer (in buildStreamingRequest) can close the
+ // underlying pipe/stream. Caller treats body as ignorable when
+ // err != nil per Go convention; the defer reads it via closure.
+ if copyErr != nil {
+ return body, fmt.Errorf("error copying the request body: %w", copyErr)
+ }
+
+ if authErr != nil {
+ return body, authErr
+ }
+
+ return body, nil
+}
+
+// mergeStaticQuery overlays staticQuery onto r.query. On conflict r.query
+// wins — the parameters set by the client take precedence over the ones
+// extracted from basePath / pathPattern.
+func (r *Request) mergeStaticQuery(staticQuery url.Values) error {
+ originalParams := r.GetQueryParams()
+ for k, v := range staticQuery {
+ if _, present := originalParams[k]; present {
+ continue
+ }
+ if err := r.SetQueryParam(k, v...); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// writeURLEncodedBody serializes form fields (and any file fields, per
+// Swagger 2.0 fallback semantics) into r.buf as
+// application/x-www-form-urlencoded. Sets Content-Type to mediaType and
+// returns r.buf as the body source.
+//
+// Per Swagger 2.0, file form parameters can be sent under
+// application/x-www-form-urlencoded by including the file content as a
+// regular form-field value. The whole form is then percent-encoded as
+// usual. This buffers the entire payload and does not preserve a
+// per-file Content-Type — multipart/form-data is preferred when both
+// are advertised by the operation.
+func (r *Request) writeURLEncodedBody(mediaType string) (io.Reader, error) {
+ r.header.Set(runtime.HeaderContentType, mediaType)
+ values := url.Values{}
+ for k, vs := range r.formFields {
+ values[k] = append(values[k], vs...)
+ }
+ for fn, ff := range r.fileFields {
+ for _, fi := range ff {
+ data, ferr := io.ReadAll(fi)
+ if cerr := fi.Close(); cerr != nil && ferr == nil {
+ ferr = cerr
+ }
+ if ferr != nil {
+ return nil, ferr
+ }
+ values.Add(fn, string(data))
+ }
+ }
+ r.buf.WriteString(values.Encode())
+ return r.buf, nil
+}
+
+// writeMultipartBody assembles a multipart/form-data body via an
+// io.Pipe. A goroutine streams form fields and files into the pipe
+// writer; the pipe reader is returned as the body. Sets Content-Type to
+// the multipart media type with the writer's boundary parameter.
+//
+// The goroutine owns the pipe writer's lifecycle: it closes the
+// multipart writer (flushing the closing boundary) and the pipe writer
+// when it finishes or hits an error.
+func (r *Request) writeMultipartBody(ctx context.Context, mediaType string) io.Reader {
+ pr, pw := io.Pipe()
+ mp := multipart.NewWriter(pw)
+ r.header.Set(runtime.HeaderContentType, mangleContentType(mediaType, mp.Boundary()))
+
+ go r.streamMultipartParts(ctx, mp, pw)
+
+ return pr
+}
+
+// streamMultipartParts writes form fields then file fields to mp,
+// closing mp and pw when done.
+//
+// Errors are reported by closing pw with the error so the consumer of pr observes them on its next Read.
+//
+// Context cancellation is observed at iteration boundaries (between
+// fields and between files) and during file copy via a context-aware
+// reader. When ctx is canceled the pipe writer is closed with ctx.Err()
+// so the body consumer surfaces the cancellation as the read error.
+func (r *Request) streamMultipartParts(ctx context.Context, mp *multipart.Writer, pw *io.PipeWriter) {
+ defer func() {
+ mp.Close()
+ pw.Close()
+ }()
+
+ for fn, v := range r.formFields {
+ for _, vi := range v {
+ if err := ctx.Err(); err != nil {
+ _ = pw.CloseWithError(err)
+ return
+ }
+ if err := mp.WriteField(fn, vi); err != nil {
+ logClose(err, pw)
+ return
+ }
+ }
+ }
+
+ defer func() {
+ for _, ff := range r.fileFields {
+ for _, ffi := range ff {
+ ffi.Close()
+ }
+ }
+ }()
+
+ for fn, f := range r.fileFields {
+ for _, fi := range f {
+ if err := ctx.Err(); err != nil {
+ _ = pw.CloseWithError(err)
+ return
+ }
+
+ var fileContentType string
+ if p, ok := fi.(runtime.ContentTyper); ok {
+ fileContentType = p.ContentType()
+ } else {
+ // Need to read the data so that we can detect the content type
+ const contentTypeBufferSize = 512
+ buf := make([]byte, contentTypeBufferSize)
+ size, err := fi.Read(buf)
+ if err != nil && !errors.Is(err, io.EOF) {
+ logClose(err, pw)
+ return
+ }
+ fileContentType = http.DetectContentType(buf)
+ fi = runtime.NamedReader(fi.Name(), io.MultiReader(bytes.NewReader(buf[:size]), fi))
+ }
+
+ // Create the MIME headers for the new part
+ h := make(textproto.MIMEHeader)
+ h.Set("Content-Disposition",
+ fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
+ escapeQuotes(fn), escapeQuotes(filepath.Base(fi.Name()))))
+ h.Set("Content-Type", fileContentType)
+
+ wrtr, err := mp.CreatePart(h)
+ if err != nil {
+ logClose(err, pw)
+ return
+ }
+ if _, err := io.Copy(wrtr, &ctxReader{ctx: ctx, r: fi}); err != nil {
+ logClose(err, pw)
+ return
+ }
+ }
+ }
+}
+
+// ctxReader wraps an [io.Reader] with a context check on each Read. Once
+// ctx is done, subsequent Reads return ctx.Err() instead of delegating
+// to the underlying reader. It does not preempt a Read already in flight
+// — that is the source's responsibility (e.g. *os.File honors Close from
+// another goroutine, network sources honor SetDeadline).
+type ctxReader struct {
+ ctx context.Context //nolint:containedctx // io.Reader's Read method has no ctx parameter, so the wrapper must carry it on the struct
+ r io.Reader
+}
+
+func (cr *ctxReader) Read(p []byte) (int, error) {
+ if err := cr.ctx.Err(); err != nil {
+ return 0, err
+ }
+ return cr.r.Read(p)
+}
+
+// writeStreamPayload handles a stream payload (io.Reader /
+// io.ReadCloser). The bytes flow through verbatim — no producer is
+// invoked. The wire Content-Type is resolved via setStreamContentType
+// (priority: existing header, payload's ContentTyper,
+// streamFallbackMime, mediaType).
+//
+// Caller must ensure r.payload satisfies io.Reader (see
+// [request.usesStreamingBody]).
+func (r *Request) writeStreamPayload(mediaType string, producers map[string]runtime.Producer) io.Reader {
+ setStreamContentType(r.header, r.payload, mediaType, r.consumes, producers)
+ if rdr, ok := r.payload.(io.ReadCloser); ok {
+ return rdr
+ }
+
+ rdr, ok := r.payload.(io.Reader)
+ if !ok {
+ panic("internal error: payload expected to be an io.Reader") // guaranteed by earlier checks
+ }
+
+ return rdr
+}
+
+// writeNonStreamPayload runs the producer registered for mediaType
+// against r.payload, writing into r.buf. The Content-Type header
+// reflects the picker.
+//
+// SetHeaderParam("Content-Type", …) is intentionally NOT honored on
+// the producer path because the producer is dispatched off mediaType —
+// the wire header would otherwise misrepresent the body.
+//
+// The same reasoning applies to the form/multipart branch.
+func (r *Request) writeNonStreamPayload(mediaType string, producers map[string]runtime.Producer) (io.Reader, error) {
+ r.header.Set(runtime.HeaderContentType, mediaType)
+ producer, ok := producers[mediaType]
+ if !ok {
+ return nil, fmt.Errorf("no producer registered for content type %q (register one with Runtime.Producers)", mediaType)
+ }
+
+ if err := producer.Produce(r.buf, r.payload); err != nil {
+ return nil, err
+ }
+ return r.buf, nil
+}
+
+var quoter = strings.NewReplacer(
+ "\\", "\\\\",
+ `"`, "\\\"",
+ "\r", "_",
+ "\n", "_",
+)
+
+// escapeQuotes escapes backslash and double-quote for embedding in a
+// quoted-string Content-Disposition parameter value, and rewrites
+// CR / LF to '_' to prevent header-injection through attacker-influenced
+// field names or filenames.
+//
+// RFC 7578 §4.2 limits parameter values to printable characters; this
+// is the conservative subset relevant to security (control characters
+// that would split the header line into a forged header or part).
+// Mirrors the known stdlib gap golang/go#19038.
+func escapeQuotes(s string) string {
+ return quoter.Replace(s)
+}
+
+// setStreamContentType resolves and writes the wire Content-Type for a
+// stream payload (io.Reader / io.ReadCloser). Priority:
+//
+// 1. an explicit value already in header — the user set it via
+// SetHeaderParam during [ClientRequestWriter.WriteToRequest], and we treat that as an
+// intentional escape hatch;
+// 2. payload's [runtime.ContentTyper] declaration;
+// 3. [streamFallbackMime] (Stage-2 octet-stream upgrade);
+// 4. the picker's mediaType (passed in as the chain's terminal
+// fallback).
+//
+// Does not apply to non-stream payloads or to form/multipart bodies —
+// see the comment above the call site in [request.buildHTTP].
+func setStreamContentType(
+ header http.Header,
+ payload any,
+ mediaType string,
+ candidates []string,
+ producers map[string]runtime.Producer,
+) {
+ if header.Get(runtime.HeaderContentType) != "" {
+ return
+ }
+ fallback := streamFallbackMime(mediaType, candidates, producers)
+ header.Set(runtime.HeaderContentType, payloadContentType(payload, fallback))
+}
+
+// payloadContentType returns the payload's declared content type when
+// it implements [runtime.ContentTyper] with a non-empty result, and
+// fallback otherwise. Mirrors the per-file convention already used for
+// multipart upload parts (see [request.buildHTTP] file-fields branch).
+func payloadContentType(payload any, fallback string) string {
+ if t, ok := payload.(runtime.ContentTyper); ok {
+ if ct := t.ContentType(); ct != "" {
+ return ct
+ }
+ }
+
+ return fallback
+}
+
+// streamFallbackMime selects a wire content-type for a stream payload
+// (io.Reader / io.ReadCloser) that has neither implemented
+// `ContentType() string` nor declared an explicit value.
+//
+// The picker (Stage 1) ran without seeing the payload, so its choice
+// may be wildly wrong for raw bytes — e.g. picking application/json
+// for a payload that is just a stream of opaque data. When the
+// candidate consumes list also offers application/octet-stream and
+// the runtime has an octet-stream producer registered, that's a
+// safer wire type than the picker's choice: it advertises "raw bytes"
+// rather than making a structural claim about the body.
+//
+// If octet-stream is unavailable in either the candidate list or the
+// producer set, the picker's choice is preserved. The wire header
+// then continues to misrepresent the body — but no correct
+// alternative exists and we cannot infer one without more
+// information from the caller.
+func streamFallbackMime(picked string, candidates []string, producers map[string]runtime.Producer) string {
+ if strings.EqualFold(picked, runtime.DefaultMime) {
+ return picked
+ }
+
+ for _, c := range candidates {
+ if strings.EqualFold(c, runtime.DefaultMime) {
+ if _, ok := producers[runtime.DefaultMime]; ok {
+ return runtime.DefaultMime
+ }
+ }
+ }
+
+ return picked
+}
+
+func getRequestBuffer(r *Request) []byte {
+ if r.buf == nil {
+ return nil
+ }
+ return r.buf.Bytes()
+}
+
+func logClose(err error, pw *io.PipeWriter) {
+ log.Println(err)
+ closeErr := pw.CloseWithError(err)
+ if closeErr != nil {
+ log.Println(closeErr)
+ }
+}
+
+func mangleContentType(mediaType, boundary string) string {
+ _ = mediaType // reserved for future enhancement: honor caller-provided media type
+ // Proposal for enhancement: honor caller's boundary if specified
+ return "multipart/form-data; boundary=" + boundary
+}
diff --git a/vendor/github.com/go-openapi/runtime/client/keepalive.go b/vendor/github.com/go-openapi/runtime/client/keepalive.go
index 3bac5e272cf..6b6097d206f 100644
--- a/vendor/github.com/go-openapi/runtime/client/keepalive.go
+++ b/vendor/github.com/go-openapi/runtime/client/keepalive.go
@@ -34,20 +34,20 @@ func (k *keepAliveTransport) RoundTrip(r *http.Request) (*http.Response, error)
type drainingReadCloser struct {
rdr io.ReadCloser
- seenEOF uint32
+ seenEOF atomic.Uint32
}
func (d *drainingReadCloser) Read(p []byte) (n int, err error) {
n, err = d.rdr.Read(p)
if err == io.EOF || n == 0 {
- atomic.StoreUint32(&d.seenEOF, 1)
+ d.seenEOF.Store(1)
}
return
}
func (d *drainingReadCloser) Close() error {
// drain buffer
- if atomic.LoadUint32(&d.seenEOF) != 1 {
+ if d.seenEOF.Load() != 1 {
// If the reader side (a HTTP server) is misbehaving, it still may send
// some bytes, but the closer ignores them to keep the underling
// connection open.
diff --git a/vendor/github.com/go-openapi/runtime/client/opentelemetry.go b/vendor/github.com/go-openapi/runtime/client/opentelemetry.go
index 5054878c06c..e422f83cb12 100644
--- a/vendor/github.com/go-openapi/runtime/client/opentelemetry.go
+++ b/vendor/github.com/go-openapi/runtime/client/opentelemetry.go
@@ -4,18 +4,20 @@
package client
import (
+ "context"
"fmt"
"net/http"
"strings"
- "github.com/go-openapi/runtime"
- "github.com/go-openapi/strfmt"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/propagation"
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/trace"
+
+ "github.com/go-openapi/runtime"
+ "github.com/go-openapi/strfmt"
)
const (
@@ -23,6 +25,52 @@ const (
tracerName = "go-openapi"
)
+// WithOpenTelemetry adds opentelemetry support to the provided runtime.
+// A new client span is created for each request.
+// The provided opts are applied to each spans - for example to add global tags.
+//
+// The returned transport satisfies [runtime.ContextualTransport]: callers
+// should prefer [openTelemetryTransport.SubmitContext] over the
+// legacy [runtime.ClientOperation.Context] field. Setting that
+// field is still honored on the [openTelemetryTransport.Submit]
+// compatibility path.
+func (r *Runtime) WithOpenTelemetry(opts ...OpenTelemetryOpt) runtime.ContextualTransport {
+ return newOpenTelemetryTransport(r, r.Host, opts)
+}
+
+// WithOpenTracing adds opentracing support to the provided runtime.
+// A new client span is created for each request.
+// If the context of the client operation does not contain an active span, no span is created.
+// The provided opts are applied to each spans - for example to add global tags.
+//
+// Deprecated: use [WithOpenTelemetry] instead, as opentracing is now archived and superseded by opentelemetry.
+//
+// # Deprecation notice
+//
+// The [Runtime.WithOpenTracing] method has been deprecated in favor of [Runtime.WithOpenTelemetry].
+//
+// The method is still around so programs calling it will still build. However, it will return
+// an opentelemetry transport.
+//
+// If you have a strict requirement on using opentracing, you may still do so by importing
+// module [github.com/go-openapi/runtime/client-[middleware]/opentracing] and using
+// [github.com/go-openapi/runtime/client-[middleware]/opentracing.WithOpenTracing] with your
+// usual opentracing options and opentracing-enabled transport.
+//
+// Passed options are ignored unless they are of type [OpenTelemetryOpt].
+func (r *Runtime) WithOpenTracing(opts ...any) runtime.ContextualTransport {
+ otelOpts := make([]OpenTelemetryOpt, 0, len(opts))
+ for _, o := range opts {
+ otelOpt, ok := o.(OpenTelemetryOpt)
+ if !ok {
+ continue
+ }
+ otelOpts = append(otelOpts, otelOpt)
+ }
+
+ return r.WithOpenTelemetry(otelOpts...)
+}
+
type config struct {
Tracer trace.Tracer
Propagator propagation.TextMapPropagator
@@ -113,11 +161,31 @@ func newOpenTelemetryTransport(transport runtime.ClientTransport, host string, o
return tr
}
+// Submit implements [runtime.ClientTransport]. It honors the legacy
+// [runtime.ClientOperation.Context] field for backward compatibility
+// — that field is being phased out; new code should call
+// [openTelemetryTransport.SubmitContext] directly with an explicit
+// context.
func (t *openTelemetryTransport) Submit(op *runtime.ClientOperation) (any, error) {
- if op.Context == nil {
- return t.transport.Submit(op)
+ ctx := op.Context
+ if ctx == nil {
+ ctx = context.Background()
}
+ return t.SubmitContext(ctx, op)
+}
+// SubmitContext submits an operation with an explicit context that
+// drives both the tracing span and (when supported) the wrapped
+// transport's SubmitContext call. The legacy
+// [runtime.ClientOperation.Context] field is not consulted.
+//
+// When the wrapped transport implements [runtime.ContextualTransport], ctx is
+// forwarded directly via its SubmitContext. Otherwise, the legacy
+// Submit path is used: ctx is stamped onto op.Context for the
+// duration of that call and restored afterwards, so the wrapped
+// transport still receives a usable context. The legacy fallback
+// disappears once SubmitContext is universal (v2).
+func (t *openTelemetryTransport) SubmitContext(ctx context.Context, op *runtime.ClientOperation) (any, error) {
params := op.Params
reader := op.Reader
@@ -129,7 +197,7 @@ func (t *openTelemetryTransport) Submit(op *runtime.ClientOperation) (any, error
}()
op.Params = runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
- span = t.newOpenTelemetrySpan(op, req.GetHeaderParams())
+ span = t.newOpenTelemetrySpan(ctx, op, req.GetHeaderParams())
return params.WriteToRequest(req, reg)
})
@@ -149,7 +217,7 @@ func (t *openTelemetryTransport) Submit(op *runtime.ClientOperation) (any, error
return reader.ReadResponse(response, consumer)
})
- submit, err := t.transport.Submit(op)
+ submit, err := t.submitWrapped(ctx, op)
if err != nil && span != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
@@ -158,9 +226,18 @@ func (t *openTelemetryTransport) Submit(op *runtime.ClientOperation) (any, error
return submit, err
}
-func (t *openTelemetryTransport) newOpenTelemetrySpan(op *runtime.ClientOperation, header http.Header) trace.Span {
- ctx := op.Context
+//nolint:contextcheck // ctx is forwarded verbatim; the legacy Submit branch only stamps it onto op.Context for the wrapped transport.
+func (t *openTelemetryTransport) submitWrapped(ctx context.Context, op *runtime.ClientOperation) (any, error) {
+ if sc, ok := t.transport.(runtime.ContextualTransport); ok {
+ return sc.SubmitContext(ctx, op)
+ }
+ prev := op.Context
+ op.Context = ctx
+ defer func() { op.Context = prev }()
+ return t.transport.Submit(op)
+}
+func (t *openTelemetryTransport) newOpenTelemetrySpan(ctx context.Context, op *runtime.ClientOperation, header http.Header) trace.Span {
tracer := t.tracer
if tracer == nil {
if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() {
diff --git a/vendor/github.com/go-openapi/runtime/client/request.go b/vendor/github.com/go-openapi/runtime/client/request.go
deleted file mode 100644
index f16ee487bab..00000000000
--- a/vendor/github.com/go-openapi/runtime/client/request.go
+++ /dev/null
@@ -1,468 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
-// SPDX-License-Identifier: Apache-2.0
-
-package client
-
-import (
- "bytes"
- "context"
- "fmt"
- "io"
- "log"
- "mime/multipart"
- "net/http"
- "net/textproto"
- "net/url"
- "os"
- "path"
- "path/filepath"
- "strings"
- "time"
-
- "github.com/go-openapi/runtime"
- "github.com/go-openapi/strfmt"
-)
-
-var _ runtime.ClientRequest = new(request) // ensure compliance to the interface
-
-// Request represents a swagger client request.
-//
-// This Request struct converts to a HTTP request.
-// There might be others that convert to other transports.
-// There is no error checking here, it is assumed to be used after a spec has been validated.
-// so impossible combinations should not arise (hopefully).
-//
-// The main purpose of this struct is to hide the machinery of adding params to a transport request.
-// The generated code only implements what is necessary to turn a param into a valid value for these methods.
-type request struct {
- pathPattern string
- method string
- writer runtime.ClientRequestWriter
-
- pathParams map[string]string
- header http.Header
- query url.Values
- formFields url.Values
- fileFields map[string][]runtime.NamedReadCloser
- payload any
- timeout time.Duration
- buf *bytes.Buffer
-
- getBody func(r *request) []byte
-}
-
-// NewRequest creates a new swagger http client request.
-func newRequest(method, pathPattern string, writer runtime.ClientRequestWriter) *request {
- return &request{
- pathPattern: pathPattern,
- method: method,
- writer: writer,
- header: make(http.Header),
- query: make(url.Values),
- timeout: DefaultTimeout,
- getBody: getRequestBuffer,
- }
-}
-
-// BuildHTTP creates a new http request based on the data from the params.
-func (r *request) BuildHTTP(mediaType, basePath string, producers map[string]runtime.Producer, registry strfmt.Registry) (*http.Request, error) {
- return r.buildHTTP(mediaType, basePath, producers, registry, nil)
-}
-
-func (r *request) GetMethod() string {
- return r.method
-}
-
-func (r *request) GetPath() string {
- path := r.pathPattern
- for k, v := range r.pathParams {
- path = strings.ReplaceAll(path, "{"+k+"}", v)
- }
- return path
-}
-
-func (r *request) GetBody() []byte {
- return r.getBody(r)
-}
-
-// SetHeaderParam adds a header param to the request
-// when there is only 1 value provided for the varargs, it will set it.
-// when there are several values provided for the varargs it will add it (no overriding).
-func (r *request) SetHeaderParam(name string, values ...string) error {
- if r.header == nil {
- r.header = make(http.Header)
- }
- r.header[http.CanonicalHeaderKey(name)] = values
- return nil
-}
-
-// GetHeaderParams returns the all headers currently set for the request.
-func (r *request) GetHeaderParams() http.Header {
- return r.header
-}
-
-// SetQueryParam adds a query param to the request
-// when there is only 1 value provided for the varargs, it will set it.
-// when there are several values provided for the varargs it will add it (no overriding).
-func (r *request) SetQueryParam(name string, values ...string) error {
- if r.query == nil {
- r.query = make(url.Values)
- }
- r.query[name] = values
- return nil
-}
-
-// GetQueryParams returns a copy of all query params currently set for the request.
-func (r *request) GetQueryParams() url.Values {
- var result = make(url.Values)
- for key, value := range r.query {
- result[key] = append([]string{}, value...)
- }
- return result
-}
-
-// SetFormParam adds a forn param to the request
-// when there is only 1 value provided for the varargs, it will set it.
-// when there are several values provided for the varargs it will add it (no overriding).
-func (r *request) SetFormParam(name string, values ...string) error {
- if r.formFields == nil {
- r.formFields = make(url.Values)
- }
- r.formFields[name] = values
- return nil
-}
-
-// SetPathParam adds a path param to the request.
-func (r *request) SetPathParam(name string, value string) error {
- if r.pathParams == nil {
- r.pathParams = make(map[string]string)
- }
-
- r.pathParams[name] = value
- return nil
-}
-
-// SetFileParam adds a file param to the request.
-func (r *request) SetFileParam(name string, files ...runtime.NamedReadCloser) error {
- for _, file := range files {
- if actualFile, ok := file.(*os.File); ok {
- fi, err := os.Stat(actualFile.Name())
- if err != nil {
- return err
- }
- if fi.IsDir() {
- return fmt.Errorf("%q is a directory, only files are supported", file.Name())
- }
- }
- }
-
- if r.fileFields == nil {
- r.fileFields = make(map[string][]runtime.NamedReadCloser)
- }
- if r.formFields == nil {
- r.formFields = make(url.Values)
- }
-
- r.fileFields[name] = files
- return nil
-}
-
-func (r *request) GetFileParam() map[string][]runtime.NamedReadCloser {
- return r.fileFields
-}
-
-// SetBodyParam sets a body parameter on the request.
-// This does not yet serialze the object, this happens as late as possible.
-func (r *request) SetBodyParam(payload any) error {
- r.payload = payload
- return nil
-}
-
-func (r *request) GetBodyParam() any {
- return r.payload
-}
-
-// SetTimeout sets the timeout for a request.
-func (r *request) SetTimeout(timeout time.Duration) error {
- r.timeout = timeout
- return nil
-}
-
-func (r *request) isMultipart(mediaType string) bool {
- if len(r.fileFields) > 0 {
- return true
- }
-
- return runtime.MultipartFormMime == mediaType
-}
-
-func (r *request) buildHTTP(mediaType, basePath string, producers map[string]runtime.Producer, registry strfmt.Registry, auth runtime.ClientAuthInfoWriter) (*http.Request, error) { //nolint:gocyclo,maintidx
- // build the data
- if err := r.writer.WriteToRequest(r, registry); err != nil {
- return nil, err
- }
-
- // Our body must be an io.Reader.
- // When we create the http.Request, if we pass it a
- // bytes.Buffer then it will wrap it in an io.ReadCloser
- // and set the content length automatically.
- var body io.Reader
- var pr *io.PipeReader
- var pw *io.PipeWriter
-
- r.buf = bytes.NewBuffer(nil)
- if r.payload != nil || len(r.formFields) > 0 || len(r.fileFields) > 0 {
- body = r.buf
- if r.isMultipart(mediaType) {
- pr, pw = io.Pipe()
- body = pr
- }
- }
-
- // check if this is a form type request
- if len(r.formFields) > 0 || len(r.fileFields) > 0 {
- if !r.isMultipart(mediaType) {
- r.header.Set(runtime.HeaderContentType, mediaType)
- formString := r.formFields.Encode()
- r.buf.WriteString(formString)
- goto DoneChoosingBodySource
- }
-
- mp := multipart.NewWriter(pw)
- r.header.Set(runtime.HeaderContentType, mangleContentType(mediaType, mp.Boundary()))
-
- go func() {
- defer func() {
- mp.Close()
- pw.Close()
- }()
-
- for fn, v := range r.formFields {
- for _, vi := range v {
- if err := mp.WriteField(fn, vi); err != nil {
- logClose(err, pw)
- return
- }
- }
- }
-
- defer func() {
- for _, ff := range r.fileFields {
- for _, ffi := range ff {
- ffi.Close()
- }
- }
- }()
- for fn, f := range r.fileFields {
- for _, fi := range f {
- var fileContentType string
- if p, ok := fi.(interface {
- ContentType() string
- }); ok {
- fileContentType = p.ContentType()
- } else {
- // Need to read the data so that we can detect the content type
- const contentTypeBufferSize = 512
- buf := make([]byte, contentTypeBufferSize)
- size, err := fi.Read(buf)
- if err != nil && err != io.EOF {
- logClose(err, pw)
- return
- }
- fileContentType = http.DetectContentType(buf)
- fi = runtime.NamedReader(fi.Name(), io.MultiReader(bytes.NewReader(buf[:size]), fi))
- }
-
- // Create the MIME headers for the new part
- h := make(textproto.MIMEHeader)
- h.Set("Content-Disposition",
- fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
- escapeQuotes(fn), escapeQuotes(filepath.Base(fi.Name()))))
- h.Set("Content-Type", fileContentType)
-
- wrtr, err := mp.CreatePart(h)
- if err != nil {
- logClose(err, pw)
- return
- }
- if _, err := io.Copy(wrtr, fi); err != nil {
- logClose(err, pw)
- }
- }
- }
- }()
-
- goto DoneChoosingBodySource
- }
-
- // if there is payload, use the producer to write the payload, and then
- // set the header to the content-type appropriate for the payload produced
- if r.payload != nil {
- // Enhancement proposal: https://github.com/go-openapi/runtime/issues/387
- r.header.Set(runtime.HeaderContentType, mediaType)
- if rdr, ok := r.payload.(io.ReadCloser); ok {
- body = rdr
- goto DoneChoosingBodySource
- }
-
- if rdr, ok := r.payload.(io.Reader); ok {
- body = rdr
- goto DoneChoosingBodySource
- }
-
- producer := producers[mediaType]
- if err := producer.Produce(r.buf, r.payload); err != nil {
- return nil, err
- }
- }
-
-DoneChoosingBodySource:
-
- if runtime.CanHaveBody(r.method) && body != nil && r.header.Get(runtime.HeaderContentType) == "" {
- r.header.Set(runtime.HeaderContentType, mediaType)
- }
-
- if auth != nil {
- // If we're not using r.buf as our http.Request's body,
- // either the payload is an io.Reader or io.ReadCloser,
- // or we're doing a multipart form/file.
- //
- // In those cases, if the AuthenticateRequest call asks for the body,
- // we must read it into a buffer and provide that, then use that buffer
- // as the body of our http.Request.
- //
- // This is done in-line with the GetBody() request rather than ahead
- // of time, because there's no way to know if the AuthenticateRequest
- // will even ask for the body of the request.
- //
- // If for some reason the copy fails, there's no way to return that
- // error to the GetBody() call, so return it afterwards.
- //
- // An error from the copy action is prioritized over any error
- // from the AuthenticateRequest call, because the mis-read
- // body may have interfered with the auth.
- //
- var copyErr error
- if buf, ok := body.(*bytes.Buffer); body != nil && (!ok || buf != r.buf) {
- var copied bool
- r.getBody = func(r *request) []byte {
- if copied {
- return getRequestBuffer(r)
- }
-
- defer func() {
- copied = true
- }()
-
- if _, copyErr = io.Copy(r.buf, body); copyErr != nil {
- return nil
- }
-
- if closer, ok := body.(io.ReadCloser); ok {
- if copyErr = closer.Close(); copyErr != nil {
- return nil
- }
- }
-
- body = r.buf
- return getRequestBuffer(r)
- }
- }
-
- authErr := auth.AuthenticateRequest(r, registry)
-
- if copyErr != nil {
- return nil, fmt.Errorf("error retrieving the response body: %v", copyErr)
- }
-
- if authErr != nil {
- return nil, authErr
- }
- }
-
- // In case the basePath or the request pathPattern include static query parameters,
- // parse those out before constructing the final path. The parameters themselves
- // will be merged with the ones set by the client, with the priority given first to
- // the ones set by the client, then the path pattern, and lastly the base path.
- basePathURL, err := url.Parse(basePath)
- if err != nil {
- return nil, err
- }
- staticQueryParams := basePathURL.Query()
-
- pathPatternURL, err := url.Parse(r.pathPattern)
- if err != nil {
- return nil, err
- }
- for name, values := range pathPatternURL.Query() {
- if _, present := staticQueryParams[name]; present {
- staticQueryParams.Del(name)
- }
- for _, value := range values {
- staticQueryParams.Add(name, value)
- }
- }
-
- // create http request
- var reinstateSlash bool
- if pathPatternURL.Path != "" && pathPatternURL.Path != "/" && pathPatternURL.Path[len(pathPatternURL.Path)-1] == '/' {
- reinstateSlash = true
- }
-
- urlPath := path.Join(basePathURL.Path, pathPatternURL.Path)
- for k, v := range r.pathParams {
- urlPath = strings.ReplaceAll(urlPath, "{"+k+"}", url.PathEscape(v))
- }
- if reinstateSlash {
- urlPath += "/"
- }
-
- req, err := http.NewRequestWithContext(context.Background(), r.method, urlPath, body)
- if err != nil {
- return nil, err
- }
-
- originalParams := r.GetQueryParams()
-
- // Merge the query parameters extracted from the basePath with the ones set by
- // the client in this struct. In case of conflict, the client wins.
- for k, v := range staticQueryParams {
- _, present := originalParams[k]
- if !present {
- if err = r.SetQueryParam(k, v...); err != nil {
- return nil, err
- }
- }
- }
-
- req.URL.RawQuery = r.query.Encode()
- req.Header = r.header
-
- return req, nil
-}
-
-func escapeQuotes(s string) string {
- return strings.NewReplacer("\\", "\\\\", `"`, "\\\"").Replace(s)
-}
-
-func getRequestBuffer(r *request) []byte {
- if r.buf == nil {
- return nil
- }
- return r.buf.Bytes()
-}
-
-func logClose(err error, pw *io.PipeWriter) {
- log.Println(err)
- closeErr := pw.CloseWithError(err)
- if closeErr != nil {
- log.Println(closeErr)
- }
-}
-
-func mangleContentType(mediaType, boundary string) string {
- if strings.ToLower(mediaType) == runtime.URLencodedFormMime {
- return fmt.Sprintf("%s; boundary=%s", mediaType, boundary)
- }
- return "multipart/form-data; boundary=" + boundary
-}
diff --git a/vendor/github.com/go-openapi/runtime/client/runtime.go b/vendor/github.com/go-openapi/runtime/client/runtime.go
index eeb17dfb24e..b890f9f4133 100644
--- a/vendor/github.com/go-openapi/runtime/client/runtime.go
+++ b/vendor/github.com/go-openapi/runtime/client/runtime.go
@@ -5,25 +5,19 @@ package client
import (
"context"
- "crypto"
- "crypto/ecdsa"
- "crypto/rsa"
- "crypto/tls"
- "crypto/x509"
- "encoding/pem"
- "errors"
"fmt"
"mime"
"net/http"
"net/http/httputil"
- "os"
"strings"
"sync"
"time"
"github.com/go-openapi/runtime"
+ "github.com/go-openapi/runtime/client/internal/request"
"github.com/go-openapi/runtime/logger"
"github.com/go-openapi/runtime/middleware"
+ "github.com/go-openapi/runtime/server-middleware/mediatype"
"github.com/go-openapi/runtime/yamlpc"
"github.com/go-openapi/strfmt"
)
@@ -36,184 +30,6 @@ const (
// DefaultTimeout the default request timeout.
var DefaultTimeout = 30 * time.Second
-// TLSClientOptions to configure client authentication with mutual TLS.
-type TLSClientOptions struct {
- // Certificate is the path to a PEM-encoded certificate to be used for
- // client authentication. If set then Key must also be set.
- Certificate string
-
- // LoadedCertificate is the certificate to be used for client authentication.
- // This field is ignored if Certificate is set. If this field is set, LoadedKey
- // is also required.
- LoadedCertificate *x509.Certificate
-
- // Key is the path to an unencrypted PEM-encoded private key for client
- // authentication. This field is required if Certificate is set.
- Key string
-
- // LoadedKey is the key for client authentication. This field is required if
- // LoadedCertificate is set.
- LoadedKey crypto.PrivateKey
-
- // CA is a path to a PEM-encoded certificate that specifies the root certificate
- // to use when validating the TLS certificate presented by the server. If this field
- // (and LoadedCA) is not set, the system certificate pool is used. This field is ignored if LoadedCA
- // is set.
- CA string
-
- // LoadedCA specifies the root certificate to use when validating the server's TLS certificate.
- // If this field (and CA) is not set, the system certificate pool is used.
- LoadedCA *x509.Certificate
-
- // LoadedCAPool specifies a pool of RootCAs to use when validating the server's TLS certificate.
- // If set, it will be combined with the other loaded certificates (see LoadedCA and CA).
- // If neither LoadedCA or CA is set, the provided pool with override the system
- // certificate pool.
- // The caller must not use the supplied pool after calling TLSClientAuth.
- LoadedCAPool *x509.CertPool
-
- // ServerName specifies the hostname to use when verifying the server certificate.
- // If this field is set then InsecureSkipVerify will be ignored and treated as
- // false.
- ServerName string
-
- // InsecureSkipVerify controls whether the certificate chain and hostname presented
- // by the server are validated. If true, any certificate is accepted.
- InsecureSkipVerify bool
-
- // VerifyPeerCertificate, if not nil, is called after normal
- // certificate verification. It receives the raw ASN.1 certificates
- // provided by the peer and also any verified chains that normal processing found.
- // If it returns a non-nil error, the handshake is aborted and that error results.
- //
- // If normal verification fails then the handshake will abort before
- // considering this callback. If normal verification is disabled by
- // setting InsecureSkipVerify then this callback will be considered but
- // the verifiedChains argument will always be nil.
- VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
-
- // VerifyConnection, if not nil, is called after normal certificate
- // verification and after [TLSClientOptions.VerifyPeerCertificate] by either a TLS client or
- // server. It receives the [tls.ConnectionState] which may be inspected.
- //
- // Unlike VerifyPeerCertificate, this callback is invoked on every
- // connection, including resumed ones, making it suitable for checks
- // that must always apply (e.g. certificate pinning).
- //
- // If it returns a non-nil error, the handshake is aborted and that error results.
- VerifyConnection func(tls.ConnectionState) error
-
- // SessionTicketsDisabled may be set to true to disable session ticket and
- // PSK (resumption) support. Note that on clients, session ticket support is
- // also disabled if ClientSessionCache is nil.
- SessionTicketsDisabled bool
-
- // ClientSessionCache is a cache of ClientSessionState entries for TLS
- // session resumption. It is only used by clients.
- ClientSessionCache tls.ClientSessionCache
-
- // Prevents callers using unkeyed fields.
- _ struct{}
-}
-
-// TLSClientAuth creates a [tls.Config] for mutual auth.
-func TLSClientAuth(opts TLSClientOptions) (*tls.Config, error) {
- // create client tls config
- cfg := &tls.Config{
- MinVersion: tls.VersionTLS12,
- }
-
- // load client cert if specified
- if opts.Certificate != "" {
- cert, err := tls.LoadX509KeyPair(opts.Certificate, opts.Key)
- if err != nil {
- return nil, fmt.Errorf("tls client cert: %v", err)
- }
- cfg.Certificates = []tls.Certificate{cert}
- } else if opts.LoadedCertificate != nil {
- block := pem.Block{Type: "CERTIFICATE", Bytes: opts.LoadedCertificate.Raw}
- certPem := pem.EncodeToMemory(&block)
-
- var keyBytes []byte
- switch k := opts.LoadedKey.(type) {
- case *rsa.PrivateKey:
- keyBytes = x509.MarshalPKCS1PrivateKey(k)
- case *ecdsa.PrivateKey:
- var err error
- keyBytes, err = x509.MarshalECPrivateKey(k)
- if err != nil {
- return nil, fmt.Errorf("tls client priv key: %v", err)
- }
- default:
- return nil, errors.New("tls client priv key: unsupported key type")
- }
-
- block = pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes}
- keyPem := pem.EncodeToMemory(&block)
-
- cert, err := tls.X509KeyPair(certPem, keyPem)
- if err != nil {
- return nil, fmt.Errorf("tls client cert: %v", err)
- }
- cfg.Certificates = []tls.Certificate{cert}
- }
-
- cfg.InsecureSkipVerify = opts.InsecureSkipVerify
-
- cfg.VerifyPeerCertificate = opts.VerifyPeerCertificate
- cfg.VerifyConnection = opts.VerifyConnection
- cfg.SessionTicketsDisabled = opts.SessionTicketsDisabled
- cfg.ClientSessionCache = opts.ClientSessionCache
-
- // When no CA certificate is provided, default to the system cert pool
- // that way when a request is made to a server known by the system trust store,
- // the name is still verified
- switch {
- case opts.LoadedCA != nil:
- caCertPool := basePool(opts.LoadedCAPool)
- caCertPool.AddCert(opts.LoadedCA)
- cfg.RootCAs = caCertPool
- case opts.CA != "":
- // load ca cert
- caCert, err := os.ReadFile(opts.CA)
- if err != nil {
- return nil, fmt.Errorf("tls client ca: %v", err)
- }
- caCertPool := basePool(opts.LoadedCAPool)
- caCertPool.AppendCertsFromPEM(caCert)
- cfg.RootCAs = caCertPool
- case opts.LoadedCAPool != nil:
- cfg.RootCAs = opts.LoadedCAPool
- }
-
- // apply servername overrride
- if opts.ServerName != "" {
- cfg.InsecureSkipVerify = false
- cfg.ServerName = opts.ServerName
- }
-
- return cfg, nil
-}
-
-// TLSTransport creates a [http] client transport suitable for mutual [tls] auth.
-func TLSTransport(opts TLSClientOptions) (http.RoundTripper, error) {
- cfg, err := TLSClientAuth(opts)
- if err != nil {
- return nil, err
- }
-
- return &http.Transport{TLSClientConfig: cfg}, nil
-}
-
-// TLSClient creates a [http.Client] for mutual auth.
-func TLSClient(opts TLSClientOptions) (*http.Client, error) {
- transport, err := TLSTransport(opts)
- if err != nil {
- return nil, err
- }
- return &http.Client{Transport: transport}, nil
-}
-
// Runtime represents an API client that uses the transport
// to make [http] requests based on a swagger specification.
type Runtime struct {
@@ -228,17 +44,50 @@ type Runtime struct {
Host string
BasePath string
Formats strfmt.Registry
- Context context.Context //nolint:containedctx // we precisely want this type to contain the request context
+ // Deprecated: prefer [runtime.ContextualTransport.SubmitContext] to pass the request context explicitly.
+ Context context.Context //nolint:containedctx // we precisely want this type to contain the request context
+
+ Debug bool
+
+ // Trace enables connection-level diagnostic output via
+ // [net/http/httptrace]. When true, the runtime narrates the
+ // connection lifecycle of every request through r.logger.Debugf:
+ // DNS, dial, TLS handshake, idle-pool reuse, request body
+ // transfer, time-to-first-byte, response body transfer, and a
+ // trailing per-request summary line.
+ //
+ // Trace is orthogonal to Debug: Debug dumps wire bytes (request
+ // and response headers and body), Trace narrates how the
+ // connection got there. Both may be enabled independently.
+ //
+ // Trace is not coupled to the SWAGGER_DEBUG / DEBUG environment
+ // variables: it defaults to false and is only enabled by
+ // explicit assignment.
+ //
+ // Trace is primarily intended as a problem-investigation tool
+ // (the local equivalent of curl -vvv), not an always-on tracer.
+ // For distributed-trace correlation, use the OpenTelemetry
+ // integration ([Runtime.WithOpenTelemetry]).
+ Trace bool
- Debug bool
logger logger.Logger
+ // MatchSuffix enables RFC 6839 structured-syntax suffix tolerance
+ // for codec lookup. When true, a response with Content-Type
+ // "application/problem+json" finds the JSON consumer registered
+ // under "application/json"; with the default false, the lookup
+ // is strict and falls through to the "*/*" wildcard if present.
+ // See [mediatype.AllowSuffix] for the semantics.
+ MatchSuffix bool
+
clientOnce *sync.Once
client *http.Client
schemes []string
response ClientResponseFunc
}
+var _ runtime.ContextualTransport = &Runtime{}
+
// New creates a new default runtime for a swagger api runtime.Client.
func New(host, basePath string, schemes []string) *Runtime {
var rt Runtime
@@ -246,13 +95,15 @@ func New(host, basePath string, schemes []string) *Runtime {
// Enhancement proposal: https://github.com/go-openapi/runtime/issues/385
rt.Consumers = map[string]runtime.Consumer{
- runtime.YAMLMime: yamlpc.YAMLConsumer(),
- runtime.JSONMime: runtime.JSONConsumer(),
- runtime.XMLMime: runtime.XMLConsumer(),
- runtime.TextMime: runtime.TextConsumer(),
- runtime.HTMLMime: runtime.TextConsumer(),
- runtime.CSVMime: runtime.CSVConsumer(),
- runtime.DefaultMime: runtime.ByteStreamConsumer(),
+ runtime.YAMLMime: yamlpc.YAMLConsumer(),
+ runtime.JSONMime: runtime.JSONConsumer(),
+ runtime.XMLMime: runtime.XMLConsumer(),
+ runtime.TextMime: runtime.TextConsumer(),
+ runtime.HTMLMime: runtime.TextConsumer(),
+ runtime.CSVMime: runtime.CSVConsumer(),
+ runtime.MultipartFormMime: runtime.ByteStreamConsumer(),
+ runtime.URLencodedFormMime: runtime.ByteStreamConsumer(),
+ runtime.DefaultMime: runtime.ByteStreamConsumer(),
}
rt.Producers = map[string]runtime.Producer{
runtime.YAMLMime: yamlpc.YAMLProducer(),
@@ -294,47 +145,6 @@ func NewWithClient(host, basePath string, schemes []string, client *http.Client)
return rt
}
-// WithOpenTracing adds opentracing support to the provided runtime.
-// A new client span is created for each request.
-// If the context of the client operation does not contain an active span, no span is created.
-// The provided opts are applied to each spans - for example to add global tags.
-//
-// Deprecated: use [WithOpenTelemetry] instead, as opentracing is now archived and superseded by opentelemetry.
-//
-// # Deprecation notice
-//
-// The [Runtime.WithOpenTracing] method has been deprecated in favor of [Runtime.WithOpenTelemetry].
-//
-// The method is still around so programs calling it will still build. However, it will return
-// an opentelemetry transport.
-//
-// If you have a strict requirement on using opentracing, you may still do so by importing
-// module [github.com/go-openapi/runtime/client-[middleware]/opentracing] and using
-// [github.com/go-openapi/runtime/client-[middleware]/opentracing.WithOpenTracing] with your
-// usual opentracing options and opentracing-enabled transport.
-//
-// Passed options are ignored unless they are of type [OpenTelemetryOpt].
-func (r *Runtime) WithOpenTracing(opts ...any) runtime.ClientTransport {
- otelOpts := make([]OpenTelemetryOpt, 0, len(opts))
- for _, o := range opts {
- otelOpt, ok := o.(OpenTelemetryOpt)
- if !ok {
- continue
- }
- otelOpts = append(otelOpts, otelOpt)
- }
-
- return r.WithOpenTelemetry(otelOpts...)
-}
-
-// WithOpenTelemetry adds opentelemetry support to the provided runtime.
-// A new client span is created for each request.
-// If the context of the client operation does not contain an active span, no span is created.
-// The provided opts are applied to each spans - for example to add global tags.
-func (r *Runtime) WithOpenTelemetry(opts ...OpenTelemetryOpt) runtime.ClientTransport {
- return newOpenTelemetryTransport(r, r.Host, opts)
-}
-
// EnableConnectionReuse drains the remaining body from a response
// so that go will reuse the TCP connections.
//
@@ -357,105 +167,109 @@ func (r *Runtime) EnableConnectionReuse() {
)
}
+// CreateHTTPRequestContext creates the requests and bind the parameters, but does not send it over the wire
+// like [Runtime.SubmitContext].
+//
+// The [http.Request] is complete with authentication, headers and body (including streamed body) and ready for callers
+// to submit it to a [http.Client] of their choice, then consume the [http.Response].
+//
+// Most users would simply use [Runtime.SubmitContext], which wraps all these operations in one call.
+func (r *Runtime) CreateHTTPRequestContext(ctx context.Context, operation *runtime.ClientOperation) (req *http.Request, cancel context.CancelFunc, err error) {
+ req, cancel, err = r.createHTTPRequestContext(ctx, operation)
+ return
+}
+
+// CreateHttpRequest builds the [http.Request] for the given operation, using
+// [context.Background] as the request context.
+//
+// Any per-operation timeout declared by the operation's [runtime.ClientRequestWriter]
+// is silently ignored here, which can leak a context-cancellation channel if the
+// caller relies on it.
+//
+// Deprecated: use [Runtime.CreateHTTPRequestContext] instead, with explicit
+// control over the request context and its cancellation.
func (r *Runtime) CreateHttpRequest(operation *runtime.ClientOperation) (req *http.Request, err error) { //nolint:revive
- _, req, err = r.createHttpRequest(operation)
+ req, _, err = r.createHTTPRequestContext(context.Background(), operation)
return
}
// Submit a request and when there is a body on success it will turn that into the result
// all other things are turned into an api error for swagger which retains the status code.
+//
+// This call inherits the context possibly put in the operation, otherwise the one possibly put in the [Runtime].
+// If none are set, use [context.Background].
+//
+// Any timeout set by parameters is honored.
func (r *Runtime) Submit(operation *runtime.ClientOperation) (any, error) {
- _, readResponse, _ := operation.Params, operation.Reader, operation.AuthInfo
+ return r.SubmitContext(r.ensureContext(operation), operation)
+}
- request, req, err := r.createHttpRequest(operation)
+// SubmitContext submits a request and returns the result.
+//
+// Errors are turned into an api error for swagger which retains the status code.
+//
+// Unlike [Submit], [SubmitContext] only injects the context provided by the caller:
+// contexts possibly cached in operation or runtime are ignored.
+//
+// On the other hand, a timeout set by parameters is honored.
+func (r *Runtime) SubmitContext(parentCtx context.Context, operation *runtime.ClientOperation) (any, error) {
+ req, cancel, err := r.createHTTPRequestContext(parentCtx, operation)
if err != nil {
return nil, err
}
+ defer cancel()
- r.clientOnce.Do(func() {
- r.client = &http.Client{
- Transport: r.Transport,
- Jar: r.Jar,
- }
- })
-
- if r.Debug {
- b, err2 := httputil.DumpRequestOut(req, true)
- if err2 != nil {
- return nil, err2
- }
- r.logger.Debugf("%s\n", string(b))
- }
+ r.ensureClient()
- var parentCtx context.Context
- switch {
- case operation.Context != nil:
- parentCtx = operation.Context
- case r.Context != nil:
- parentCtx = r.Context
- default:
- parentCtx = context.Background()
+ if err := r.dumpRequest(req); err != nil {
+ return nil, err
}
- var (
- ctx context.Context
- cancel context.CancelFunc
- )
- if request.timeout == 0 {
- // There may be a deadline in the context passed to the operation.
- // Otherwise, there is no timeout set.
- ctx, cancel = context.WithCancel(parentCtx)
- } else {
- // Sets the timeout passed from request params (by default runtime.DefaultTimeout).
- // If there is already a deadline in the parent context, the shortest will
- // apply.
- ctx, cancel = context.WithTimeout(parentCtx, request.timeout)
+ // Attach the trace session before Do so the httptrace hooks
+ // fire during the round-trip. The session emits its trailing
+ // summary on finish; the response body is consumed by
+ // ReadResponse downstream, after which finish is called.
+ var trace *traceSession
+ if r.Trace {
+ trace = newTraceSession(r.logger, req.Method, req.URL.String(),
+ introspectTLSConfig(r.pickClient(operation)))
+ //nolint:contextcheck // We intentionally derive from req.Context() to layer the trace hooks onto the existing request context.
+ req = req.WithContext(trace.attach(req.Context()))
+ if req.Body != nil {
+ req.Body = trace.wrapRequestBody(req.Body)
+ }
+ defer trace.finish()
}
- defer cancel()
- var client *http.Client
- if operation.Client != nil {
- client = operation.Client
- } else {
- client = r.client
- }
- req = req.WithContext(ctx)
- res, err := client.Do(req) // make requests, by default follows 10 redirects before failing
+ res, err := r.pickClient(operation).Do(req)
if err != nil {
+ if trace != nil {
+ trace.onRoundTripError(err)
+ }
return nil, err
}
defer res.Body.Close()
+ if trace != nil {
+ trace.onResponse(res.StatusCode)
+ res.Body = trace.wrapResponseBody(res.Body)
+ }
+
ct := res.Header.Get(runtime.HeaderContentType)
if ct == "" { // this should really never occur
ct = r.DefaultMediaType
}
- if r.Debug {
- printBody := true
- if ct == runtime.DefaultMime {
- printBody = false // Spare the terminal from a binary blob.
- }
- b, err2 := httputil.DumpResponse(res, printBody)
- if err2 != nil {
- return nil, err2
- }
- r.logger.Debugf("%s\n", string(b))
+ if err := r.dumpResponse(res, ct); err != nil {
+ return nil, err
}
- mt, _, err := mime.ParseMediaType(ct)
+ cons, err := r.resolveConsumer(ct)
if err != nil {
- return nil, fmt.Errorf("parse content type: %s", err)
+ return nil, err
}
- cons, ok := r.Consumers[mt]
- if !ok {
- if cons, ok = r.Consumers["*/*"]; !ok {
- // scream about not knowing what to do
- return nil, fmt.Errorf("no consumer: %q", ct)
- }
- }
- return readResponse.ReadResponse(r.response(res), cons)
+ return operation.Reader.ReadResponse(r.response(res), cons)
}
// SetDebug changes the debug flag.
@@ -482,6 +296,17 @@ func (r *Runtime) SetResponseReader(f ClientResponseFunc) {
r.response = f
}
+func (r *Runtime) ensureContext(operation *runtime.ClientOperation) context.Context {
+ switch {
+ case operation.Context != nil: //nolint:staticcheck // kept for backward compatibility
+ return operation.Context
+ case r.Context != nil:
+ return r.Context
+ default:
+ return context.Background()
+ }
+}
+
func (r *Runtime) pickScheme(schemes []string) string {
if v := r.selectScheme(r.schemes); v != "" {
return v
@@ -518,16 +343,121 @@ func transportOrDefault(left, right http.RoundTripper) http.RoundTripper {
return left
}
-// takes a client operation and creates equivalent http.Request.
-func (r *Runtime) createHttpRequest(operation *runtime.ClientOperation) (*request, *http.Request, error) { //nolint:revive
+// ensureClient lazily initializes r.client from r.Transport and r.Jar
+// on first use. Safe under concurrent calls via sync.Once.
+func (r *Runtime) ensureClient() {
+ r.clientOnce.Do(func() {
+ r.client = &http.Client{
+ Transport: r.Transport,
+ Jar: r.Jar,
+ }
+ })
+}
+
+// pickClient returns the http.Client to use for this operation: the
+// per-operation override if set, else the runtime's shared client.
+func (r *Runtime) pickClient(operation *runtime.ClientOperation) *http.Client {
+ if operation.Client != nil {
+ return operation.Client
+ }
+ return r.client
+}
+
+// dumpRequest writes the outgoing request to the debug logger when
+// r.Debug is enabled. No-op otherwise. Returns the dump error so the
+// caller can decide whether to abort the submit.
+func (r *Runtime) dumpRequest(req *http.Request) error {
+ if !r.Debug {
+ return nil
+ }
+ b, err := httputil.DumpRequestOut(req, true)
+ if err != nil {
+ return err
+ }
+ r.logger.Debugf("%s\n", string(b))
+ return nil
+}
+
+// dumpResponse writes the incoming response to the debug logger when
+// r.Debug is enabled. The body is omitted for runtime.DefaultMime
+// (binary blob). No-op otherwise.
+func (r *Runtime) dumpResponse(res *http.Response, ct string) error {
+ if !r.Debug {
+ return nil
+ }
+ printBody := ct != runtime.DefaultMime // Spare the terminal from a binary blob.
+ b, err := httputil.DumpResponse(res, printBody)
+ if err != nil {
+ return err
+ }
+ r.logger.Debugf("%s\n", string(b))
+ return nil
+}
+
+// resolveConsumer parses ct and returns the registered Consumer for
+// that media type. Lookup is alias-aware (RFC 9512 §2.1 — yaml
+// aliases) and, when [Runtime.MatchSuffix] is true, also tolerates
+// RFC 6839 structured-syntax suffix media types (+json, +xml, +yaml).
+// Falls back to the "*/*" entry if no match found.
+func (r *Runtime) resolveConsumer(ct string) (runtime.Consumer, error) {
+ if _, _, err := mime.ParseMediaType(ct); err != nil {
+ return nil, fmt.Errorf("parse content type: %w", err)
+ }
+ if cons, ok := mediatype.Lookup(r.Consumers, ct, r.matchOpts()...); ok {
+ return cons, nil
+ }
+ if cons, ok := r.Consumers["*/*"]; ok {
+ return cons, nil
+ }
+ // scream about not knowing what to do
+ return nil, fmt.Errorf("no consumer: %q", ct)
+}
+
+// matchOpts builds the mediatype.MatchOption slice for codec
+// lookups on the Runtime, currently just the AllowSuffix opt-in.
+func (r *Runtime) matchOpts() []mediatype.MatchOption {
+ if !r.MatchSuffix {
+ return nil
+ }
+
+ return []mediatype.MatchOption{mediatype.AllowSuffix()}
+}
+
+// createHTTPRequestContext is the context-aware builder of a [http.Request].
+//
+// The returned [http.Request] carries a context derived from parentCtx that
+// honors the per-request timeout set during WriteToRequest. Callers must
+// invoke cancel once the response is fully read.
+func (r *Runtime) createHTTPRequestContext(parentCtx context.Context, operation *runtime.ClientOperation) (*http.Request, context.CancelFunc, error) {
+ req, cmt, auth, err := r.prepareRequest(operation)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ httpReq, cancel, err := req.BuildHTTPContext(parentCtx, cmt, r.BasePath, r.Producers, r.Formats, auth)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ r.applyHostScheme(httpReq, operation)
+
+ return httpReq, cancel, nil
+}
+
+// prepareRequest performs the operation-to-request setup that is
+// independent of how the http.Request is finally assembled: parameters,
+// headers, default authentication, and consumes-media-type selection.
+func (r *Runtime) prepareRequest(operation *runtime.ClientOperation) (*request.Request, string, runtime.ClientAuthInfoWriter, error) {
params, _, auth := operation.Params, operation.Reader, operation.AuthInfo
- request := newRequest(operation.Method, operation.PathPattern, params)
+ req := request.New(operation.Method, operation.PathPattern, params)
+ _ = req.SetTimeout(DefaultTimeout) // the timeout may be overridden by ClientRequestWriter
+ req.SetConsumes(operation.ConsumesMediaTypes)
accept := make([]string, 0, len(operation.ProducesMediaTypes))
accept = append(accept, operation.ProducesMediaTypes...)
- if err := request.SetHeaderParam(runtime.HeaderAccept, accept...); err != nil {
- return nil, nil, err
+ if err := req.SetHeaderParam(runtime.HeaderAccept, accept...); err != nil {
+ return nil, "", nil, err
}
if auth == nil && r.DefaultAuthentication != nil {
@@ -538,39 +468,75 @@ func (r *Runtime) createHttpRequest(operation *runtime.ClientOperation) (*reques
return r.DefaultAuthentication.AuthenticateRequest(req, reg)
})
}
- // if auth != nil {
- // if err := auth.AuthenticateRequest(request, r.Formats); err != nil {
- // return nil, err
- // }
- //}
-
- // Enhancement proposal: https://github.com/go-openapi/runtime/issues/386
- cmt := r.DefaultMediaType
- for _, mediaType := range operation.ConsumesMediaTypes {
- // Pick first non-empty media type
- if mediaType != "" {
- cmt = mediaType
- break
- }
- }
- if _, ok := r.Producers[cmt]; !ok && cmt != runtime.MultipartFormMime && cmt != runtime.URLencodedFormMime {
- return nil, nil, fmt.Errorf("none of producers: %v registered. try %s", r.Producers, cmt)
+ cmt := pickConsumesMediaType(operation.ConsumesMediaTypes, r.Producers, r.DefaultMediaType, r.matchOpts()...)
+ if _, ok := mediatype.Lookup(r.Producers, cmt, r.matchOpts()...); !ok && cmt != runtime.MultipartFormMime && cmt != runtime.URLencodedFormMime {
+ return nil, "", nil, fmt.Errorf("none of producers: %v registered. try %s", r.Producers, cmt)
}
- req, err := request.buildHTTP(cmt, r.BasePath, r.Producers, r.Formats, auth)
- if err != nil {
- return nil, nil, err
- }
- req.URL.Scheme = r.pickScheme(operation.Schemes)
- req.URL.Host = r.Host
- req.Host = r.Host
- return request, req, nil
+ return req, cmt, auth, nil
}
-func basePool(pool *x509.CertPool) *x509.CertPool {
- if pool == nil {
- return x509.NewCertPool()
+// applyHostScheme stamps the runtime's host and the operation-selected
+// scheme onto the freshly built http.Request.
+func (r *Runtime) applyHostScheme(httpReq *http.Request, operation *runtime.ClientOperation) {
+ httpReq.URL.Scheme = r.pickScheme(operation.Schemes)
+ httpReq.URL.Host = r.Host
+ httpReq.Host = r.Host
+}
+
+// pickConsumesMediaType selects which Content-Type the client will send.
+//
+// Selection rules, in priority order:
+//
+// 1. multipart/form-data if any consumes entry advertises it (it streams
+// and preserves per-file Content-Type, regardless of codegen ordering;
+// resolves issue #286);
+// 2. the first non-empty entry whose mime is either structural
+// (multipart/form-data or application/x-www-form-urlencoded — these
+// do not need a producer in the map) or has a producer registered in
+// producers — this lets the client gracefully skip unregistered
+// spec entries instead of erroring at the gate that follows;
+// 3. the first non-empty entry overall (preserves the historical error
+// path: the gate at the call site reports "none of producers" with
+// the unregistered mime, so the diagnostic is unchanged when nothing
+// in consumes is registered);
+// 4. def, if consumes is empty or all empty strings.
+//
+// Step 2 closes part of issues #32 and #386: an operation declaring
+// `consumes: [application/x-vendor, application/json]` with no vendor
+// producer registered now silently uses JSON instead of erroring.
+func pickConsumesMediaType(consumes []string, producers map[string]runtime.Producer, def string, opts ...mediatype.MatchOption) string {
+ for _, mt := range consumes {
+ if strings.EqualFold(mt, runtime.MultipartFormMime) {
+ return mt
+ }
+ }
+ var firstNonEmpty string
+ for _, mt := range consumes {
+ if mt == "" {
+ continue
+ }
+ if firstNonEmpty == "" {
+ firstNonEmpty = mt
+ }
+ if isStructuralMime(mt) {
+ return mt
+ }
+ if _, ok := mediatype.Lookup(producers, mt, opts...); ok {
+ return mt
+ }
+ }
+ if firstNonEmpty != "" {
+ return firstNonEmpty
}
- return pool
+ return def
+}
+
+// isStructuralMime reports whether mt is a media type whose body shape
+// is owned by the runtime (multipart envelope, urlencoded form). These
+// do not require an entry in the producers map.
+func isStructuralMime(mt string) bool {
+ return strings.EqualFold(mt, runtime.MultipartFormMime) ||
+ strings.EqualFold(mt, runtime.URLencodedFormMime)
}
diff --git a/vendor/github.com/go-openapi/runtime/client/tls.go b/vendor/github.com/go-openapi/runtime/client/tls.go
new file mode 100644
index 00000000000..017694fae08
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/client/tls.go
@@ -0,0 +1,197 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package client
+
+import (
+ "crypto"
+ "crypto/tls"
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
+ "net/http"
+ "os"
+)
+
+// TLSClientOptions to configure client authentication with mutual TLS.
+type TLSClientOptions struct {
+ // Certificate is the path to a PEM-encoded certificate to be used for
+ // client authentication. If set then Key must also be set.
+ Certificate string
+
+ // LoadedCertificate is the certificate to be used for client authentication.
+ // This field is ignored if Certificate is set. If this field is set, LoadedKey
+ // is also required.
+ LoadedCertificate *x509.Certificate
+
+ // Key is the path to an unencrypted PEM-encoded private key for client
+ // authentication. This field is required if Certificate is set.
+ Key string
+
+ // LoadedKey is the key for client authentication. This field is required if
+ // LoadedCertificate is set.
+ LoadedKey crypto.PrivateKey
+
+ // CA is a path to a PEM-encoded certificate that specifies the root certificate
+ // to use when validating the TLS certificate presented by the server. If this field
+ // (and LoadedCA) is not set, the system certificate pool is used. This field is ignored if LoadedCA
+ // is set.
+ CA string
+
+ // LoadedCA specifies the root certificate to use when validating the server's TLS certificate.
+ // If this field (and CA) is not set, the system certificate pool is used.
+ LoadedCA *x509.Certificate
+
+ // LoadedCAPool specifies a pool of RootCAs to use when validating the server's TLS certificate.
+ // If set, it will be combined with the other loaded certificates (see LoadedCA and CA).
+ // If neither LoadedCA or CA is set, the provided pool will override the system
+ // certificate pool.
+ //
+ // The caller must not use the supplied pool after calling TLSClientAuth.
+ LoadedCAPool *x509.CertPool
+
+ // ServerName specifies the hostname to use when verifying the server certificate.
+ // If this field is set then InsecureSkipVerify will be ignored and treated as
+ // false.
+ ServerName string
+
+ // InsecureSkipVerify controls whether the certificate chain and hostname presented
+ // by the server are validated. If true, any certificate is accepted.
+ InsecureSkipVerify bool
+
+ // VerifyPeerCertificate, if not nil, is called after normal
+ // certificate verification. It receives the raw ASN.1 certificates
+ // provided by the peer and also any verified chains that normal processing found.
+ // If it returns a non-nil error, the handshake is aborted and that error results.
+ //
+ // If normal verification fails then the handshake will abort before
+ // considering this callback. If normal verification is disabled by
+ // setting InsecureSkipVerify then this callback will be considered but
+ // the verifiedChains argument will always be nil.
+ VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
+
+ // VerifyConnection, if not nil, is called after normal certificate
+ // verification and after [TLSClientOptions.VerifyPeerCertificate] by either a TLS client or
+ // server. It receives the [tls.ConnectionState] which may be inspected.
+ //
+ // Unlike VerifyPeerCertificate, this callback is invoked on every
+ // connection, including resumed ones, making it suitable for checks
+ // that must always apply (e.g. certificate pinning).
+ //
+ // If it returns a non-nil error, the handshake is aborted and that error results.
+ VerifyConnection func(tls.ConnectionState) error
+
+ // SessionTicketsDisabled may be set to true to disable session ticket and
+ // PSK (resumption) support. Note that on clients, session ticket support is
+ // also disabled if ClientSessionCache is nil.
+ SessionTicketsDisabled bool
+
+ // ClientSessionCache is a cache of ClientSessionState entries for TLS
+ // session resumption. It is only used by clients.
+ ClientSessionCache tls.ClientSessionCache
+
+ // Prevents callers using unkeyed fields.
+ _ struct{}
+}
+
+// TLSClientAuth creates a [tls.Config] for mutual auth.
+func TLSClientAuth(opts TLSClientOptions) (*tls.Config, error) {
+ // create client tls config
+ cfg := &tls.Config{
+ MinVersion: tls.VersionTLS12,
+ }
+
+ // load client cert if specified
+ if opts.Certificate != "" {
+ cert, err := tls.LoadX509KeyPair(opts.Certificate, opts.Key)
+ if err != nil {
+ return nil, fmt.Errorf("tls client cert: %w", err)
+ }
+ cfg.Certificates = []tls.Certificate{cert}
+ } else if opts.LoadedCertificate != nil {
+ block := pem.Block{Type: "CERTIFICATE", Bytes: opts.LoadedCertificate.Raw}
+ certPem := pem.EncodeToMemory(&block)
+
+ // PKCS#8 covers RSA, ECDSA, Ed25519, X25519 (the key types tls.X509KeyPair
+ // understands) and pairs with the canonical "PRIVATE KEY" PEM label.
+ keyBytes, err := x509.MarshalPKCS8PrivateKey(opts.LoadedKey)
+ if err != nil {
+ return nil, fmt.Errorf("tls client priv key: %w", err)
+ }
+
+ block = pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes}
+ keyPem := pem.EncodeToMemory(&block)
+
+ cert, err := tls.X509KeyPair(certPem, keyPem)
+ if err != nil {
+ return nil, fmt.Errorf("tls client cert: %w", err)
+ }
+ cfg.Certificates = []tls.Certificate{cert}
+ }
+
+ cfg.InsecureSkipVerify = opts.InsecureSkipVerify
+
+ cfg.VerifyPeerCertificate = opts.VerifyPeerCertificate
+ cfg.VerifyConnection = opts.VerifyConnection
+ cfg.SessionTicketsDisabled = opts.SessionTicketsDisabled
+ cfg.ClientSessionCache = opts.ClientSessionCache
+
+ // When no CA certificate is provided, default to the system cert pool
+ // that way when a request is made to a server known by the system trust store,
+ // the name is still verified
+ switch {
+ case opts.LoadedCA != nil:
+ caCertPool := basePool(opts.LoadedCAPool)
+ caCertPool.AddCert(opts.LoadedCA)
+ cfg.RootCAs = caCertPool
+ case opts.CA != "":
+ // load ca cert
+ caCert, err := os.ReadFile(opts.CA)
+ if err != nil {
+ return nil, fmt.Errorf("tls client ca: %w", err)
+ }
+ caCertPool := basePool(opts.LoadedCAPool)
+ caCertPool.AppendCertsFromPEM(caCert)
+ cfg.RootCAs = caCertPool
+ case opts.LoadedCAPool != nil:
+ cfg.RootCAs = opts.LoadedCAPool
+ }
+
+ // apply servername override
+ if opts.ServerName != "" {
+ cfg.InsecureSkipVerify = false
+ cfg.ServerName = opts.ServerName
+ }
+
+ return cfg, nil
+}
+
+// TLSTransport creates a [http.RoundTripper] for a client transport,suitable for mutual TLS auth.
+func TLSTransport(opts TLSClientOptions) (http.RoundTripper, error) {
+ cfg, err := TLSClientAuth(opts)
+ if err != nil {
+ return nil, err
+ }
+
+ return &http.Transport{TLSClientConfig: cfg}, nil
+}
+
+// TLSClient creates a [http.Client] for mutual auth.
+func TLSClient(opts TLSClientOptions) (*http.Client, error) {
+ transport, err := TLSTransport(opts)
+ if err != nil {
+ return nil, err
+ }
+ return &http.Client{Transport: transport}, nil
+}
+
+// basePool returns pool if non-nil; otherwise it returns a new empty cert pool.
+//
+// Clones the pool provided up front by the caller.
+func basePool(pool *x509.CertPool) *x509.CertPool {
+ if pool == nil {
+ return x509.NewCertPool()
+ }
+
+ return pool.Clone()
+}
diff --git a/vendor/github.com/go-openapi/runtime/client_operation.go b/vendor/github.com/go-openapi/runtime/client_operation.go
index ad7277e091f..61f6ead34a2 100644
--- a/vendor/github.com/go-openapi/runtime/client_operation.go
+++ b/vendor/github.com/go-openapi/runtime/client_operation.go
@@ -19,12 +19,30 @@ type ClientOperation struct {
AuthInfo ClientAuthInfoWriter
Params ClientRequestWriter
Reader ClientResponseReader
- Context context.Context //nolint:containedctx // we precisely want this type to contain the request context
- Client *http.Client
+ // Deprecated: prefer [ContextualTransport.SubmitContext] to pass the request context explicitly.
+ Context context.Context //nolint:containedctx // we precisely want this type to contain the request context
+ Client *http.Client
}
// A ClientTransport implementor knows how to submit Request objects to some destination.
type ClientTransport interface {
- // Submit(string, RequestWriter, ResponseReader, AuthInfoWriter) (interface{}, error)
+ // Submit the operation and return the deserialized response or an error.
Submit(*ClientOperation) (any, error)
}
+
+// ContextualTransport extends [ClientTransport] with an explicit
+// context-aware submission method.
+//
+// Wrappers such as the OpenTelemetry transport type-assert to this
+// interface so they can forward an explicit context to the underlying
+// transport without setting the cached [ClientOperation.Context] field.
+//
+// In v2, SubmitContext will be folded into [ClientTransport] itself
+// and the cached [ClientOperation.Context] field removed; this interface
+// is the v0.x bridge.
+type ContextualTransport interface {
+ ClientTransport
+
+ // SubmitContext submits the operation using ctx as the request context.
+ SubmitContext(ctx context.Context, operation *ClientOperation) (any, error)
+}
diff --git a/vendor/github.com/go-openapi/runtime/client_response.go b/vendor/github.com/go-openapi/runtime/client_response.go
index 92668db4ece..7b4b7e40df7 100644
--- a/vendor/github.com/go-openapi/runtime/client_response.go
+++ b/vendor/github.com/go-openapi/runtime/client_response.go
@@ -59,7 +59,7 @@ func (o *APIError) Error() string {
if err, ok := o.Response.(error); ok {
resp = []byte("'" + sanitizer.Replace(err.Error()) + "'")
} else {
- resp, _ = json.Marshal(o.Response)
+ resp, _ = json.Marshal(o.Response) //nolint:errchkjson // error swallowed as this is our last best effort attempt
}
return fmt.Sprintf("%s (status %d): %s", o.OperationName, o.Code, resp)
diff --git a/vendor/github.com/go-openapi/runtime/constants.go b/vendor/github.com/go-openapi/runtime/constants.go
index 80de6c80868..ea86cfadbc1 100644
--- a/vendor/github.com/go-openapi/runtime/constants.go
+++ b/vendor/github.com/go-openapi/runtime/constants.go
@@ -21,8 +21,12 @@ const (
DefaultMime = "application/octet-stream"
// JSONMime the json mime type.
JSONMime = "application/json"
- // YAMLMime the [yaml] mime type.
- YAMLMime = "application/x-yaml"
+ // YAMLMime the [yaml] mime type. Set to the canonical RFC 9512
+ // name (application/yaml). Legacy forms application/x-yaml,
+ // text/yaml, and text/x-yaml — per RFC 9512 §2.1 "Deprecated
+ // alias names for this type" — resolve to the same codec via
+ // the mediatype alias bridge.
+ YAMLMime = "application/yaml"
// XMLMime the [xml] mime type.
XMLMime = "application/xml"
// TextMime the text mime type.
diff --git a/vendor/github.com/go-openapi/runtime/csv.go b/vendor/github.com/go-openapi/runtime/csv.go
index 558d0cb99aa..11d60872c3e 100644
--- a/vendor/github.com/go-openapi/runtime/csv.go
+++ b/vendor/github.com/go-openapi/runtime/csv.go
@@ -100,7 +100,7 @@ func CSVConsumer(opts ...CSVOpt) Consumer {
default:
// support *[][]string, *[]byte, *string
- if ptr := reflect.TypeOf(data); ptr.Kind() != reflect.Ptr {
+ if ptr := reflect.TypeOf(data); ptr.Kind() != reflect.Pointer {
return errors.New("destination must be a pointer")
}
@@ -159,14 +159,14 @@ func CSVConsumer(opts ...CSVOpt) Consumer {
//
// Supported input underlying types and interfaces, prioritized in this order:
//
-// - *[csv.Reader]
-// - [CSVReader] (reader options are ignored)
-// - [io.Reader]
-// - [io.WriterTo]
-// - [encoding.BinaryMarshaler]
-// - [][]string
-// - []byte
-// - string
+// - *[csv.Reader]
+// - [CSVReader] (reader options are ignored)
+// - [io.Reader]
+// - [io.WriterTo]
+// - [encoding.BinaryMarshaler]
+// - [][]string
+// - []byte
+// - string
//
// The producer prioritizes situations where buffering the input is not required.
func CSVProducer(opts ...CSVOpt) Producer {
diff --git a/vendor/github.com/go-openapi/runtime/file.go b/vendor/github.com/go-openapi/runtime/file.go
index 2a85379a748..0420db9440a 100644
--- a/vendor/github.com/go-openapi/runtime/file.go
+++ b/vendor/github.com/go-openapi/runtime/file.go
@@ -5,4 +5,10 @@ package runtime
import "github.com/go-openapi/swag/fileutils"
+// File represents an uploaded file. Re-exported from
+// [fileutils.File] for backwards compatibility.
+//
+// See [BindForm] (in form.go) for the orchestrator that parses
+// multipart / urlencoded request bodies and binds declared file
+// fields onto handler-side targets.
type File = fileutils.File
diff --git a/vendor/github.com/go-openapi/runtime/form.go b/vendor/github.com/go-openapi/runtime/form.go
new file mode 100644
index 00000000000..b4b36f14705
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/form.go
@@ -0,0 +1,355 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package runtime
+
+import (
+ stderrors "errors"
+ "fmt"
+ "mime/multipart"
+ "net/http"
+ "strings"
+
+ "github.com/go-openapi/errors"
+)
+
+// DefaultMaxUploadFilenameLength is the default cap applied to
+// FileHeader.Filename for each declared file when [BindForm] is invoked
+// without an explicit [BindFormMaxFilenameLen] option.
+//
+// Multipart headers are allocated per part; an attacker submitting
+// multi-MB filenames inflates the parser's memory footprint. 1 KiB
+// matches the IETF guidance for sane filename length and is enough
+// for realistic uploads.
+const DefaultMaxUploadFilenameLength = 1024
+
+// DefaultMaxUploadBodySize limits the size of the body to upload forms to 32MB.
+//
+// Use an explicit [BindFormMaxBody] option to change this limit.
+const DefaultMaxUploadBodySize = int64(32) << 20
+
+// filenamePreviewLen caps the byte length of the FileHeader.Filename
+// preview embedded as the ParseError.Value field when the helper
+// rejects a too-long filename.
+const filenamePreviewLen = 32
+
+// ValidateFilenameLength enforces the FileHeader.Filename length cap
+// that [BindForm] applies via [BindFormFile] declarations. Untyped
+// binder paths that fetch the file via [http.Request.FormFile]
+// directly (rather than declaring the file through [BindFormFile]) call
+// this to opt into the same protection.
+//
+// Returns nil if filename length is within maxLen or maxLen <= 0.
+// Otherwise returns a [*errors.ParseError] suitable for direct return
+// from a parameter binder. The error embeds a truncated preview of
+// the offending filename to keep the error message bounded.
+func ValidateFilenameLength(paramName, paramIn, filename string, maxLen int) error {
+ if maxLen <= 0 || len(filename) <= maxLen {
+ return nil
+ }
+ preview := filename[:min(len(filename), filenamePreviewLen)]
+ return errors.NewParseError(paramName, paramIn, preview,
+ fmt.Errorf("filename length %d exceeds limit %d", len(filename), maxLen))
+}
+
+// FileBinder is the per-file callback invoked by [BindForm] when a
+// declared file field is present.
+//
+// The callback is responsible for BOTH validating the file (size, MIME, etc.) AND assigning the bound
+// file to its destination — typically using:
+//
+// o.FieldName = &runtime.File{Data: file, Header: header}
+//
+// Returning a non-nil error surfaces the error in [BindForm]'s per-field
+// accumulator. Errors from the binder flow through verbatim — the
+// binder is expected to produce HTTP-aware errors (e.g.
+// [errors.ExceedsMaximum] from go-openapi/validate).
+type FileBinder func(file multipart.File, header *multipart.FileHeader) error
+
+// BindOption configures [BindForm]. The variadic style keeps simple
+// call sites simple and lets new knobs (security caps, additional
+// behaviour) be added without breaking the signature.
+type BindOption func(*bindConfig)
+
+type bindConfig struct {
+ maxParseMemory int64
+ maxBody int64
+ maxFiles int
+ maxFilenameLen int
+ files []formFileSpec
+}
+
+type formFileSpec struct {
+ name string
+ required bool
+ bind FileBinder
+}
+
+// BindFormMaxParseMemory caps the in-memory portion of a multipart
+// body. Bytes beyond this are spilled to temporary files on disk by
+// the stdlib parser. 0 (the default) defers to the stdlib's 32 MB.
+//
+// This option does NOT cap total body bytes — see [BindFormMaxBody]
+// for that. The default body cap ([DefaultMaxUploadBodySize] = 32 MB)
+// is applied even when this option is not supplied, so out of the box
+// [BindForm] is bounded; callers with stricter or looser requirements
+// adjust via [BindFormMaxBody].
+func BindFormMaxParseMemory(n int64) BindOption {
+ return func(c *bindConfig) { c.maxParseMemory = n }
+}
+
+// BindFormMaxBody caps the size of the body read from a http form before parsing.
+//
+// The limit is set to 32MB by default. This default limit is applied for any n=0.
+//
+// The limit is disabled for n<0, assuming the caller has already capped the body size upstream.
+func BindFormMaxBody(n int64) BindOption {
+ return func(c *bindConfig) { c.maxBody = n }
+}
+
+// BindFormMaxFiles rejects parses where the total number of file
+// parts across all field names exceeds n. 0 (the default) means no
+// cap. Exceeding the cap is a fatal error — [BindForm] returns
+// fatal=true and no per-file binders run.
+func BindFormMaxFiles(n int) BindOption {
+ return func(c *bindConfig) { c.maxFiles = n }
+}
+
+// BindFormMaxFilenameLen rejects per-file headers whose Filename
+// length exceeds n. 0 means no cap; the default applied when this
+// option is not supplied is [DefaultMaxUploadFilenameLength]. The
+// cap is a per-field bind error (non-fatal); other declared files
+// still run.
+func BindFormMaxFilenameLen(n int) BindOption {
+ return func(c *bindConfig) { c.maxFilenameLen = n }
+}
+
+// BindFormFile declares a file field to bind under the given form
+// name. If required is true and the field is absent, [BindForm]
+// produces the per-field error.
+//
+// errors.NewParseError(name, "formData", "", http.ErrMissingFile)
+//
+// If required is false, absence is silent (no error, no bind).
+//
+// The bind callback runs only when the field is present. It is the
+// site where both validation and assignment happen — see [FileBinder].
+//
+// FileHeader.Filename is attacker-controlled text; the binder MUST
+// NOT use it directly as a filesystem path. The helper does not
+// touch the filesystem.
+func BindFormFile(name string, required bool, bind FileBinder) BindOption {
+ return func(c *bindConfig) {
+ c.files = append(c.files, formFileSpec{
+ name: name,
+ required: required,
+ bind: bind,
+ })
+ }
+}
+
+// BindForm parses r as multipart/form-data, falling back to
+// application/x-www-form-urlencoded when the request is not
+// multipart. On success, r.MultipartForm and r.PostForm are populated;
+// the caller can read non-file form values via [Values](r.Form) after
+// the call returns.
+//
+// All errors produced by BindForm itself (parse failure, missing
+// required field, cap exceeded) are [*errors.ParseError] values built
+// via [errors.NewParseError], matching the untyped
+// middleware/parameter.go path. Errors returned by per-file binders
+// flow through verbatim — binders own their HTTP-aware error shape.
+//
+// Per-file binders declared via [BindFormFile] run in declaration
+// order after a successful parse. Their errors are accumulated and
+// returned wrapped in [errors.CompositeValidationError]; the caller
+// typically appends the returned err to its own []error and continues
+// with non-file parameter binding.
+//
+// Return semantics:
+//
+// - fatal=true, err!=nil: parse failure or a hard cap (e.g.
+// [BindFormMaxFiles]) was exceeded. No per-file binders ran; the
+// caller MUST return err immediately.
+// - fatal=false, err!=nil: one or more per-file binders produced
+// errors. The form parsed successfully; r.Form is populated. The
+// caller appends err to its accumulator and continues.
+// - fatal=false, err==nil: full success.
+//
+// fatal==true implies err!=nil.
+//
+// Defaults applied out of the box:
+//
+// - Total body bytes capped at [DefaultMaxUploadBodySize] (32 MB)
+// via [http.MaxBytesReader]. Adjust with [BindFormMaxBody]
+// (negative n disables, when the caller has already capped the
+// body upstream).
+// - FileHeader.Filename length capped at
+// [DefaultMaxUploadFilenameLength]. Adjust with
+// [BindFormMaxFilenameLen].
+//
+// Caller responsibilities the helper does NOT cover:
+//
+// - Set [http.Server.ReadTimeout] / [http.Server.IdleTimeout] to defend
+// against slow-read attacks.
+// - Decompress Content-Encoding: gzip request bodies upstream if
+// the API accepts them, using a size-limited reader.
+// - Treat FileHeader.Filename as untrusted user input; never use
+// it directly as a filesystem path.
+func BindForm(r *http.Request, opts ...BindOption) (fatal bool, err error) {
+ cfg := bindConfig{
+ maxFilenameLen: DefaultMaxUploadFilenameLength,
+ }
+ for _, opt := range opts {
+ opt(&cfg)
+ }
+
+ if perr := parseFormBody(r, cfg.maxParseMemory, cfg.maxBody); perr != nil {
+ // Body-cap hit gets the 413 status; everything else maps to a
+ // 400 ParseError. parseFormBody returns the raw stdlib error
+ // in both cases — the HTTP-aware wrapping happens here.
+ var maxBytesErr *http.MaxBytesError
+ if stderrors.As(perr, &maxBytesErr) {
+ return true, errors.New(http.StatusRequestEntityTooLarge, "formData: %v", perr)
+ }
+ return true, errors.NewParseError("body", "formData", "", perr)
+ }
+
+ if cfg.maxFiles > 0 {
+ if got := countFileParts(r); got > cfg.maxFiles {
+ return true, errors.NewParseError("body", "formData", "",
+ fmt.Errorf("multipart form contains %d file parts, exceeds limit %d", got, cfg.maxFiles))
+ }
+ }
+
+ var bindErrs []error
+ for _, spec := range cfg.files {
+ if e := bindFormFile(r, spec, cfg.maxFilenameLen); e != nil {
+ bindErrs = append(bindErrs, e)
+ }
+ }
+ if len(bindErrs) > 0 {
+ return false, errors.CompositeValidationError(bindErrs...)
+ }
+ return false, nil
+}
+
+// parseFormBody parses the request body. Content-Type drives the
+// parser: multipart/form-data → r.ParseMultipartForm, everything else
+// → r.ParseForm (stdlib's parsePostForm only actually reads the body
+// when Content-Type is application/x-www-form-urlencoded, so calling
+// ParseForm is safe for unrecognised types).
+//
+// Caveat: ParseMultipartForm calls ParseForm internally and discards its error
+// when the body turns out not to be multipart, returning ErrNotMultipart instead
+// — the subsequent retry then short-circuits because r.PostForm is already
+// set. Content-type-based routing avoids the lossy detour.
+//
+// Returns the raw stdlib error on failure; the caller (BindForm)
+// handles HTTP-aware wrapping (413 for MaxBytesError, 400 ParseError
+// otherwise).
+//
+// maxMemory == 0 falls through to the stdlib default (32 MB).
+// maxBody == 0 defaults to DefaultMaxUploadBodySize; maxBody < 0
+// disables the body cap (caller has capped upstream).
+func parseFormBody(r *http.Request, maxMemory, maxBody int64) error {
+ if r.Body != nil && maxBody >= 0 {
+ if maxBody == 0 {
+ maxBody = DefaultMaxUploadBodySize
+ }
+ r.Body = http.MaxBytesReader(nil, r.Body, maxBody)
+ }
+
+ mt, _, _ := ContentType(r.Header)
+ if mt == MultipartFormMime {
+ //nolint:gosec // G120: false positive -- see below
+ // gosec doesn't track the Body.
+ // See https://github.com/securego/gosec/blob/de65614d10a6b84029e3e1215567b8ce7e490f23/testutils/g120_samples.go#L57
+ return r.ParseMultipartForm(maxMemory)
+ }
+ return r.ParseForm()
+}
+
+func countFileParts(r *http.Request) int {
+ if r.MultipartForm == nil {
+ return 0
+ }
+ var n int
+ for _, fhs := range r.MultipartForm.File {
+ n += len(fhs)
+ }
+
+ return n
+}
+
+// FormFile resolves a file field from a parsed form body, transparently
+// handling both content types accepted for `type: file` parameters by
+// the OpenAPI 2.0 spec:
+//
+// - multipart/form-data — delegates to [http.Request.FormFile].
+// - application/x-www-form-urlencoded — looks up the field in
+// r.PostForm and synthesizes a [multipart.File] backed by the
+// value bytes plus a [multipart.FileHeader] with Filename equal
+// to the field name and Size set to the byte length.
+//
+// Returns [http.ErrMissingFile] when the field is absent under either
+// content type. Callers must have parsed the body upstream (e.g. via
+// [BindForm] or [http.Request.ParseForm]) before reading from the
+// urlencoded path — [http.Request.FormFile] takes care of parsing on
+// the multipart path.
+//
+// Presence is the only criterion for binding a urlencoded file: an
+// empty value (e.g. `file=`) is bound as a zero-byte file.
+func FormFile(r *http.Request, name string) (multipart.File, *multipart.FileHeader, error) {
+ file, header, err := r.FormFile(name)
+ if err == nil {
+ return file, header, nil
+ }
+ if !stderrors.Is(err, http.ErrNotMultipart) {
+ return nil, nil, err
+ }
+
+ values, present := r.PostForm[name]
+ if !present {
+ return nil, nil, http.ErrMissingFile
+ }
+ value := values[0]
+ return urlencodedFile{Reader: strings.NewReader(value)},
+ &multipart.FileHeader{Filename: name, Size: int64(len(value))},
+ nil
+}
+
+// urlencodedFile adapts a urlencoded form value (already buffered in
+// memory by [http.Request.ParseForm]) to the [multipart.File]
+// interface. The embedded [strings.Reader] supplies Read/ReadAt/Seek;
+// Close is a no-op since there is no resource to release.
+type urlencodedFile struct {
+ *strings.Reader
+}
+
+func (urlencodedFile) Close() error { return nil }
+
+func bindFormFile(r *http.Request, spec formFileSpec, maxFilenameLen int) error {
+ file, header, err := FormFile(r, spec.name)
+ if err != nil {
+ if stderrors.Is(err, http.ErrMissingFile) {
+ if spec.required {
+ return errors.New(http.StatusBadRequest, "formData: %v", http.ErrMissingFile)
+ }
+
+ return nil
+ }
+
+ return errors.NewParseError(spec.name, "formData", "", err)
+ }
+
+ if err := ValidateFilenameLength(spec.name, "formData", header.Filename, maxFilenameLen); err != nil {
+ return err
+ }
+
+ if spec.bind == nil {
+ return nil
+ }
+
+ return spec.bind(file, header)
+}
diff --git a/vendor/github.com/go-openapi/runtime/go.work b/vendor/github.com/go-openapi/runtime/go.work
index b4cd9e01e86..73479f9ad8f 100644
--- a/vendor/github.com/go-openapi/runtime/go.work
+++ b/vendor/github.com/go-openapi/runtime/go.work
@@ -1,6 +1,8 @@
use (
.
./client-middleware/opentracing
+ ./docs/examples
+ ./server-middleware
)
-go 1.24.0
+go 1.25.0
diff --git a/vendor/github.com/go-openapi/runtime/go.work.sum b/vendor/github.com/go-openapi/runtime/go.work.sum
deleted file mode 100644
index b24a8cfaf94..00000000000
--- a/vendor/github.com/go-openapi/runtime/go.work.sum
+++ /dev/null
@@ -1,109 +0,0 @@
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/go-openapi/errors v0.22.2/go.mod h1:+n/5UdIqdVnLIJ6Q9Se8HNGUXYaY6CN8ImWzfi/Gzp0=
-github.com/go-openapi/jsonpointer v0.22.0/go.mod h1:xt3jV88UtExdIkkL7NloURjRQjbeUgcxFblMjq2iaiU=
-github.com/go-openapi/jsonreference v0.21.1/go.mod h1:PWs8rO4xxTUqKGu+lEvvCxD5k2X7QYkKAepJyCmSTT8=
-github.com/go-openapi/swag v0.24.1/go.mod h1:sm8I3lCPlspsBBwUm1t5oZeWZS0s7m/A+Psg0ooRU0A=
-github.com/go-openapi/swag/cmdutils v0.24.0/go.mod h1:uxib2FAeQMByyHomTlsP8h1TtPd54Msu2ZDU/H5Vuf8=
-github.com/go-openapi/swag/conv v0.24.0/go.mod h1:jbn140mZd7EW2g8a8Y5bwm8/Wy1slLySQQ0ND6DPc2c=
-github.com/go-openapi/swag/fileutils v0.24.0/go.mod h1:3SCrCSBHyP1/N+3oErQ1gP+OX1GV2QYFSnrTbzwli90=
-github.com/go-openapi/swag/jsonname v0.24.0/go.mod h1:GXqrPzGJe611P7LG4QB9JKPtUZ7flE4DOVechNaDd7Q=
-github.com/go-openapi/swag/jsonutils v0.24.0/go.mod h1:vBowZtF5Z4DDApIoxcIVfR8v0l9oq5PpYRUuteVu6f0=
-github.com/go-openapi/swag/loading v0.24.0/go.mod h1:gShCN4woKZYIxPxbfbyHgjXAhO61m88tmjy0lp/LkJk=
-github.com/go-openapi/swag/mangling v0.24.0/go.mod h1:Jm5Go9LHkycsz0wfoaBDkdc4CkpuSnIEf62brzyCbhc=
-github.com/go-openapi/swag/netutils v0.24.0/go.mod h1:WRgiHcYTnx+IqfMCtu0hy9oOaPR0HnPbmArSRN1SkZM=
-github.com/go-openapi/swag/stringutils v0.24.0/go.mod h1:5nUXB4xA0kw2df5PRipZDslPJgJut+NjL7D25zPZ/4w=
-github.com/go-openapi/swag/typeutils v0.24.0/go.mod h1:q8C3Kmk/vh2VhpCLaoR2MVWOGP8y7Jc8l82qCTd1DYI=
-github.com/go-openapi/swag/yamlutils v0.24.0/go.mod h1:DpKv5aYuaGm/sULePoeiG8uwMpZSfReo1HR3Ik0yaG8=
-github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM=
-github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
-github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
-github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
-github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
-github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30 h1:BHT1/DKsYDGkUgQ2jmMaozVcdk+sVfz0+1ZJq4zkWgw=
-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
-github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
-github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
-github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
-github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
-github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
-github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
-github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
-github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
-github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
-go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
-golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
-golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
-golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
-golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
-golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
-golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
-golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
-golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
-golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
-golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
-golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
-golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488/go.mod h1:fGb/2+tgXXjhjHsTNdVEEMZNWA0quBnfrO+AfoDSAKw=
-golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
-golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
-golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
-golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
-golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
-golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
-golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
-golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
-golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
-golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
-golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/vendor/github.com/go-openapi/runtime/interfaces.go b/vendor/github.com/go-openapi/runtime/interfaces.go
index a8b4b318d9c..85211989078 100644
--- a/vendor/github.com/go-openapi/runtime/interfaces.go
+++ b/vendor/github.com/go-openapi/runtime/interfaces.go
@@ -99,3 +99,25 @@ type Validatable interface {
type ContextValidatable interface {
ContextValidate(context.Context, strfmt.Registry) error
}
+
+// ContentTyper is implemented by values that declare their own MIME
+// content type. The client runtime consults it in two places:
+//
+// - on a body payload set via [SetBodyParam]: when the payload is a
+// stream (io.Reader, io.ReadCloser) and ContentType returns a
+// non-empty value, that value becomes the wire Content-Type
+// header instead of the operation's picked consumes entry.
+//
+// - on individual file values inside a multipart upload: their per-
+// part Content-Type header is taken from ContentType() rather
+// than sniffed via http.DetectContentType.
+//
+// An empty string return is treated as "no opinion" and the runtime
+// falls back to its default selection. Values that have no content
+// type to declare may simply not implement the interface.
+//
+// See docs/MEDIA_TYPES.md for the full client-side selection
+// algorithm.
+type ContentTyper interface {
+ ContentType() string
+}
diff --git a/vendor/github.com/go-openapi/runtime/middleware/context.go b/vendor/github.com/go-openapi/runtime/middleware/context.go
index 1f85e86b538..8291f63a72d 100644
--- a/vendor/github.com/go-openapi/runtime/middleware/context.go
+++ b/vendor/github.com/go-openapi/runtime/middleware/context.go
@@ -5,10 +5,9 @@ package middleware
import (
stdContext "context"
+ stderrors "errors"
"fmt"
"net/http"
- "net/url"
- "path"
"strings"
"sync"
@@ -17,19 +16,21 @@ import (
"github.com/go-openapi/loads"
"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
+ "github.com/go-openapi/swag/typeutils"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/logger"
"github.com/go-openapi/runtime/middleware/untyped"
"github.com/go-openapi/runtime/security"
+ "github.com/go-openapi/runtime/server-middleware/docui"
+ "github.com/go-openapi/runtime/server-middleware/mediatype"
+ "github.com/go-openapi/runtime/server-middleware/negotiate"
)
// Debug when true turns on verbose logging.
var Debug = logger.DebugEnabled()
// Logger is the standard library logger used for printing debug messages.
-//
-// (Note: The correct spelling is "library", not "libra". "Libra" is a zodiac sign/constellation and wouldn't make sense in this context.)
var Logger logger.Logger = logger.StandardLogger{}
func debugLogfFunc(lg logger.Logger) func(string, ...any) {
@@ -75,11 +76,103 @@ func (fn ResponderFunc) WriteResponse(rw http.ResponseWriter, pr runtime.Produce
// used throughout to store request context with the standard context attached
// to the [http.Request].
type Context struct {
- spec *loads.Document
- analyzer *analysis.Spec
- api RoutableAPI
- router Router
- debugLogf func(string, ...any) // a logging function to debug context and all components using it
+ spec *loads.Document
+ analyzer *analysis.Spec
+ api RoutableAPI
+ router Router
+ debugLogf func(string, ...any) // a logging function to debug context and all components using it
+ ignoreParameters bool // see SetIgnoreParameters / WithIgnoreParameters
+ matchSuffix bool // see SetMatchSuffix / WithMatchSuffix
+}
+
+// NewRoutableContext creates a new context for a routable API.
+//
+// If a nil Router is provided, the [DefaultRouter] ([denco]-based) will be used.
+func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Router) *Context {
+ var an *analysis.Spec
+ if spec != nil {
+ an = analysis.New(spec.Spec())
+ }
+
+ return NewRoutableContextWithAnalyzedSpec(spec, an, routableAPI, routes)
+}
+
+// NewRoutableContextWithAnalyzedSpec is like [NewRoutableContext] but takes as input an already analysed spec.
+//
+// If a nil Router is provided, the [DefaultRouter] ([denco]-based) will be used.
+func NewRoutableContextWithAnalyzedSpec(spec *loads.Document, an *analysis.Spec, routableAPI RoutableAPI, routes Router) *Context {
+ // Either there are no spec doc and analysis, or both of them.
+ if (spec != nil || an != nil) && (spec == nil || an == nil) {
+ panic(fmt.Errorf("%d: %s", http.StatusInternalServerError, "routable context requires either both spec doc and analysis, or none of them"))
+ }
+
+ return &Context{
+ spec: spec,
+ api: routableAPI,
+ analyzer: an,
+ router: routes,
+ debugLogf: debugLogfFunc(nil),
+ }
+}
+
+// NewContext creates a new context wrapper.
+//
+// If a nil Router is provided, the [DefaultRouter] ([denco]-based) will be used.
+func NewContext(spec *loads.Document, api *untyped.API, routes Router) *Context {
+ var an *analysis.Spec
+ if spec != nil {
+ an = analysis.New(spec.Spec())
+ }
+ ctx := &Context{
+ spec: spec,
+ analyzer: an,
+ router: routes,
+ debugLogf: debugLogfFunc(nil),
+ }
+ ctx.api = newRoutableUntypedAPI(spec, api, ctx)
+
+ return ctx
+}
+
+// Serve serves the specified spec with the specified api registrations as a [http.Handler].
+func Serve(spec *loads.Document, api *untyped.API) http.Handler {
+ return ServeWithBuilder(spec, api, PassthroughBuilder)
+}
+
+// SetIgnoreParameters toggles the legacy parameter-stripping behaviour for
+// Accept negotiation server-wide. When set, every internal call to
+// [NegotiateContentType] from this Context applies [WithIgnoreParameters].
+//
+// Returns the receiver for fluent configuration:
+//
+// ctx := middleware.NewContext(spec, api, nil).SetIgnoreParameters(true)
+//
+// See [WithIgnoreParameters] for the rationale and an example.
+func (c *Context) SetIgnoreParameters(ignore bool) *Context {
+ c.ignoreParameters = ignore
+
+ return c
+}
+
+// SetMatchSuffix toggles RFC 6839 structured-syntax suffix tolerance
+// server-wide. When enabled, both Accept negotiation and codec lookup
+// fall back through the suffix base for the recognised suffixes
+// (+json, +xml, +yaml) — so an operation declaring
+// consumes: [application/json] also accepts request bodies sent with
+// Content-Type: application/vnd.api+json (or any other +json variant).
+//
+// Default: strict (false). Use only when interoperating with clients
+// that do not strictly abide by the spec.
+//
+// Returns the receiver for fluent configuration:
+//
+// ctx := middleware.NewContext(spec, api, nil).SetMatchSuffix(true)
+//
+// See [negotiate.WithMatchSuffix] for the per-call form and rationale.
+func (c *Context) SetMatchSuffix(enable bool) *Context {
+ c.matchSuffix = enable
+
+ return c
}
type routableUntypedAPI struct {
@@ -95,53 +188,57 @@ func newRoutableUntypedAPI(spec *loads.Document, api *untyped.API, context *Cont
if spec == nil || api == nil {
return nil
}
+
analyzer := analysis.New(spec.Spec())
for method, hls := range analyzer.Operations() {
um := strings.ToUpper(method)
for path, op := range hls {
schemes := analyzer.SecurityRequirementsFor(op)
- if oh, ok := api.OperationHandlerFor(method, path); ok {
- if handlers == nil {
- handlers = make(map[string]map[string]http.Handler)
+ oh, ok := api.OperationHandlerFor(method, path)
+ if !ok {
+ continue
+ }
+
+ if handlers == nil {
+ handlers = make(map[string]map[string]http.Handler)
+ }
+ if b, ok := handlers[um]; !ok || b == nil {
+ handlers[um] = make(map[string]http.Handler)
+ }
+
+ var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // lookup route info in the context
+ route, rCtx, _ := context.RouteInfo(r)
+ if rCtx != nil {
+ r = rCtx
}
- if b, ok := handlers[um]; !ok || b == nil {
- handlers[um] = make(map[string]http.Handler)
+
+ // bind and validate the request using reflection
+ var bound any
+ var validation error
+ bound, r, validation = context.BindAndValidate(r, route)
+ if validation != nil {
+ context.Respond(w, r, route.Produces, route, validation)
+ return
}
- var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- // lookup route info in the context
- route, rCtx, _ := context.RouteInfo(r)
- if rCtx != nil {
- r = rCtx
- }
-
- // bind and validate the request using reflection
- var bound any
- var validation error
- bound, r, validation = context.BindAndValidate(r, route)
- if validation != nil {
- context.Respond(w, r, route.Produces, route, validation)
- return
- }
-
- // actually handle the request
- result, err := oh.Handle(bound)
- if err != nil {
- // respond with failure
- context.Respond(w, r, route.Produces, route, err)
- return
- }
-
- // respond with success
- context.Respond(w, r, route.Produces, route, result)
- })
-
- if len(schemes) > 0 {
- handler = newSecureAPI(context, handler)
+ // actually handle the request
+ result, err := oh.Handle(bound)
+ if err != nil {
+ // respond with failure
+ context.Respond(w, r, route.Produces, route, err)
+ return
}
- handlers[um][path] = handler
+
+ // respond with success
+ context.Respond(w, r, route.Produces, route, result)
+ })
+
+ if len(schemes) > 0 {
+ handler = newSecureAPI(context, handler)
}
+ handlers[um][path] = handler
}
}
@@ -192,60 +289,6 @@ func (r *routableUntypedAPI) DefaultConsumes() string {
return r.defaultConsumes
}
-// NewRoutableContext creates a new context for a routable API.
-//
-// If a nil Router is provided, the [DefaultRouter] ([denco]-based) will be used.
-func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Router) *Context {
- var an *analysis.Spec
- if spec != nil {
- an = analysis.New(spec.Spec())
- }
-
- return NewRoutableContextWithAnalyzedSpec(spec, an, routableAPI, routes)
-}
-
-// NewRoutableContextWithAnalyzedSpec is like [NewRoutableContext] but takes as input an already analysed spec.
-//
-// If a nil Router is provided, the [DefaultRouter] ([denco]-based) will be used.
-func NewRoutableContextWithAnalyzedSpec(spec *loads.Document, an *analysis.Spec, routableAPI RoutableAPI, routes Router) *Context {
- // Either there are no spec doc and analysis, or both of them.
- if (spec != nil || an != nil) && (spec == nil || an == nil) {
- panic(fmt.Errorf("%d: %s", http.StatusInternalServerError, "routable context requires either both spec doc and analysis, or none of them"))
- }
-
- return &Context{
- spec: spec,
- api: routableAPI,
- analyzer: an,
- router: routes,
- debugLogf: debugLogfFunc(nil),
- }
-}
-
-// NewContext creates a new context wrapper.
-//
-// If a nil Router is provided, the [DefaultRouter] ([denco]-based) will be used.
-func NewContext(spec *loads.Document, api *untyped.API, routes Router) *Context {
- var an *analysis.Spec
- if spec != nil {
- an = analysis.New(spec.Spec())
- }
- ctx := &Context{
- spec: spec,
- analyzer: an,
- router: routes,
- debugLogf: debugLogfFunc(nil),
- }
- ctx.api = newRoutableUntypedAPI(spec, api, ctx)
-
- return ctx
-}
-
-// Serve serves the specified spec with the specified api registrations as a [http.Handler].
-func Serve(spec *loads.Document, api *untyped.API) http.Handler {
- return ServeWithBuilder(spec, api, PassthroughBuilder)
-}
-
// ServeWithBuilder serves the specified spec with the specified api registrations as a [http.Handler] that is decorated
// by the Builder.
func ServeWithBuilder(spec *loads.Document, api *untyped.API, builder Builder) http.Handler {
@@ -319,57 +362,42 @@ func (c *Context) RequiredProduces() []string {
// BindValidRequest binds a params object to a request but only when the request is valid
// if the request is not valid an error will be returned.
func (c *Context) BindValidRequest(request *http.Request, route *MatchedRoute, binder RequestBinder) error {
- var res []error
var requestContentType string
// check and validate content type, select consumer
if runtime.HasBody(request) {
- ct, _, err := runtime.ContentType(request.Header)
+ ct, cons, err := c.bindRequestBody(request, route)
if err != nil {
- res = append(res, err)
- } else {
- c.debugLogf("validating content type for %q against [%s]", ct, strings.Join(route.Consumes, ", "))
- if err := validateContentType(route.Consumes, ct); err != nil {
- res = append(res, err)
- }
- if len(res) == 0 {
- cons, ok := route.Consumers[ct]
- if !ok {
- res = append(res, errors.New(http.StatusInternalServerError, "no consumer registered for %s", ct))
- } else {
- route.Consumer = cons
- requestContentType = ct
- }
- }
+ return errors.CompositeValidationError(err)
}
+
+ // happy path
+ requestContentType = ct
+ route.Consumer = cons
}
// check and validate the response format
- if len(res) == 0 {
- // if the route does not provide Produces and a default contentType could not be identified
- // based on a body, typical for GET and DELETE requests, then default contentType to.
- if len(route.Produces) == 0 && requestContentType == "" {
- requestContentType = "*/*"
- }
+ // if the route does not provide Produces and a default contentType could not be identified
+ // based on a body, typical for GET and DELETE requests, then default contentType to.
+ if len(route.Produces) == 0 && requestContentType == "" {
+ requestContentType = "*/*"
+ }
- if str := NegotiateContentType(request, route.Produces, requestContentType); str == "" {
- res = append(res, errors.InvalidResponseFormat(request.Header.Get(runtime.HeaderAccept), route.Produces))
- }
+ str := negotiate.ContentType(request, route.Produces, requestContentType, c.negotiateOpts()...)
+ if str == "" {
+ return errors.CompositeValidationError(
+ errors.InvalidResponseFormat(request.Header.Get(runtime.HeaderAccept), route.Produces),
+ )
+ }
+
+ if binder == nil {
+ return nil
}
// now bind the request with the provided binder
// it's assumed the binder will also validate the request and return an error if the
// request is invalid
- if binder != nil && len(res) == 0 {
- if err := binder.BindRequest(request, route); err != nil {
- return err
- }
- }
-
- if len(res) > 0 {
- return errors.CompositeValidationError(res...)
- }
- return nil
+ return binder.BindRequest(request, route)
}
// ContentType gets the parsed value of a content type
@@ -431,7 +459,7 @@ func (c *Context) ResponseFormat(r *http.Request, offers []string) (string, *htt
return v, r
}
- format := NegotiateContentType(r, offers, "")
+ format := negotiate.ContentType(r, offers, "", c.negotiateOpts()...)
if format != "" {
c.debugLogf("[%s %s] set response format %q in context", r.Method, r.URL.Path, format)
r = r.WithContext(stdContext.WithValue(rCtx, ctxResponseFormat, format))
@@ -453,44 +481,6 @@ func (c *Context) ResetAuth(request *http.Request) *http.Request {
return request.WithContext(rctx)
}
-// Authorize authorizes the request
-// Returns the principal object and a shallow copy of the request when its
-// context doesn't contain the principal, otherwise the same request or an error
-// (the last) if one of the authenticators returns one or an Unauthenticated error.
-func (c *Context) Authorize(request *http.Request, route *MatchedRoute) (any, *http.Request, error) {
- if route == nil || !route.HasAuth() {
- return nil, nil, nil
- }
-
- var rCtx = request.Context()
- if v := rCtx.Value(ctxSecurityPrincipal); v != nil {
- return v, request, nil
- }
-
- applies, usr, err := route.Authenticators.Authenticate(request, route)
- if !applies || err != nil || !route.Authenticators.AllowsAnonymous() && usr == nil {
- if err != nil {
- return nil, nil, err
- }
- return nil, nil, errors.Unauthenticated("invalid credentials")
- }
- if route.Authorizer != nil {
- if err := route.Authorizer.Authorize(request, usr); err != nil {
- if _, ok := err.(errors.Error); ok {
- return nil, nil, err
- }
-
- return nil, nil, errors.New(http.StatusForbidden, "%v", err)
- }
- }
-
- rCtx = request.Context()
-
- rCtx = stdContext.WithValue(rCtx, ctxSecurityPrincipal, usr)
- rCtx = stdContext.WithValue(rCtx, ctxSecurityScopes, route.Authenticator.AllScopes())
- return usr, request.WithContext(rCtx), nil
-}
-
// BindAndValidate binds and validates the request
// Returns the validation map and a shallow copy of the request when its context
// doesn't contain the validation, otherwise it returns the same request or an
@@ -523,91 +513,29 @@ func (c *Context) NotFound(rw http.ResponseWriter, r *http.Request) {
// Respond renders the response after doing some content negotiation.
func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []string, route *MatchedRoute, data any) {
c.debugLogf("responding to %s %s with produces: %v", r.Method, r.URL.Path, produces)
- offers := []string{}
- for _, mt := range produces {
- if mt != c.api.DefaultProduces() {
- offers = append(offers, mt)
- }
- }
- // the default producer is last so more specific producers take precedence
- offers = append(offers, c.api.DefaultProduces())
- c.debugLogf("offers: %v", offers)
+ offers := c.buildOffers(produces)
var format string
format, r = c.ResponseFormat(r, offers)
rw.Header().Set(runtime.HeaderContentType, format)
if resp, ok := data.(Responder); ok {
- producers := route.Producers
- // producers contains keys with normalized format, if a format has MIME type parameter such as `text/plain; charset=utf-8`
- // then you must provide `text/plain` to get the correct producer. HOWEVER, format here is not normalized.
- prod, ok := producers[normalizeOffer(format)]
- if !ok {
- prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
- pr, ok := prods[c.api.DefaultProduces()]
- if !ok {
- panic(fmt.Errorf("%d: %s", http.StatusInternalServerError, cantFindProducer(format)))
- }
- prod = pr
- }
- resp.WriteResponse(rw, prod)
+ c.respondWithResponder(rw, r, route, resp, format)
return
}
if err, ok := data.(error); ok {
- if format == "" {
- rw.Header().Set(runtime.HeaderContentType, runtime.JSONMime)
- }
-
- if realm := security.FailedBasicAuth(r); realm != "" {
- rw.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q", realm))
- }
-
- if route == nil || route.Operation == nil {
- c.api.ServeErrorFor("")(rw, r, err)
- return
- }
- c.api.ServeErrorFor(route.Operation.ID)(rw, r, err)
+ c.respondWithError(rw, r, produces, route, err, format)
return
}
if route == nil || route.Operation == nil {
- rw.WriteHeader(http.StatusOK)
- if r.Method == http.MethodHead {
- return
- }
- producers := c.api.ProducersFor(normalizeOffers(offers))
- prod, ok := producers[format]
- if !ok {
- panic(fmt.Errorf("%d: %s", http.StatusInternalServerError, cantFindProducer(format)))
- }
- if err := prod.Produce(rw, data); err != nil {
- panic(err) // let the recovery middleware deal with this
- }
+ c.respondWithoutCode(rw, r, data, format, offers)
return
}
if _, code, ok := route.Operation.SuccessResponse(); ok {
- rw.WriteHeader(code)
- if code == http.StatusNoContent || r.Method == http.MethodHead {
- return
- }
-
- producers := route.Producers
- prod, ok := producers[format]
- if !ok {
- if !ok {
- prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
- pr, ok := prods[c.api.DefaultProduces()]
- if !ok {
- panic(fmt.Errorf("%d: %s", http.StatusInternalServerError, cantFindProducer(format)))
- }
- prod = pr
- }
- }
- if err := prod.Produce(rw, data); err != nil {
- panic(err) // let the recovery middleware deal with this
- }
+ c.respondWithCode(rw, r, route, code, data, format)
return
}
@@ -618,57 +546,76 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
//
// This handler includes a swagger spec, router and the contract defined in the swagger spec.
//
-// A spec UI ([SwaggerUI]) is served at {API base path}/docs and the spec document at /swagger.json
-// (these can be modified with uiOptions).
+// A spec UI ([docui.SwaggerUI]) is served at {API base path}/docs and the spec document at /swagger.json
+// (these can be modified with combined [UIOption]).
+//
+// Deprecated: use [Context.APIHandlerWithUI] with [docui.SwaggerUI] middleware instead.
func (c *Context) APIHandlerSwaggerUI(builder Builder, opts ...UIOption) http.Handler {
- b := builder
- if b == nil {
- b = PassthroughBuilder
- }
-
- specPath, uiOpts, specOpts := c.uiOptionsForHandler(opts)
- var swaggerUIOpts SwaggerUIOpts
- fromCommonToAnyOptions(uiOpts, &swaggerUIOpts)
-
- return Spec(specPath, c.spec.Raw(), SwaggerUI(swaggerUIOpts, c.RoutesHandler(b)), specOpts...)
+ return c.APIHandlerWithUI(builder, docui.UseSwaggerUI, c.uiOptionsForHandler(opts)...)
}
// APIHandlerRapiDoc returns a handler to serve the API.
//
// This handler includes a swagger spec, router and the contract defined in the swagger spec.
//
-// A spec UI ([RapiDoc]) is served at {API base path}/docs and the spec document at /swagger.json
-// (these can be modified with uiOptions).
+// A spec UI ([docui.RapiDoc]) is served at {API base path}/docs and the spec document at /swagger.json
+// (these can be modified with combined [UIOption]).
+//
+// Deprecated: use [Context.APIHandlerWithUI] with [docui.UseRapiDoc] middleware instead.
func (c *Context) APIHandlerRapiDoc(builder Builder, opts ...UIOption) http.Handler {
- b := builder
- if b == nil {
- b = PassthroughBuilder
- }
-
- specPath, uiOpts, specOpts := c.uiOptionsForHandler(opts)
- var rapidocUIOpts RapiDocOpts
- fromCommonToAnyOptions(uiOpts, &rapidocUIOpts)
-
- return Spec(specPath, c.spec.Raw(), RapiDoc(rapidocUIOpts, c.RoutesHandler(b)), specOpts...)
+ return c.APIHandlerWithUI(builder, docui.UseRapiDoc, c.uiOptionsForHandler(opts)...)
}
// APIHandler returns a handler to serve the API.
//
// This handler includes a swagger spec, router and the contract defined in the swagger spec.
//
-// A spec UI ([Redoc]) is served at {API base path}/docs and the spec document at /swagger.json
-// (these can be modified with uiOptions).
+// A spec UI ([docui.Redoc]) is served at {API base path}/docs and the spec document at /swagger.json
+// (these can be modified with combined [UIOption]).
+//
+// Notice that you may use [Context.APIHandlerWithUI] to use an alternate UI-serving middleware.
func (c *Context) APIHandler(builder Builder, opts ...UIOption) http.Handler {
+ return c.APIHandlerWithUI(builder, docui.UseRedoc, c.uiOptionsForHandler(opts)...)
+}
+
+// APIHandlerWithUI returns a handler to serve the API with a swagger spec and a UI.
+//
+// This handler includes a swagger spec, router and the contract defined in the swagger spec.
+//
+// A spec UI is served at {API base path}/docs and the spec document at /swagger.json
+// (these can be modified with combined [UIOption]).
+//
+// Notice that any function that accepts the [docui.Option] set and returns a valid middleware may be injected here.
+//
+// [Context.APIHandlerWithUI] extends [Context.APIHandler], and supersedes [Context.APIHandlerRapiDoc] and [Context.APIHandlerSwaggerUI].
+func (c *Context) APIHandlerWithUI(builder Builder, uiMiddleware docui.UIMiddleware, opts ...docui.Option) http.Handler {
b := builder
if b == nil {
b = PassthroughBuilder
}
- specPath, uiOpts, specOpts := c.uiOptionsForHandler(opts)
- var redocOpts RedocOpts
- fromCommonToAnyOptions(uiOpts, &redocOpts)
+ // the UI titles defaults to the title in the spec
+ const extraOptions = 2
+ prepend := make([]docui.Option, 0, len(opts)+extraOptions)
+ var title string
- return Spec(specPath, c.spec.Raw(), Redoc(redocOpts, c.RoutesHandler(b)), specOpts...)
+ sp := c.spec.Spec()
+ if sp != nil && sp.Info != nil && sp.Info.Title != "" {
+ title = sp.Info.Title
+ }
+ if title != "" {
+ prepend = append(prepend, docui.WithUITitle(title))
+ }
+
+ prepend = append(prepend, docui.WithUIBasePath(c.BasePath()))
+ prepend = append(prepend, opts...)
+
+ // aligns spec serve path with UI setting to fetch spec document.
+ return docui.UseSpec(c.spec.Raw(), docui.WithSpecPathFromOptions(prepend...))(
+ uiMiddleware(prepend...)(
+ c.RoutesHandler(b),
+ ),
+ )
}
// RoutesHandler returns a handler to serve the API, just the routes and the contract defined in the swagger spec.
@@ -680,37 +627,192 @@ func (c *Context) RoutesHandler(builder Builder) http.Handler {
return NewRouter(c, b(NewOperationExecutor(c)))
}
-func (c Context) uiOptionsForHandler(opts []UIOption) (string, uiOptions, []SpecOption) {
- var title string
- sp := c.spec.Spec()
- if sp != nil && sp.Info != nil && sp.Info.Title != "" {
- title = sp.Info.Title
+// authorizeImpl is the real authentication+authorization body shared
+// between the production and dev-only variants of [Context.Authorize].
+// See context_skipauth_disabled.go (default build) and
+// context_skipauth_enabled.go (the `openapi_unsafe_skipauth` build tag).
+//
+// The doc on the exported Authorize describes the user-facing
+// contract; this function MUST NOT change semantics for the
+// production path.
+func (c *Context) authorizeImpl(request *http.Request, route *MatchedRoute) (any, *http.Request, error) {
+ if route == nil || !route.HasAuth() {
+ return nil, nil, nil
}
- // default options (may be overridden)
- const baseOptions = 2
- optsForContext := make([]UIOption, 0, len(opts)+baseOptions)
- optsForContext = append(optsForContext,
- WithUIBasePath(c.BasePath()),
- WithUITitle(title),
- )
- optsForContext = append(optsForContext, opts...)
- uiOpts := uiOptionsWithDefaults(optsForContext)
+ var rCtx = request.Context()
+ if v := rCtx.Value(ctxSecurityPrincipal); v != nil {
+ return v, request, nil
+ }
+
+ applies, usr, err := route.Authenticators.Authenticate(request, route)
+ if !applies || err != nil || !route.Authenticators.AllowsAnonymous() && typeutils.IsZero(usr) {
+ if err != nil {
+ return nil, nil, err
+ }
+ return nil, nil, errors.Unauthenticated("invalid credentials")
+ }
+ if route.Authorizer != nil {
+ if err := route.Authorizer.Authorize(request, usr); err != nil {
+ var apiError errors.Error
+ if stderrors.As(err, &apiError) {
+ return nil, nil, err
+ }
+
+ return nil, nil, errors.New(http.StatusForbidden, "%v", err)
+ }
+ }
+
+ rCtx = request.Context()
+
+ rCtx = stdContext.WithValue(rCtx, ctxSecurityPrincipal, usr)
+ rCtx = stdContext.WithValue(rCtx, ctxSecurityScopes, route.Authenticator.AllScopes())
+ return usr, request.WithContext(rCtx), nil
+}
+
+func (c *Context) bindRequestBody(request *http.Request, route *MatchedRoute) (string, runtime.Consumer, error) {
+ ct, _, err := runtime.ContentType(request.Header)
+ if err != nil {
+ return "", nil, err
+ }
+
+ c.debugLogf("validating content type for %q against [%s]", ct, strings.Join(route.Consumes, ", "))
+ if err := validateContentType(route.Consumes, ct); err != nil {
+ return "", nil, err
+ }
+
+ cons, ok := mediatype.Lookup(route.Consumers, ct, c.matchOpts()...)
+ if !ok {
+ return "", nil, errors.New(http.StatusInternalServerError, "no consumer registered for %s", ct)
+ }
+
+ return ct, cons, nil
+}
+
+func (c *Context) respondWithResponder(rw http.ResponseWriter, r *http.Request, route *MatchedRoute, resp Responder, format string) {
+ _ = r
+ producers := route.Producers
+
+ // producers contains keys with normalized format, if a format has MIME type parameter such as `text/plain; charset=utf-8`
+ // then you must provide `text/plain` to get the correct producer. HOWEVER, format here is not normalized.
+ prod, ok := producers[normalizeOffer(format)]
+ if !ok {
+ prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
+ pr, ok := prods[c.api.DefaultProduces()]
+ if !ok {
+ panic(fmt.Errorf("%d: %s", http.StatusInternalServerError, cantFindProducer(format)))
+ }
+ prod = pr
+ }
+
+ resp.WriteResponse(rw, prod)
+}
+
+func (c *Context) respondWithError(rw http.ResponseWriter, r *http.Request, produces []string, route *MatchedRoute, err error, format string) {
+ _ = produces
+
+ if format == "" {
+ rw.Header().Set(runtime.HeaderContentType, runtime.JSONMime)
+ }
+
+ if realm := security.FailedBasicAuth(r); realm != "" {
+ rw.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q", realm))
+ }
+
+ if route == nil || route.Operation == nil {
+ c.api.ServeErrorFor("")(rw, r, err)
+ return
+ }
+
+ c.api.ServeErrorFor(route.Operation.ID)(rw, r, err)
+}
+
+func (c *Context) respondWithoutCode(rw http.ResponseWriter, r *http.Request, data any, format string, offers []string) {
+ rw.WriteHeader(http.StatusOK)
+ if r.Method == http.MethodHead {
+ return
+ }
+
+ producers := c.api.ProducersFor(normalizeOffers(offers))
+ prod, ok := producers[format]
+ if !ok {
+ panic(fmt.Errorf("%d: %s", http.StatusInternalServerError, cantFindProducer(format)))
+ }
+
+ if err := prod.Produce(rw, data); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+}
+
+func (c *Context) buildOffers(produces []string) []string {
+ offers := make([]string, 0, len(produces)+1)
+
+ for _, mt := range produces {
+ if mt != c.api.DefaultProduces() {
+ offers = append(offers, mt)
+ }
+ }
+
+ // the default producer is last so more specific producers take precedence
+ offers = append(offers, c.api.DefaultProduces())
+ c.debugLogf("offers: %v", offers)
+
+ return offers
+}
+
+func (c *Context) respondWithCode(rw http.ResponseWriter, r *http.Request, route *MatchedRoute, code int, data any, format string) {
+ rw.WriteHeader(code)
+ if code == http.StatusNoContent || r.Method == http.MethodHead {
+ return
+ }
+
+ producers := route.Producers
+ prod, ok := producers[format]
+ if !ok {
+ if !ok {
+ prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
+ pr, ok := prods[c.api.DefaultProduces()]
+ if !ok {
+ panic(fmt.Errorf("%d: %s", http.StatusInternalServerError, cantFindProducer(format)))
+ }
+ prod = pr
+ }
+ }
- // If spec URL is provided, there is a non-default path to serve the spec.
- // This makes sure that the UI middleware is aligned with the Spec middleware.
- u, _ := url.Parse(uiOpts.SpecURL)
- var specPath string
- if u != nil {
- specPath = u.Path
+ if err := prod.Produce(rw, data); err != nil {
+ panic(err) // let the recovery middleware deal with this
}
+}
+
+// uiOptionsForHandler bridges the deprecated [UIOption] set to the new [docui.Option] set.
+func (c Context) uiOptionsForHandler(opts []UIOption) []docui.Option {
+ uiOpts := uiOptionsWithDefaults(opts)
- pth, doc := path.Split(specPath)
- if pth == "." {
- pth = ""
+ return uiOpts.toFuncOptions()
+}
+
+func (c *Context) negotiateOpts() []negotiate.Option {
+ var opts []negotiate.Option
+ if c.ignoreParameters {
+ opts = append(opts, negotiate.WithIgnoreParameters(true))
+ }
+ if c.matchSuffix {
+ opts = append(opts, negotiate.WithMatchSuffix(true))
+ }
+
+ return opts
+}
+
+// matchOpts builds the mediatype.MatchOption slice that the
+// codec-lookup and Content-Type validation paths apply server-wide.
+// Mirrors negotiateOpts but at the mediatype level (without going
+// through the negotiate.Option wrapper).
+func (c *Context) matchOpts() []mediatype.MatchOption {
+ if !c.matchSuffix {
+ return nil
}
- return pth, uiOpts, []SpecOption{WithSpecDocument(doc)}
+ return []mediatype.MatchOption{mediatype.AllowSuffix()}
}
func cantFindProducer(format string) string {
diff --git a/vendor/github.com/go-openapi/runtime/middleware/context_skipauth_disabled.go b/vendor/github.com/go-openapi/runtime/middleware/context_skipauth_disabled.go
new file mode 100644
index 00000000000..c8cd01a4343
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/middleware/context_skipauth_disabled.go
@@ -0,0 +1,24 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+//go:build !openapi_unsafe_skipauth
+
+package middleware
+
+import "net/http"
+
+// Authorize authorizes the request.
+//
+// Returns the principal object and a shallow copy of the request when its
+// context doesn't contain the principal, otherwise the same request or an error
+// (the last) if one of the authenticators returns one or an Unauthenticated error.
+//
+// This is the production variant — compiled when the build tag
+// `openapi_unsafe_skipauth` is NOT set. There is no skip-auth check
+// in this codepath; the field, setter, and storage for the bypass
+// flag are entirely absent from the binary. See the alternate
+// implementation in context_skipauth_enabled.go for the dev-only
+// bypass mechanism.
+func (c *Context) Authorize(request *http.Request, route *MatchedRoute) (any, *http.Request, error) {
+ return c.authorizeImpl(request, route)
+}
diff --git a/vendor/github.com/go-openapi/runtime/middleware/context_skipauth_enabled.go b/vendor/github.com/go-openapi/runtime/middleware/context_skipauth_enabled.go
new file mode 100644
index 00000000000..2ac87068187
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/middleware/context_skipauth_enabled.go
@@ -0,0 +1,61 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+//go:build openapi_unsafe_skipauth
+
+package middleware
+
+import (
+ "log"
+ "net/http"
+ "sync/atomic"
+)
+
+// skipAuthEnabled holds the process-wide skip-auth flag. It only
+// exists in binaries built with the `openapi_unsafe_skipauth` tag —
+// production binaries (built without the tag) have no field, no
+// setter, no storage, and no skip-checking branch in [Context.Authorize].
+// Reflection, unsafe-pointer arithmetic, or a debugger cannot flip
+// what is not in the binary.
+var skipAuthEnabled atomic.Bool
+
+// SetSkipAuth toggles a PROCESS-WIDE bypass of authentication AND
+// authorization for every operation served by every Context in the
+// running program.
+//
+// DANGER: this disables ALL authentication and ALL authorization.
+// Every request to every secured endpoint runs as if it had been
+// authorized with a nil principal. Use ONLY on developer
+// workstations during early prototyping (e.g. while
+// authentication is not yet wired up).
+//
+// This function exists only when the build tag
+// `openapi_unsafe_skipauth` is set:
+//
+// go build -tags openapi_unsafe_skipauth ./...
+//
+// Production CI MUST NOT pass this tag. Calls compile to a symbol
+// that does not exist in production binaries.
+//
+// Calling with true emits a one-line WARNING via the stdlib `log`
+// package (stderr by default) so the bypass is visible at startup.
+// Calling with false silently disables it.
+func SetSkipAuth(skip bool) {
+ skipAuthEnabled.Store(skip)
+ if skip {
+ log.Println("WARNING: go-openapi/runtime: SetSkipAuth(true) — authentication and authorization are bypassed for ALL operations. This MUST NOT run in production.")
+ }
+}
+
+// Authorize is the dev-build variant of the production
+// [Context.Authorize] (see context_skipauth_disabled.go for the
+// production path). When [SetSkipAuth] has enabled the bypass, this
+// returns a nil principal with the original request and no error —
+// handlers downstream receive a nil-value principal. Otherwise it
+// delegates to the standard authentication+authorization body.
+func (c *Context) Authorize(request *http.Request, route *MatchedRoute) (any, *http.Request, error) {
+ if skipAuthEnabled.Load() {
+ return nil, request, nil
+ }
+ return c.authorizeImpl(request, route)
+}
diff --git a/vendor/github.com/go-openapi/runtime/middleware/denco/router.go b/vendor/github.com/go-openapi/runtime/middleware/denco/router.go
index f89d761cf2a..e380a138d50 100644
--- a/vendor/github.com/go-openapi/runtime/middleware/denco/router.go
+++ b/vendor/github.com/go-openapi/runtime/middleware/denco/router.go
@@ -9,6 +9,7 @@ package denco
import (
"errors"
"fmt"
+ "slices"
"sort"
"strings"
)
@@ -29,8 +30,8 @@ const (
// PathParamCharacter indicates a RESTCONF path param.
PathParamCharacter = '='
- // MaxSize is max size of records and internal slice.
- MaxSize = (1 << 22) - 1 //nolint:mnd
+ // MaxSize is the maximum size of records and internal slice (encoded over 22 bits).
+ MaxSize = (1 << baseBits) - 1
)
// Router represents a URL router.
@@ -53,9 +54,12 @@ func New() *Router {
}
}
-// Lookup returns data and path parameters that associated with path.
+// Lookup returns data and path parameters which are associated to the path.
+//
// params is a slice of the [Param] that arranged in the order in which parameters appeared.
-// e.g. when built routing path is "/path/to/:id/:name" and given path is "/path/to/1/alice". params order is [{"id": "1"}, {"name": "alice"}], not [{"name": "alice"}, {"id": "1"}].
+//
+// e.g. when built routing path is "/path/to/:id/:name" and given path is "/path/to/1/alice",
+// params order is [{"id": "1"}, {"name": "alice"}], not [{"name": "alice"}, {"id": "1"}].
func (rt *Router) Lookup(path string) (data any, params Params, found bool) {
if data, found = rt.static[path]; found {
return data, nil, true
@@ -144,6 +148,7 @@ func newDoubleArray() *doubleArray {
type baseCheck uint32
const (
+ baseBits = 22
flagsBits = 10
checkBits = 8
)
@@ -157,7 +162,7 @@ func (bc *baseCheck) SetBase(base int) {
}
func (bc baseCheck) Check() byte {
- return byte(bc) //nolint:gosec // integer conversion is ok
+ return byte(bc) //nolint:gosec // integer conversion is ok: we pick the last 8 bits
}
func (bc *baseCheck) SetCheck(check byte) {
@@ -213,8 +218,8 @@ func (da *doubleArray) lookup(path string, params []Param, idx int) (*node, []Pa
}
BACKTRACKING:
- for j := len(indices) - 1; j >= 0; j-- {
- i, idx := int(indices[j]>>indexOffset), int(indices[j]&indexMask)
+ for _, j := range slices.Backward(indices) {
+ i, idx := int(j>>indexOffset), int(j&indexMask)
if da.bc[idx].IsSingleParam() {
nextIdx := nextIndex(da.bc[idx].Base(), ParamCharacter)
if nextIdx >= len(da.bc) {
diff --git a/vendor/github.com/go-openapi/runtime/middleware/denco/server.go b/vendor/github.com/go-openapi/runtime/middleware/denco/server.go
index e6c0976d8b2..3bbbc679d92 100644
--- a/vendor/github.com/go-openapi/runtime/middleware/denco/server.go
+++ b/vendor/github.com/go-openapi/runtime/middleware/denco/server.go
@@ -9,7 +9,7 @@ import (
"net/http"
)
-// Mux represents a multiplexer for HTTP request.
+// Mux represents a multiplexer for HTTP requests.
type Mux struct{}
// NewMux returns a new [Mux].
@@ -17,27 +17,27 @@ func NewMux() *Mux {
return &Mux{}
}
-// GET is shorthand of [Mux].Handler("GET", path, handler).
+// GET is shorthand for [Mux.Handler] ("GET", path, handler).
func (m *Mux) GET(path string, handler HandlerFunc) Handler {
return m.Handler("GET", path, handler)
}
-// POST is shorthand of [Mux].Handler("POST", path, handler).
+// POST is shorthand for [Mux.Handler] ("POST", path, handler).
func (m *Mux) POST(path string, handler HandlerFunc) Handler {
return m.Handler("POST", path, handler)
}
-// PUT is shorthand of [Mux].Handler("PUT", path, handler).
+// PUT is shorthand for [Mux.Handler] ("PUT", path, handler).
func (m *Mux) PUT(path string, handler HandlerFunc) Handler {
return m.Handler("PUT", path, handler)
}
-// HEAD is shorthand of [Mux].Handler("HEAD", path, handler).
+// HEAD is shorthand for [Mux.Handler]("HEAD", path, handler).
func (m *Mux) HEAD(path string, handler HandlerFunc) Handler {
return m.Handler("HEAD", path, handler)
}
-// Handler returns a handler for HTTP method.
+// Handler returns a [Handler] for a HTTP method.
func (m *Mux) Handler(method, path string, handler HandlerFunc) Handler {
return Handler{
Method: method,
@@ -63,7 +63,7 @@ func (m *Mux) Build(handlers []Handler) (http.Handler, error) {
return mux, nil
}
-// Handler represents a handler of HTTP request.
+// Handler represents a handler of HTTP requests.
type Handler struct {
// Method is an HTTP method.
Method string
@@ -75,7 +75,7 @@ type Handler struct {
Func HandlerFunc
}
-// HandlerFunc is aliased to type of handler function.
+// HandlerFunc is an alias to the handler function, similar to [http.HandlerFunc].
type HandlerFunc func(w http.ResponseWriter, r *http.Request, params Params)
type serveMux struct {
@@ -88,7 +88,7 @@ func newServeMux() *serveMux {
}
}
-// ServeHTTP implements http.Handler interface.
+// ServeHTTP implements the [http.Handler] interface.
func (mux *serveMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
handler, params := mux.handler(r.Method, r.URL.Path)
handler(w, r, params)
@@ -97,15 +97,17 @@ func (mux *serveMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func (mux *serveMux) handler(method, path string) (HandlerFunc, []Param) {
if router, found := mux.routers[method]; found {
if handler, params, found := router.Lookup(path); found {
- return handler.(HandlerFunc), params
+ return handler.(HandlerFunc), params //nolint:forcetypeassert // type is guaranteed when the path is found
}
}
return NotFound, nil
}
// NotFound replies to the request with an HTTP 404 not found error.
-// NotFound is called when unknown HTTP method or a handler not found.
-// If you want to use the your own NotFound handler, please overwrite this variable.
+//
+// NotFound is called when unknown HTTP methods are being user or a handler not found.
+//
+// If you want to use your own NotFound handler, please overwrite this variable.
var NotFound = func(w http.ResponseWriter, r *http.Request, _ Params) {
http.NotFound(w, r)
}
diff --git a/vendor/github.com/go-openapi/runtime/middleware/header/header.go b/vendor/github.com/go-openapi/runtime/middleware/header/header.go
deleted file mode 100644
index 6ce870d8936..00000000000
--- a/vendor/github.com/go-openapi/runtime/middleware/header/header.go
+++ /dev/null
@@ -1,339 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
-// SPDX-License-Identifier: Apache-2.0
-
-// Copyright 2013 The Go Authors. All rights reserved.
-//
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file or at
-// https://developers.google.com/open-source/licenses/bsd.
-
-// this file was taken from the github.com/golang/gddo repository
-
-// Package header provides functions for parsing HTTP headers.
-package header
-
-import (
- "maps"
- "net/http"
- "strings"
- "time"
-)
-
-// Octet types from RFC 2616.
-var octetTypes [256]octetType
-
-type octetType byte
-
-const (
- isToken octetType = 1 << iota
- isSpace
-)
-
-const (
- asciiMaxControlChar = 31
- asciiMaxChar = 127
-)
-
-func init() {
- // OCTET =
- // CHAR =
- // CTL =
- // CR =
- // LF =
- // SP =
- // HT =
- // <"> =
- // CRLF = CR LF
- // LWS = [CRLF] 1*( SP | HT )
- // TEXT =
- // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
- // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
- // token = 1*
- // qdtext = >
-
- for c := range 256 {
- var t octetType
- isCtl := c <= asciiMaxControlChar || c == asciiMaxChar
- isChar := 0 <= c && c <= asciiMaxChar
- isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
- if strings.ContainsRune(" \t\r\n", rune(c)) {
- t |= isSpace
- }
- if isChar && !isCtl && !isSeparator {
- t |= isToken
- }
- octetTypes[c] = t
- }
-}
-
-// Copy returns a shallow copy of the header.
-func Copy(header http.Header) http.Header {
- h := make(http.Header)
- maps.Copy(h, header)
- return h
-}
-
-var timeLayouts = []string{"Mon, 02 Jan 2006 15:04:05 GMT", time.RFC850, time.ANSIC}
-
-// ParseTime parses the header as time. The zero value is returned if the
-// header is not present or there is an error parsing the
-// header.
-func ParseTime(header http.Header, key string) time.Time {
- if s := header.Get(key); s != "" {
- for _, layout := range timeLayouts {
- if t, err := time.Parse(layout, s); err == nil {
- return t.UTC()
- }
- }
- }
- return time.Time{}
-}
-
-// ParseList parses a comma separated list of values. Commas are ignored in
-// quoted strings. Quoted values are not unescaped or unquoted. Whitespace is
-// trimmed.
-func ParseList(header http.Header, key string) []string {
- var result []string
- for _, s := range header[http.CanonicalHeaderKey(key)] {
- begin := 0
- end := 0
- escape := false
- quote := false
- for i := range len(s) {
- b := s[i]
- switch {
- case escape:
- escape = false
- end = i + 1
- case quote:
- switch b {
- case '\\':
- escape = true
- case '"':
- quote = false
- }
- end = i + 1
- case b == '"':
- quote = true
- end = i + 1
- case octetTypes[b]&isSpace != 0:
- if begin == end {
- begin = i + 1
- end = begin
- }
- case b == ',':
- if begin < end {
- result = append(result, s[begin:end])
- }
- begin = i + 1
- end = begin
- default:
- end = i + 1
- }
- }
- if begin < end {
- result = append(result, s[begin:end])
- }
- }
- return result
-}
-
-// ParseValueAndParams parses a comma separated list of values with optional
-// semicolon separated name-value pairs. Content-Type and Content-Disposition
-// headers are in this format.
-func ParseValueAndParams(header http.Header, key string) (string, map[string]string) {
- return parseValueAndParams(header.Get(key))
-}
-
-func parseValueAndParams(s string) (value string, params map[string]string) {
- params = make(map[string]string)
- value, s = expectTokenSlash(s)
- if value == "" {
- return
- }
- value = strings.ToLower(value)
- s = skipSpace(s)
- for strings.HasPrefix(s, ";") {
- var pkey string
- pkey, s = expectToken(skipSpace(s[1:]))
- if pkey == "" {
- return
- }
- if !strings.HasPrefix(s, "=") {
- return
- }
- var pvalue string
- pvalue, s = expectTokenOrQuoted(s[1:])
- if pvalue == "" {
- return
- }
- pkey = strings.ToLower(pkey)
- params[pkey] = pvalue
- s = skipSpace(s)
- }
- return
-}
-
-// AcceptSpec ...
-type AcceptSpec struct {
- Value string
- Q float64
-}
-
-// ParseAccept2 ...
-func ParseAccept2(header http.Header, key string) (specs []AcceptSpec) {
- for _, en := range ParseList(header, key) {
- v, p := parseValueAndParams(en)
- var spec AcceptSpec
- spec.Value = v
- spec.Q = 1.0
- if p != nil {
- if q, ok := p["q"]; ok {
- spec.Q, _ = expectQuality(q)
- }
- }
- if spec.Q < 0.0 {
- continue
- }
- specs = append(specs, spec)
- }
-
- return
-}
-
-// ParseAccept parses Accept* headers.
-func ParseAccept(header http.Header, key string) []AcceptSpec {
- var specs []AcceptSpec
-loop:
- for _, s := range header[key] {
- for {
- var spec AcceptSpec
- spec.Value, s = expectTokenSlash(s)
- if spec.Value == "" {
- continue loop
- }
- spec.Q = 1.0
- s = skipSpace(s)
- if strings.HasPrefix(s, ";") {
- s = skipSpace(s[1:])
- for !strings.HasPrefix(s, "q=") && s != "" && !strings.HasPrefix(s, ",") {
- s = skipSpace(s[1:])
- }
- if strings.HasPrefix(s, "q=") {
- spec.Q, s = expectQuality(s[2:])
- if spec.Q < 0.0 {
- continue loop
- }
- }
- }
-
- specs = append(specs, spec)
- s = skipSpace(s)
- if !strings.HasPrefix(s, ",") {
- continue loop
- }
- s = skipSpace(s[1:])
- }
- }
-
- return specs
-}
-
-func skipSpace(s string) (rest string) {
- i := 0
- for ; i < len(s); i++ {
- if octetTypes[s[i]]&isSpace == 0 {
- break
- }
- }
- return s[i:]
-}
-
-func expectToken(s string) (token, rest string) {
- i := 0
- for ; i < len(s); i++ {
- if octetTypes[s[i]]&isToken == 0 {
- break
- }
- }
- return s[:i], s[i:]
-}
-
-func expectTokenSlash(s string) (token, rest string) {
- i := 0
- for ; i < len(s); i++ {
- b := s[i]
- if (octetTypes[b]&isToken == 0) && b != '/' {
- break
- }
- }
- return s[:i], s[i:]
-}
-
-func expectQuality(s string) (q float64, rest string) {
- switch {
- case len(s) == 0:
- return -1, ""
- case s[0] == '0':
- // q is already 0
- s = s[1:]
- case s[0] == '1':
- s = s[1:]
- q = 1
- case s[0] == '.':
- // q is already 0
- default:
- return -1, ""
- }
- if !strings.HasPrefix(s, ".") {
- return q, s
- }
- s = s[1:]
- i := 0
- n := 0
- d := 1
- for ; i < len(s); i++ {
- b := s[i]
- if b < '0' || b > '9' {
- break
- }
- n = n*10 + int(b) - '0'
- d *= 10
- }
- return q + float64(n)/float64(d), s[i:]
-}
-
-func expectTokenOrQuoted(s string) (value string, rest string) {
- if !strings.HasPrefix(s, "\"") {
- return expectToken(s)
- }
- s = s[1:]
- for i := 0; i < len(s); i++ {
- switch s[i] {
- case '"':
- return s[:i], s[i+1:]
- case '\\':
- p := make([]byte, len(s)-1)
- j := copy(p, s[:i])
- escape := true
- for i++; i < len(s); i++ {
- b := s[i]
- switch {
- case escape:
- escape = false
- p[j] = b
- j++
- case b == '\\':
- escape = true
- case b == '"':
- return string(p[:j]), s[i+1:]
- default:
- p[j] = b
- j++
- }
- }
- return "", ""
- }
- }
- return "", ""
-}
diff --git a/vendor/github.com/go-openapi/runtime/middleware/negotiate.go b/vendor/github.com/go-openapi/runtime/middleware/negotiate.go
deleted file mode 100644
index cb0a85283c1..00000000000
--- a/vendor/github.com/go-openapi/runtime/middleware/negotiate.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
-// SPDX-License-Identifier: Apache-2.0
-
-// Copyright 2013 The Go Authors. All rights reserved.
-//
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file or at
-// https://developers.google.com/open-source/licenses/bsd.
-
-// this file was taken from the github.com/golang/gddo repository
-
-package middleware
-
-import (
- "net/http"
- "strings"
-
- "github.com/go-openapi/runtime/middleware/header"
-)
-
-// NegotiateContentEncoding returns the best offered content encoding for the
-// request's Accept-Encoding header. If two offers match with equal weight and
-// then the offer earlier in the list is preferred. If no offers are
-// acceptable, then "" is returned.
-func NegotiateContentEncoding(r *http.Request, offers []string) string {
- bestOffer := "identity"
- bestQ := -1.0
- specs := header.ParseAccept(r.Header, "Accept-Encoding")
- for _, offer := range offers {
- for _, spec := range specs {
- if spec.Q > bestQ &&
- (spec.Value == "*" || spec.Value == offer) {
- bestQ = spec.Q
- bestOffer = offer
- }
- }
- }
- if bestQ == 0 {
- bestOffer = ""
- }
- return bestOffer
-}
-
-// NegotiateContentType returns the best offered content type for the request's
-// Accept header. If two offers match with equal weight, then the more specific
-// offer is preferred. For example, text/* trumps */*. If two offers match
-// with equal weight and specificity, then the offer earlier in the list is
-// preferred. If no offers match, then defaultOffer is returned.
-func NegotiateContentType(r *http.Request, offers []string, defaultOffer string) string {
- bestOffer := defaultOffer
- bestQ := -1.0
- bestWild := 3
- specs := header.ParseAccept(r.Header, "Accept")
- for _, rawOffer := range offers {
- offer := normalizeOffer(rawOffer)
- // No Accept header: just return the first offer.
- if len(specs) == 0 {
- return rawOffer
- }
- for _, spec := range specs {
- switch {
- case spec.Q == 0.0:
- // ignore
- case spec.Q < bestQ:
- // better match found
- case spec.Value == "*/*":
- if spec.Q > bestQ || bestWild > 2 {
- bestQ = spec.Q
- bestWild = 2
- bestOffer = rawOffer
- }
- case strings.HasSuffix(spec.Value, "/*"):
- if strings.HasPrefix(offer, spec.Value[:len(spec.Value)-1]) &&
- (spec.Q > bestQ || bestWild > 1) {
- bestQ = spec.Q
- bestWild = 1
- bestOffer = rawOffer
- }
- default:
- if spec.Value == offer &&
- (spec.Q > bestQ || bestWild > 0) {
- bestQ = spec.Q
- bestWild = 0
- bestOffer = rawOffer
- }
- }
- }
- }
- return bestOffer
-}
-
-func normalizeOffers(orig []string) (norm []string) {
- for _, o := range orig {
- norm = append(norm, normalizeOffer(o))
- }
- return
-}
-
-func normalizeOffer(orig string) string {
- const maxParts = 2
- return strings.SplitN(orig, ";", maxParts)[0]
-}
diff --git a/vendor/github.com/go-openapi/runtime/middleware/parameter.go b/vendor/github.com/go-openapi/runtime/middleware/parameter.go
index a9d2a36460b..4ae8e3d62d6 100644
--- a/vendor/github.com/go-openapi/runtime/middleware/parameter.go
+++ b/vendor/github.com/go-openapi/runtime/middleware/parameter.go
@@ -6,7 +6,7 @@ package middleware
import (
"encoding"
"encoding/base64"
- "fmt"
+ stderrors "errors"
"io"
"net/http"
"reflect"
@@ -56,126 +56,153 @@ func (p *untypedParamBinder) Type() reflect.Type {
}
func (p *untypedParamBinder) Bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, target reflect.Value) error {
- // fmt.Println("binding", p.name, "as", p.Type())
switch p.parameter.In {
case "query":
- data, custom, hasKey, err := p.readValue(runtime.Values(request.URL.Query()), target)
- if err != nil {
- return err
- }
- if custom {
- return nil
- }
-
- return p.bindValue(data, hasKey, target)
+ return p.bindQuery(request, routeParams, consumer, target)
case "header":
- data, custom, hasKey, err := p.readValue(runtime.Values(request.Header), target)
- if err != nil {
- return err
- }
- if custom {
- return nil
- }
- return p.bindValue(data, hasKey, target)
+ return p.bindHeader(request, routeParams, consumer, target)
case "path":
- data, custom, hasKey, err := p.readValue(routeParams, target)
- if err != nil {
- return err
- }
- if custom {
- return nil
- }
- return p.bindValue(data, hasKey, target)
+ return p.bindPath(request, routeParams, consumer, target)
case "formData":
- var err error
- var mt string
+ return p.bindFormData(request, routeParams, consumer, target)
- mt, _, e := runtime.ContentType(request.Header)
- if e != nil {
- // because of the interface conversion go thinks the error is not nil
- // so we first check for nil and then set the err var if it's not nil
- err = e
- }
+ case "body":
+ return p.bindBody(request, routeParams, consumer, target)
+ default:
+ return errors.New(http.StatusInternalServerError, "invalid parameter location: %q", p.parameter.In)
+ }
+}
- if err != nil {
- return errors.InvalidContentType("", []string{"multipart/form-data", "application/x-www-form-urlencoded"})
- }
+func (p *untypedParamBinder) bindQuery(request *http.Request, _ RouteParams, _ runtime.Consumer, target reflect.Value) error {
+ data, custom, hasKey, err := p.readValue(runtime.Values(request.URL.Query()), target)
+ if err != nil {
+ return err
+ }
+ if custom {
+ return nil
+ }
- if mt != "multipart/form-data" && mt != "application/x-www-form-urlencoded" {
- return errors.InvalidContentType(mt, []string{"multipart/form-data", "application/x-www-form-urlencoded"})
- }
+ return p.bindValue(data, hasKey, target)
+}
- if mt == "multipart/form-data" {
- if err = request.ParseMultipartForm(defaultMaxMemory); err != nil {
- return errors.NewParseError(p.Name, p.parameter.In, "", err)
- }
- }
+func (p *untypedParamBinder) bindHeader(request *http.Request, _ RouteParams, _ runtime.Consumer, target reflect.Value) error {
+ data, custom, hasKey, err := p.readValue(runtime.Values(request.Header), target)
+ if err != nil {
+ return err
+ }
+ if custom {
+ return nil
+ }
+ return p.bindValue(data, hasKey, target)
+}
- if err = request.ParseForm(); err != nil {
- return errors.NewParseError(p.Name, p.parameter.In, "", err)
- }
+func (p *untypedParamBinder) bindPath(_ *http.Request, routeParams RouteParams, _ runtime.Consumer, target reflect.Value) error {
+ data, custom, hasKey, err := p.readValue(routeParams, target)
+ if err != nil {
+ return err
+ }
+ if custom {
+ return nil
+ }
+ return p.bindValue(data, hasKey, target)
+}
- if p.parameter.Type == "file" {
- file, header, ffErr := request.FormFile(p.parameter.Name)
- if ffErr != nil {
- if p.parameter.Required {
- return errors.NewParseError(p.Name, p.parameter.In, "", ffErr)
- }
+func (p *untypedParamBinder) bindFormData(request *http.Request, _ RouteParams, _ runtime.Consumer, target reflect.Value) error {
+ mt, _, ctErr := runtime.ContentType(request.Header)
+ if ctErr != nil {
+ return errors.InvalidContentType("", []string{runtime.MultipartFormMime, runtime.URLencodedFormMime})
+ }
- return nil
- }
+ if mt != runtime.MultipartFormMime && mt != runtime.URLencodedFormMime {
+ return errors.InvalidContentType(mt, []string{runtime.MultipartFormMime, runtime.URLencodedFormMime})
+ }
- target.Set(reflect.ValueOf(runtime.File{Data: file, Header: header}))
- return nil
- }
+ // Parse via the shared helper. The helper routes on Content-Type
+ // (multipart/form-data → ParseMultipartForm; all non-multipart types,
+ // including application/x-www-form-urlencoded, → ParseForm)
+ // and applies the default 32 MiB body cap via http.MaxBytesReader.
+ // Idempotent across the per-parameter loop: stdlib short-circuits
+ // when r.MultipartForm / r.PostForm are already populated.
+ if _, perr := runtime.BindForm(request, runtime.BindFormMaxParseMemory(defaultMaxMemory)); perr != nil {
+ return perr
+ }
- if request.MultipartForm != nil {
- data, custom, hasKey, rvErr := p.readValue(runtime.Values(request.MultipartForm.Value), target)
- if rvErr != nil {
- return rvErr
- }
- if custom {
+ if p.parameter.Type == "file" {
+ // runtime.FormFile handles both multipart/form-data and
+ // application/x-www-form-urlencoded (OpenAPI 2.0 permits
+ // either consumes for `type: file`), and surfaces a
+ // missing field as http.ErrMissingFile under both.
+ file, header, ffErr := runtime.FormFile(request, p.parameter.Name)
+ if ffErr != nil {
+ if stderrors.Is(ffErr, http.ErrMissingFile) {
+ if p.parameter.Required {
+ return errors.NewParseError(p.Name, p.parameter.In, "", http.ErrMissingFile)
+ }
return nil
}
- return p.bindValue(data, hasKey, target)
+ return errors.NewParseError(p.Name, p.parameter.In, "", ffErr)
}
- data, custom, hasKey, err := p.readValue(runtime.Values(request.PostForm), target)
- if err != nil {
+
+ // Mirror the FileHeader.Filename length cap that BindForm
+ // applies to typed (codegen) paths through BindFormFile, so
+ // untyped formData bindings get the same protection.
+ if err := runtime.ValidateFilenameLength(p.Name, p.parameter.In, header.Filename,
+ runtime.DefaultMaxUploadFilenameLength); err != nil {
return err
}
+
+ target.Set(reflect.ValueOf(runtime.File{Data: file, Header: header}))
+ return nil
+ }
+
+ if request.MultipartForm != nil {
+ data, custom, hasKey, rvErr := p.readValue(runtime.Values(request.MultipartForm.Value), target)
+ if rvErr != nil {
+ return rvErr
+ }
if custom {
return nil
}
return p.bindValue(data, hasKey, target)
+ }
+ data, custom, hasKey, err := p.readValue(runtime.Values(request.PostForm), target)
+ if err != nil {
+ return err
+ }
+ if custom {
+ return nil
+ }
+ return p.bindValue(data, hasKey, target)
+}
- case "body":
- newValue := reflect.New(target.Type())
- if !runtime.HasBody(request) {
- if p.parameter.Default != nil {
- target.Set(reflect.ValueOf(p.parameter.Default))
- }
+func (p *untypedParamBinder) bindBody(request *http.Request, _ RouteParams, consumer runtime.Consumer, target reflect.Value) error {
+ newValue := reflect.New(target.Type())
+ if !runtime.HasBody(request) {
+ if p.parameter.Default != nil {
+ target.Set(reflect.ValueOf(p.parameter.Default))
+ }
+ return nil
+ }
+
+ if err := consumer.Consume(request.Body, newValue.Interface()); err != nil {
+ if stderrors.Is(err, io.EOF) && p.parameter.Default != nil {
+ target.Set(reflect.ValueOf(p.parameter.Default))
return nil
}
- if err := consumer.Consume(request.Body, newValue.Interface()); err != nil {
- if err == io.EOF && p.parameter.Default != nil {
- target.Set(reflect.ValueOf(p.parameter.Default))
- return nil
- }
- tpe := p.parameter.Type
- if p.parameter.Format != "" {
- tpe = p.parameter.Format
- }
- return errors.InvalidType(p.Name, p.parameter.In, tpe, nil)
+ tpe := p.parameter.Type
+ if p.parameter.Format != "" {
+ tpe = p.parameter.Format
}
- target.Set(reflect.Indirect(newValue))
- return nil
- default:
- return fmt.Errorf("%d: invalid parameter location %q", http.StatusInternalServerError, p.parameter.In)
+ return errors.InvalidType(p.Name, p.parameter.In, tpe, nil)
}
+
+ target.Set(reflect.Indirect(newValue))
+
+ return nil
}
func (p *untypedParamBinder) typeForSchema(tpe, format string, items *spec.Items) reflect.Type {
@@ -261,20 +288,51 @@ func (p *untypedParamBinder) bindValue(data []string, hasKey bool, target reflec
if p.parameter.Type == typeArray {
return p.setSliceFieldValue(target, p.parameter.Default, data, hasKey)
}
+
var d string
if len(data) > 0 {
d = data[len(data)-1]
}
+
return p.setFieldValue(target, p.parameter.Default, d, hasKey)
}
-func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue any, data string, hasKey bool) error { //nolint:gocyclo
+func (p *untypedParamBinder) isMissingAndRequired(hasKey bool, data string) bool {
+ return p.parameter.Required &&
+ p.parameter.Default == nil &&
+ (!hasKey || (!p.parameter.AllowEmptyValue && data == ""))
+}
+
+func (p *untypedParamBinder) setByte(target, defVal reflect.Value, tpe, data string) error {
+ if data == "" {
+ if target.CanSet() {
+ target.SetBytes(defVal.Bytes())
+ }
+
+ return nil
+ }
+
+ b, err := base64.StdEncoding.DecodeString(data)
+ if err != nil {
+ b, err = base64.URLEncoding.DecodeString(data)
+ if err != nil {
+ return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
+ }
+ }
+ if target.CanSet() {
+ target.SetBytes(b)
+ }
+
+ return nil
+}
+
+func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue any, data string, hasKey bool) error {
tpe := p.parameter.Type
if p.parameter.Format != "" {
tpe = p.parameter.Format
}
- if (!hasKey || (!p.parameter.AllowEmptyValue && data == "")) && p.parameter.Required && p.parameter.Default == nil {
+ if p.isMissingAndRequired(hasKey, data) {
return errors.Required(p.Name, p.parameter.In, data)
}
@@ -292,27 +350,15 @@ func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue an
}
if tpe == "byte" {
- if data == "" {
- if target.CanSet() {
- target.SetBytes(defVal.Bytes())
- }
- return nil
- }
-
- b, err := base64.StdEncoding.DecodeString(data)
- if err != nil {
- b, err = base64.URLEncoding.DecodeString(data)
- if err != nil {
- return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
- }
- }
- if target.CanSet() {
- target.SetBytes(b)
- }
- return nil
+ return p.setByte(target, defVal, tpe, data)
}
- switch target.Kind() { //nolint:exhaustive // we want to check only types that map from a swagger parameter
+ return p.setReflectFieldValue(target, defVal, tpe, data, hasKey)
+}
+
+//nolint:gocyclo,cyclop // not much we can simplify further significantly: the big case with all types is unavoidable.
+func (p *untypedParamBinder) setReflectFieldValue(target, defVal reflect.Value, tpe, data string, hasKey bool) error {
+ switch target.Kind() { // we want to check only types that map from a swagger parameter
case reflect.Bool:
if data == "" {
if target.CanSet() {
@@ -327,6 +373,7 @@ func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue an
if target.CanSet() {
target.SetBool(b)
}
+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if data == "" {
if target.CanSet() {
@@ -394,8 +441,8 @@ func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue an
target.SetString(value)
}
- case reflect.Ptr:
- if data == "" && defVal.Kind() == reflect.Ptr {
+ case reflect.Pointer:
+ if data == "" && defVal.Kind() == reflect.Pointer {
if target.CanSet() {
target.Set(defVal)
}
@@ -412,6 +459,7 @@ func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue an
default:
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
}
+
return nil
}
@@ -419,20 +467,30 @@ func (p *untypedParamBinder) tryUnmarshaler(target reflect.Value, defaultValue a
if !target.CanSet() {
return false, nil
}
+
// When a type implements encoding.TextUnmarshaler we'll use that instead of reflecting some more
- if reflect.PointerTo(target.Type()).Implements(textUnmarshalType) {
- if defaultValue != nil && len(data) == 0 {
- target.Set(reflect.ValueOf(defaultValue))
- return true, nil
- }
- value := reflect.New(target.Type())
- if err := value.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(data)); err != nil {
- return true, err
- }
- target.Set(reflect.Indirect(value))
+ ttyp := target.Type()
+ if !reflect.PointerTo(ttyp).Implements(textUnmarshalType) {
+ return false, nil
+ }
+
+ if defaultValue != nil && len(data) == 0 {
+ target.Set(reflect.ValueOf(defaultValue))
return true, nil
}
- return false, nil
+
+ value := reflect.New(ttyp)
+ if !value.CanInterface() {
+ return false, nil
+ }
+
+ if err := value.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(data)); err != nil { //nolint:forcetypeassert // this is guaranteed by the reflect check above
+ return true, err
+ }
+
+ target.Set(reflect.Indirect(value))
+
+ return true, nil
}
func (p *untypedParamBinder) readFormattedSliceFieldValue(data string, target reflect.Value) ([]string, bool, error) {
diff --git a/vendor/github.com/go-openapi/runtime/middleware/rapidoc.go b/vendor/github.com/go-openapi/runtime/middleware/rapidoc.go
deleted file mode 100644
index 1574defb41a..00000000000
--- a/vendor/github.com/go-openapi/runtime/middleware/rapidoc.go
+++ /dev/null
@@ -1,83 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
-// SPDX-License-Identifier: Apache-2.0
-
-package middleware
-
-import (
- "bytes"
- "fmt"
- "html/template"
- "net/http"
- "path"
-)
-
-// RapiDocOpts configures the [RapiDoc] middlewares.
-type RapiDocOpts struct {
- // BasePath for the UI, defaults to: /
- BasePath string
-
- // Path combines with BasePath to construct the path to the UI, defaults to: "docs".
- Path string
-
- // SpecURL is the URL of the spec document.
- //
- // Defaults to: /swagger.json
- SpecURL string
-
- // Title for the documentation site, default to: API documentation
- Title string
-
- // Template specifies a custom template to serve the UI
- Template string
-
- // RapiDocURL points to the js asset that generates the rapidoc site.
- //
- // Defaults to https://unpkg.com/rapidoc/dist/rapidoc-min.js
- RapiDocURL string
-}
-
-func (r *RapiDocOpts) EnsureDefaults() {
- common := toCommonUIOptions(r)
- common.EnsureDefaults()
- fromCommonToAnyOptions(common, r)
-
- // rapidoc-specifics
- if r.RapiDocURL == "" {
- r.RapiDocURL = rapidocLatest
- }
- if r.Template == "" {
- r.Template = rapidocTemplate
- }
-}
-
-// RapiDoc creates a [middleware] to serve a documentation site for a swagger spec.
-//
-// This allows for altering the spec before starting the [http] listener.
-func RapiDoc(opts RapiDocOpts, next http.Handler) http.Handler {
- opts.EnsureDefaults()
-
- pth := path.Join(opts.BasePath, opts.Path)
- tmpl := template.Must(template.New("rapidoc").Parse(opts.Template))
- assets := bytes.NewBuffer(nil)
- if err := tmpl.Execute(assets, opts); err != nil {
- panic(fmt.Errorf("cannot execute template: %w", err))
- }
-
- return serveUI(pth, assets.Bytes(), next)
-}
-
-const (
- rapidocLatest = "https://unpkg.com/rapidoc/dist/rapidoc-min.js"
- rapidocTemplate = `
-
-
- {{ .Title }}
-
-
-
-
-
-
-
-`
-)
diff --git a/vendor/github.com/go-openapi/runtime/middleware/redoc.go b/vendor/github.com/go-openapi/runtime/middleware/redoc.go
deleted file mode 100644
index 1007409a30b..00000000000
--- a/vendor/github.com/go-openapi/runtime/middleware/redoc.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
-// SPDX-License-Identifier: Apache-2.0
-
-package middleware
-
-import (
- "bytes"
- "fmt"
- "html/template"
- "net/http"
- "path"
-)
-
-// RedocOpts configures the [Redoc] middlewares.
-type RedocOpts struct {
- // BasePath for the UI, defaults to: /
- BasePath string
-
- // Path combines with BasePath to construct the path to the UI, defaults to: "docs".
- Path string
-
- // SpecURL is the URL of the spec document.
- //
- // Defaults to: /swagger.json
- SpecURL string
-
- // Title for the documentation site, default to: API documentation
- Title string
-
- // Template specifies a custom template to serve the UI
- Template string
-
- // RedocURL points to the js that generates the redoc site.
- //
- // Defaults to: https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js
- RedocURL string
-}
-
-// EnsureDefaults in case some options are missing.
-func (r *RedocOpts) EnsureDefaults() {
- common := toCommonUIOptions(r)
- common.EnsureDefaults()
- fromCommonToAnyOptions(common, r)
-
- // redoc-specifics
- if r.RedocURL == "" {
- r.RedocURL = redocLatest
- }
- if r.Template == "" {
- r.Template = redocTemplate
- }
-}
-
-// Redoc creates a [middleware] to serve a documentation site for a swagger spec.
-//
-// This allows for altering the spec before starting the [http] listener.
-func Redoc(opts RedocOpts, next http.Handler) http.Handler {
- opts.EnsureDefaults()
-
- pth := path.Join(opts.BasePath, opts.Path)
- tmpl := template.Must(template.New("redoc").Parse(opts.Template))
- assets := bytes.NewBuffer(nil)
- if err := tmpl.Execute(assets, opts); err != nil {
- panic(fmt.Errorf("cannot execute template: %w", err))
- }
-
- return serveUI(pth, assets.Bytes(), next)
-}
-
-const (
- redocLatest = "https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js"
- redocTemplate = `
-
-
- {{ .Title }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-`
-)
diff --git a/vendor/github.com/go-openapi/runtime/middleware/request.go b/vendor/github.com/go-openapi/runtime/middleware/request.go
index ad781663b8b..08a0362da29 100644
--- a/vendor/github.com/go-openapi/runtime/middleware/request.go
+++ b/vendor/github.com/go-openapi/runtime/middleware/request.go
@@ -40,8 +40,25 @@ func NewUntypedRequestBinder(parameters map[string]spec.Parameter, spec *spec.Sw
// Bind perform the databinding and validation.
func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, data any) error {
+ err := o.bind(request, routeParams, consumer, data)
+ if err == nil {
+ return nil // avoids returning a nil-interface
+ }
+
+ return err
+}
+
+// SetLogger allows for injecting a logger to catch debug entries.
+//
+// The logger is enabled in DEBUG mode only.
+func (o *UntypedRequestBinder) SetLogger(lg logger.Logger) {
+ o.debugLogf = debugLogfFunc(lg)
+}
+
+func (o *UntypedRequestBinder) bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, data any) *errors.CompositeError {
val := reflect.Indirect(reflect.ValueOf(data))
isMap := val.Kind() == reflect.Map
+
var result []error
o.debugLogf("binding %d parameters for %s %s", len(o.Parameters), request.Method, request.URL.EscapedPath())
for fieldName, param := range o.Parameters {
@@ -94,13 +111,6 @@ func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RoutePara
return nil
}
-// SetLogger allows for injecting a logger to catch debug entries.
-//
-// The logger is enabled in DEBUG mode only.
-func (o *UntypedRequestBinder) SetLogger(lg logger.Logger) {
- o.debugLogf = debugLogfFunc(lg)
-}
-
func (o *UntypedRequestBinder) setDebugLogf(fn func(string, ...any)) {
o.debugLogf = fn
}
diff --git a/vendor/github.com/go-openapi/runtime/middleware/router.go b/vendor/github.com/go-openapi/runtime/middleware/router.go
index e828653be7a..939cf7337ab 100644
--- a/vendor/github.com/go-openapi/runtime/middleware/router.go
+++ b/vendor/github.com/go-openapi/runtime/middleware/router.go
@@ -21,6 +21,7 @@ import (
"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag/stringutils"
+ "github.com/go-openapi/swag/typeutils"
)
// RouteParam is a object to capture route params in a framework agnostic way.
@@ -292,7 +293,7 @@ func (ras RouteAuthenticators) Authenticate(req *http.Request, route *MatchedRou
continue
}
applies, usr, err := ra.Authenticate(req, route)
- if !applies || err != nil || usr == nil {
+ if !applies || err != nil || typeutils.IsZero(usr) {
if err != nil {
lastError = err
}
@@ -348,49 +349,62 @@ func (m *MatchedRoute) NeedsAuth() bool {
func (d *defaultRouter) Lookup(method, path string) (*MatchedRoute, bool) {
mth := strings.ToUpper(method)
d.debugLogf("looking up route for %s %s", method, path)
- if Debug {
- if len(d.routers) == 0 {
+ if len(d.routers) == 0 {
+ if Debug {
d.debugLogf("there are no known routers")
}
+ panic("internal error: no router is configured")
+ }
+
+ if Debug {
for meth := range d.routers {
d.debugLogf("got a router for %s", meth)
}
}
- if router, ok := d.routers[mth]; ok {
- if m, rp, ok := router.Lookup(fpath.Clean(path)); ok && m != nil {
- if entry, ok := m.(*routeEntry); ok {
- d.debugLogf("found a route for %s %s with %d parameters", method, path, len(entry.Parameters))
- var params RouteParams
- for _, p := range rp {
- v, err := url.PathUnescape(p.Value)
- if err != nil {
- d.debugLogf("failed to escape %q: %v", p.Value, err)
- v = p.Value
- }
- // a workaround to handle fragment/composing parameters until they are supported in denco router
- // check if this parameter is a fragment within a path segment
- const enclosureSize = 2
- if xpos := strings.Index(entry.PathPattern, fmt.Sprintf("{%s}", p.Name)) + len(p.Name) + enclosureSize; xpos < len(entry.PathPattern) && entry.PathPattern[xpos] != '/' {
- // extract fragment parameters
- ep := strings.Split(entry.PathPattern[xpos:], "/")[0]
- pnames, pvalues := decodeCompositParams(p.Name, v, ep, nil, nil)
- for i, pname := range pnames {
- params = append(params, RouteParam{Name: pname, Value: pvalues[i]})
- }
- } else {
- // use the parameter directly
- params = append(params, RouteParam{Name: p.Name, Value: v})
- }
- }
- return &MatchedRoute{routeEntry: *entry, Params: params}, true
+
+ router, ok := d.routers[mth]
+ if !ok {
+ d.debugLogf("couldn't find a route by method for %s %s", method, path)
+ return nil, false
+ }
+
+ m, rp, ok := router.Lookup(fpath.Clean(escapeLiteralColons(path)))
+ if !ok || m == nil {
+ d.debugLogf("couldn't find a route by path for %s %s", method, path)
+ return nil, false
+ }
+
+ entry, ok := m.(*routeEntry)
+ if !ok {
+ return nil, false
+ }
+
+ d.debugLogf("found a route for %s %s with %d parameters", method, path, len(entry.Parameters))
+ var params RouteParams
+ for _, p := range rp {
+ v, err := url.PathUnescape(p.Value)
+ if err != nil {
+ d.debugLogf("failed to escape %q: %v", p.Value, err)
+ v = p.Value
+ }
+
+ // a workaround to handle fragment/composing parameters until they are supported in denco router
+ // check if this parameter is a fragment within a path segment
+ const enclosureSize = 2
+ if xpos := strings.Index(entry.PathPattern, fmt.Sprintf("{%s}", p.Name)) + len(p.Name) + enclosureSize; xpos < len(entry.PathPattern) && entry.PathPattern[xpos] != '/' {
+ // extract fragment parameters
+ ep := strings.Split(entry.PathPattern[xpos:], "/")[0]
+ pnames, pvalues := decodeCompositParams(p.Name, v, ep, nil, nil)
+ for i, pname := range pnames {
+ params = append(params, RouteParam{Name: pname, Value: pvalues[i]})
}
} else {
- d.debugLogf("couldn't find a route by path for %s %s", method, path)
+ // use the parameter directly
+ params = append(params, RouteParam{Name: p.Name, Value: v})
}
- } else {
- d.debugLogf("couldn't find a route by method for %s %s", method, path)
}
- return nil, false
+
+ return &MatchedRoute{routeEntry: *entry, Params: params}, true
}
func (d *defaultRouter) OtherMethods(method, path string) []string {
@@ -398,7 +412,7 @@ func (d *defaultRouter) OtherMethods(method, path string) []string {
var methods []string
for k, v := range d.routers {
if k != mn {
- if _, _, ok := v.Lookup(fpath.Clean(path)); ok {
+ if _, _, ok := v.Lookup(fpath.Clean(escapeLiteralColons(path))); ok {
methods = append(methods, k)
continue
}
@@ -414,28 +428,39 @@ func (d *defaultRouter) SetLogger(lg logger.Logger) {
// convert swagger parameters per path segment into a denco parameter as multiple parameters per segment are not supported in denco.
var pathConverter = regexp.MustCompile(`{(.+?)}([^/]*)`)
+// escapeLiteralColons replaces literal ':' characters with their URL-encoded
+// equivalent "%3A". This prevents the denco router from misinterpreting ':'
+// in URL path segments as parameter delimiters. The ':' character is valid in
+// URL paths per RFC 3986 section 3.3.
+func escapeLiteralColons(path string) string {
+ return strings.ReplaceAll(path, ":", "%3A")
+}
+
func decodeCompositParams(name string, value string, pattern string, names []string, values []string) ([]string, []string) {
pleft := strings.Index(pattern, "{")
names = append(names, name)
+
if pleft < 0 {
if strings.HasSuffix(value, pattern) {
values = append(values, value[:len(value)-len(pattern)])
} else {
values = append(values, "")
}
+
+ return names, values
+ }
+
+ toskip := pattern[:pleft]
+ pright := strings.Index(pattern, "}")
+ vright := strings.Index(value, toskip)
+ if vright >= 0 {
+ values = append(values, value[:vright])
} else {
- toskip := pattern[:pleft]
- pright := strings.Index(pattern, "}")
- vright := strings.Index(value, toskip)
- if vright >= 0 {
- values = append(values, value[:vright])
- } else {
- values = append(values, "")
- value = ""
- }
- return decodeCompositParams(pattern[pleft+1:pright], value[vright+len(toskip):], pattern[pright+1:], names, values)
+ values = append(values, "")
+ value = ""
}
- return names, values
+
+ return decodeCompositParams(pattern[pleft+1:pright], value[vright+len(toskip):], pattern[pright+1:], names, values)
}
func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Operation) {
@@ -463,7 +488,7 @@ func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Oper
requestBinder := NewUntypedRequestBinder(parameters, d.spec.Spec(), d.api.Formats())
requestBinder.setDebugLogf(d.debugLogf)
- record := denco.NewRecord(pathConverter.ReplaceAllString(path, ":$1"), &routeEntry{
+ record := denco.NewRecord(pathConverter.ReplaceAllString(escapeLiteralColons(path), ":$1"), &routeEntry{
BasePath: bp,
PathPattern: path,
Operation: operation,
diff --git a/vendor/github.com/go-openapi/runtime/middleware/seam.go b/vendor/github.com/go-openapi/runtime/middleware/seam.go
new file mode 100644
index 00000000000..b234395f19c
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/middleware/seam.go
@@ -0,0 +1,482 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package middleware
+
+import (
+ "net/http"
+ "path"
+ "strings"
+
+ "github.com/go-openapi/runtime/server-middleware/docui"
+ "github.com/go-openapi/runtime/server-middleware/negotiate"
+)
+
+/////////////////////////////////////////////////////////:
+// Seam to the negotiate options introduced in v0.29.5
+/////////////////////////////////////////////////////////:
+
+// NegotiateOption configures [NegotiateContentType] behaviour.
+//
+// Deprecated: moved to the [negotiate] package. Use [negotiate.Option] instead.
+type NegotiateOption = negotiate.Option
+
+// NegotiateContentType returns the best offered content type for the
+// request's Accept header.
+//
+// Deprecated: moved to the [negotiate] package. Use [negotiate.ContentType] instead.
+func NegotiateContentType(r *http.Request, offers []string, defaultOffer string, opts ...NegotiateOption) string {
+ return negotiate.ContentType(r, offers, defaultOffer, opts...)
+}
+
+// NegotiateContentEncoding returns the best offered content encoding for
+// the request's Accept-Encoding header.
+//
+// Deprecated: moved to the [negotiate] package. Use [negotiate.ContentEncoding] instead.
+func NegotiateContentEncoding(r *http.Request, offers []string) string {
+ return negotiate.ContentEncoding(r, offers)
+}
+
+// WithIgnoreParameters returns a [NegotiateOption] that strips MIME-type
+// parameters from both Accept entries and offers before matching,
+// restoring the pre-v0.30 behaviour.
+//
+// Deprecated: moved to the [negotiate] package. Use [negotiate.WithIgnoreParameters] instead.
+func WithIgnoreParameters(ignore bool) NegotiateOption {
+ return negotiate.WithIgnoreParameters(ignore)
+}
+
+/////////////////////////////////////////////////////////:
+// Seam to the UI options
+/////////////////////////////////////////////////////////:
+
+// RapiDoc creates a [http.Handler] to serve a documentation site for a swagger spec.
+//
+// This allows for altering the spec before starting the [http] listener.
+//
+// Deprecated: moved to the [docui] package. Use [docui.RapiDoc] instead.
+func RapiDoc(opts RapiDocOpts, next http.Handler) http.Handler {
+ return docui.RapiDoc(next, opts.toFuncOptions()...)
+}
+
+// Redoc creates a [http.Handler] to serve a documentation site for a swagger spec.
+//
+// This allows for altering the spec before starting the [http] listener.
+//
+// Deprecated: moved to the [docui] package. Use [docui.Redoc] instead.
+func Redoc(opts RedocOpts, next http.Handler) http.Handler {
+ return docui.Redoc(next, opts.toFuncOptions()...)
+}
+
+// SwaggerUI creates a [http.Handler] to serve a documentation site for a swagger spec.
+//
+// This allows for altering the spec before starting the [http] listener.
+//
+// Deprecated: moved to the [docui] package. Use [docui.SwaggerUI] instead.
+func SwaggerUI(opts SwaggerUIOpts, next http.Handler) http.Handler {
+ return docui.SwaggerUI(next, opts.toFuncOptions()...)
+}
+
+// SwaggerUIOAuth2Callback creates a middleware that serves the OAuth2 callback page used by Swagger UI.
+//
+// Deprecated: moved to the [docui] package. Use [docui.SwaggerUIOAuth2Callback] instead.
+func SwaggerUIOAuth2Callback(opts SwaggerUIOpts, next http.Handler) http.Handler {
+ return docui.SwaggerUIOAuth2Callback(next, opts.toFuncOptions()...)
+}
+
+/////////////////////////////////////////////////////////:
+// Seam to the spec middleware options
+/////////////////////////////////////////////////////////:
+
+// SpecOption can be applied to the [Spec] serving [middleware].
+//
+// Deprecated: moved to the [docui] package. Use [docui.SpecOption] instead.
+type SpecOption func(*specOptions)
+
+type specOptions struct {
+ BasePath string
+ Path string
+ Document string
+}
+
+func (o specOptions) fullPath() string {
+ return path.Join(o.BasePath, o.Path, o.Document)
+}
+
+func specOptionsWithDefaults(basePath string, opts []SpecOption) specOptions {
+ o := specOptions{
+ BasePath: "/",
+ Path: "",
+ Document: "swagger.json",
+ }
+
+ for _, apply := range opts {
+ apply(&o)
+ }
+ if basePath != "" {
+ o.BasePath = basePath
+ }
+
+ return o
+}
+
+// Spec creates a [middleware] to serve a swagger spec as a JSON document.
+//
+// This allows for altering the spec before starting the [http] listener.
+//
+// The basePath argument indicates the path of the spec document (defaults to "/").
+// Additional [SpecOption] can be used to change the name of the document (defaults to "swagger.json").
+//
+// Deprecated: moved to the [docui] package as [docui.ServeSpec].
+func Spec(basePath string, spec []byte, next http.Handler, opts ...SpecOption) http.Handler {
+ o := specOptionsWithDefaults(basePath, opts)
+
+ return docui.ServeSpec(spec, next, docui.WithSpecPath(o.fullPath()))
+
+}
+
+// WithSpecPath sets the path to be joined to the base path of the
+// spec-serving middleware (see [docui.ServeSpec]).
+//
+// This is empty by default.
+func WithSpecPath(pth string) SpecOption {
+ return func(o *specOptions) {
+ o.Path = pth
+ }
+}
+
+// WithSpecDocument sets the name of the JSON document served as a spec.
+//
+// By default, this is "swagger.json".
+func WithSpecDocument(doc string) SpecOption {
+ return func(o *specOptions) {
+ if doc == "" {
+ return
+ }
+
+ o.Document = doc
+ }
+}
+
+// UIOptions defines common options for UI serving middlewares.
+//
+// Deprecated: use instead the function options provided by [docui].
+type UIOptions struct {
+ // BasePath for the UI, defaults to: /
+ BasePath string
+
+ // Path combines with BasePath to construct the path to the UI, defaults to: "docs".
+ Path string
+
+ // SpecURL is the URL of the spec document.
+ //
+ // Defaults to: /swagger.json
+ SpecURL string
+
+ // Title for the documentation site, default to: API documentation
+ Title string
+
+ // Template specifies a custom template to serve the UI
+ Template string
+}
+
+// toFuncOptions bridges the deprecated options struct with the newer function options in [docui].
+func (o UIOptions) toFuncOptions() []docui.Option {
+ const structMembers = 5
+ opts := make([]docui.Option, 0, structMembers)
+
+ if o.BasePath != "" {
+ opts = append(opts, docui.WithUIBasePath(o.BasePath))
+ }
+
+ if o.Path != "" {
+ opts = append(opts, docui.WithUIPath(o.Path))
+ }
+
+ if o.SpecURL != "" {
+ opts = append(opts, docui.WithSpecURL(o.SpecURL))
+ }
+
+ if o.Title != "" {
+ opts = append(opts, docui.WithUITitle(o.Title))
+ }
+
+ if o.Template != "" {
+ opts = append(opts, docui.WithUITemplate(o.Template))
+ }
+
+ return opts
+}
+
+// RapiDocOpts configures the [RapiDoc] middlewares.
+//
+// Deprecated: use instead the function options provided by [docui].
+type RapiDocOpts struct {
+ // BasePath for the UI, defaults to: /
+ BasePath string
+
+ // Path combines with BasePath to construct the path to the UI, defaults to: "docs".
+ Path string
+
+ // SpecURL is the URL of the spec document.
+ //
+ // Defaults to: /swagger.json
+ SpecURL string
+
+ // Title for the documentation site, default to: API documentation
+ Title string
+
+ // Template specifies a custom template to serve the UI
+ Template string
+
+ // RapiDocURL points to the js asset that generates the rapidoc site.
+ //
+ // Defaults to https://unpkg.com/rapidoc/dist/rapidoc-min.js
+ RapiDocURL string
+}
+
+func (o RapiDocOpts) toFuncOptions() []docui.Option {
+ const structMembers = 6
+ opts := make([]docui.Option, 0, structMembers)
+
+ if o.BasePath != "" {
+ opts = append(opts, docui.WithUIBasePath(o.BasePath))
+ }
+
+ if o.Path != "" {
+ opts = append(opts, docui.WithUIPath(o.Path))
+ }
+
+ if o.SpecURL != "" {
+ opts = append(opts, docui.WithSpecURL(o.SpecURL))
+ }
+
+ if o.Title != "" {
+ opts = append(opts, docui.WithUITitle(o.Title))
+ }
+
+ if o.Template != "" {
+ opts = append(opts, docui.WithUITemplate(o.Template))
+ }
+
+ if o.RapiDocURL != "" {
+ opts = append(opts, docui.WithUIAssetsURL(o.RapiDocURL))
+ }
+
+ return opts
+}
+
+// RedocOpts configures the [Redoc] middlewares.
+//
+// Deprecated: use instead the function options provided by [docui].
+type RedocOpts struct {
+ // BasePath for the UI, defaults to: /
+ BasePath string
+
+ // Path combines with BasePath to construct the path to the UI, defaults to: "docs".
+ Path string
+
+ // SpecURL is the URL of the spec document.
+ //
+ // Defaults to: /swagger.json
+ SpecURL string
+
+ // Title for the documentation site, default to: API documentation
+ Title string
+
+ // Template specifies a custom template to serve the UI
+ Template string
+
+ // RedocURL points to the js that generates the redoc site.
+ //
+ // Defaults to: https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js
+ RedocURL string
+}
+
+func (o RedocOpts) toFuncOptions() []docui.Option {
+ const structMembers = 6
+ opts := make([]docui.Option, 0, structMembers)
+
+ if o.BasePath != "" {
+ opts = append(opts, docui.WithUIBasePath(o.BasePath))
+ }
+
+ if o.Path != "" {
+ opts = append(opts, docui.WithUIPath(o.Path))
+ }
+
+ if o.SpecURL != "" {
+ opts = append(opts, docui.WithSpecURL(o.SpecURL))
+ }
+
+ if o.Title != "" {
+ opts = append(opts, docui.WithUITitle(o.Title))
+ }
+
+ if o.Template != "" {
+ opts = append(opts, docui.WithUITemplate(o.Template))
+ }
+
+ if o.RedocURL != "" {
+ opts = append(opts, docui.WithUIAssetsURL(o.RedocURL))
+ }
+
+ return opts
+}
+
+// SwaggerUIOpts configures the [SwaggerUI] [middleware].
+//
+// Deprecated: use instead the function options provided by [docui].
+type SwaggerUIOpts struct {
+ // BasePath for the API, defaults to: /
+ BasePath string
+
+ // Path combines with BasePath to construct the path to the UI, defaults to: "docs".
+ Path string
+
+ // SpecURL is the URL of the spec document.
+ //
+ // Defaults to: /swagger.json
+ SpecURL string
+
+ // Title for the documentation site, default to: API documentation
+ Title string
+
+ // Template specifies a custom template to serve the UI
+ Template string
+
+ // OAuthCallbackURL the url called after OAuth2 login
+ //
+ // NOTE: in the new [docui.SwaggerUIOptions] type, this field is named `OAuth2CallbackURL`,
+ // which is more appropriate.
+ OAuthCallbackURL string
+
+ // The three components needed to embed swagger-ui
+
+ // SwaggerURL points to the js that generates the SwaggerUI site.
+ //
+ // Defaults to: https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js
+ SwaggerURL string
+
+ SwaggerPresetURL string
+ SwaggerStylesURL string
+
+ Favicon32 string
+ Favicon16 string
+}
+
+func (o SwaggerUIOpts) toFuncOptions() []docui.Option {
+ const structMembers = 6
+ opts := make([]docui.Option, 0, structMembers)
+
+ if o.BasePath != "" {
+ opts = append(opts, docui.WithUIBasePath(o.BasePath))
+ }
+
+ if o.Path != "" {
+ opts = append(opts, docui.WithUIPath(o.Path))
+ }
+
+ if o.SpecURL != "" {
+ opts = append(opts, docui.WithSpecURL(o.SpecURL))
+ }
+
+ if o.Title != "" {
+ opts = append(opts, docui.WithUITitle(o.Title))
+ }
+
+ if o.Template != "" {
+ opts = append(opts, docui.WithUITemplate(o.Template))
+ }
+
+ if o.SwaggerURL != "" {
+ opts = append(opts, docui.WithUIAssetsURL(o.SwaggerURL))
+ }
+
+ var empty SwaggerUIOpts
+ if o != empty {
+ swaggeruiOpts := docui.SwaggerUIOptions{
+ OAuth2CallbackURL: o.OAuthCallbackURL,
+ SwaggerPresetURL: o.SwaggerPresetURL,
+ SwaggerStylesURL: o.SwaggerStylesURL,
+ Favicon32: o.Favicon32,
+ Favicon16: o.Favicon16,
+ }
+ opts = append(opts, docui.WithSwaggerUIOptions(swaggeruiOpts))
+ }
+
+ return opts
+}
+
+// UIOption can be applied to UI serving [middleware] to alter the default
+// behavior.
+//
+// Deprecated: use instead the function options provided by [docui].
+type UIOption func(*UIOptions)
+
+// uiOptionsWithDefaults applies the given options on top of an empty
+// [UIOptions]. Per-flavor handlers ([SwaggerUI], [Redoc], [RapiDoc])
+// fill in the remaining defaults via [UIOptions.EnsureDefaults] when
+// the option struct is used.
+func uiOptionsWithDefaults(opts []UIOption) UIOptions {
+ var o UIOptions
+ for _, apply := range opts {
+ apply(&o)
+ }
+
+ return o
+}
+
+// WithUIBasePath sets the base path from where to serve the UI assets.
+//
+// Deprecated: use instead the function options provided by [docui].
+func WithUIBasePath(base string) UIOption {
+ return func(o *UIOptions) {
+ if !strings.HasPrefix(base, "/") {
+ base = "/" + base
+ }
+ o.BasePath = base
+ }
+}
+
+// WithUIPath sets the path from where to serve the UI assets (i.e. /{basepath}/{path}.
+//
+// Deprecated: use instead the function options provided by [docui].
+func WithUIPath(pth string) UIOption {
+ return func(o *UIOptions) {
+ o.Path = pth
+ }
+}
+
+// WithUISpecURL sets the path from where to serve swagger spec document.
+//
+// This may be specified as a full URL or a path.
+//
+// By default, this is "/swagger.json".
+//
+// Deprecated: use instead the function options provided by [docui].
+func WithUISpecURL(specURL string) UIOption {
+ return func(o *UIOptions) {
+ o.SpecURL = specURL
+ }
+}
+
+// WithUITitle sets the title of the UI.
+//
+// Deprecated: use instead the function options provided by [docui].
+func WithUITitle(title string) UIOption {
+ return func(o *UIOptions) {
+ o.Title = title
+ }
+}
+
+// WithTemplate allows to set a custom template for the UI.
+//
+// UI [middleware] will panic if the template does not parse or execute properly.
+//
+// Deprecated: use instead the function options provided by [docui].
+func WithTemplate(tpl string) UIOption {
+ return func(o *UIOptions) {
+ o.Template = tpl
+ }
+}
diff --git a/vendor/github.com/go-openapi/runtime/middleware/spec.go b/vendor/github.com/go-openapi/runtime/middleware/spec.go
deleted file mode 100644
index 0a64a9572b5..00000000000
--- a/vendor/github.com/go-openapi/runtime/middleware/spec.go
+++ /dev/null
@@ -1,91 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
-// SPDX-License-Identifier: Apache-2.0
-
-package middleware
-
-import (
- "net/http"
- "path"
-)
-
-const (
- contentTypeHeader = "Content-Type"
- applicationJSON = "application/json"
-)
-
-// SpecOption can be applied to the Spec serving [middleware].
-type SpecOption func(*specOptions)
-
-var defaultSpecOptions = specOptions{
- Path: "",
- Document: "swagger.json",
-}
-
-type specOptions struct {
- Path string
- Document string
-}
-
-func specOptionsWithDefaults(opts []SpecOption) specOptions {
- o := defaultSpecOptions
- for _, apply := range opts {
- apply(&o)
- }
-
- return o
-}
-
-// Spec creates a [middleware] to serve a swagger spec as a JSON document.
-//
-// This allows for altering the spec before starting the [http] listener.
-//
-// The basePath argument indicates the path of the spec document (defaults to "/").
-// Additional [SpecOption] can be used to change the name of the document (defaults to "swagger.json").
-func Spec(basePath string, b []byte, next http.Handler, opts ...SpecOption) http.Handler {
- if basePath == "" {
- basePath = "/"
- }
- o := specOptionsWithDefaults(opts)
- pth := path.Join(basePath, o.Path, o.Document)
-
- return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
- if path.Clean(r.URL.Path) == pth {
- rw.Header().Set(contentTypeHeader, applicationJSON)
- rw.WriteHeader(http.StatusOK)
- _, _ = rw.Write(b)
-
- return
- }
-
- if next != nil {
- next.ServeHTTP(rw, r)
-
- return
- }
-
- rw.Header().Set(contentTypeHeader, applicationJSON)
- rw.WriteHeader(http.StatusNotFound)
- })
-}
-
-// WithSpecPath sets the path to be joined to the base path of the Spec [middleware].
-//
-// This is empty by default.
-func WithSpecPath(pth string) SpecOption {
- return func(o *specOptions) {
- o.Path = pth
- }
-}
-
-// WithSpecDocument sets the name of the JSON document served as a spec.
-//
-// By default, this is "swagger.json".
-func WithSpecDocument(doc string) SpecOption {
- return func(o *specOptions) {
- if doc == "" {
- return
- }
-
- o.Document = doc
- }
-}
diff --git a/vendor/github.com/go-openapi/runtime/middleware/swaggerui.go b/vendor/github.com/go-openapi/runtime/middleware/swaggerui.go
deleted file mode 100644
index 14ed37ced69..00000000000
--- a/vendor/github.com/go-openapi/runtime/middleware/swaggerui.go
+++ /dev/null
@@ -1,178 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
-// SPDX-License-Identifier: Apache-2.0
-
-package middleware
-
-import (
- "bytes"
- "fmt"
- "html/template"
- "net/http"
- "path"
-)
-
-// SwaggerUIOpts configures the [SwaggerUI] [middleware].
-type SwaggerUIOpts struct {
- // BasePath for the API, defaults to: /
- BasePath string
-
- // Path combines with BasePath to construct the path to the UI, defaults to: "docs".
- Path string
-
- // SpecURL is the URL of the spec document.
- //
- // Defaults to: /swagger.json
- SpecURL string
-
- // Title for the documentation site, default to: API documentation
- Title string
-
- // Template specifies a custom template to serve the UI
- Template string
-
- // OAuthCallbackURL the url called after OAuth2 login
- OAuthCallbackURL string
-
- // The three components needed to embed swagger-ui
-
- // SwaggerURL points to the js that generates the SwaggerUI site.
- //
- // Defaults to: https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js
- SwaggerURL string
-
- SwaggerPresetURL string
- SwaggerStylesURL string
-
- Favicon32 string
- Favicon16 string
-}
-
-// EnsureDefaults in case some options are missing.
-func (r *SwaggerUIOpts) EnsureDefaults() {
- r.ensureDefaults()
-
- if r.Template == "" {
- r.Template = swaggeruiTemplate
- }
-}
-
-func (r *SwaggerUIOpts) EnsureDefaultsOauth2() {
- r.ensureDefaults()
-
- if r.Template == "" {
- r.Template = swaggerOAuthTemplate
- }
-}
-
-func (r *SwaggerUIOpts) ensureDefaults() {
- common := toCommonUIOptions(r)
- common.EnsureDefaults()
- fromCommonToAnyOptions(common, r)
-
- // swaggerui-specifics
- if r.OAuthCallbackURL == "" {
- r.OAuthCallbackURL = path.Join(r.BasePath, r.Path, "oauth2-callback")
- }
- if r.SwaggerURL == "" {
- r.SwaggerURL = swaggerLatest
- }
- if r.SwaggerPresetURL == "" {
- r.SwaggerPresetURL = swaggerPresetLatest
- }
- if r.SwaggerStylesURL == "" {
- r.SwaggerStylesURL = swaggerStylesLatest
- }
- if r.Favicon16 == "" {
- r.Favicon16 = swaggerFavicon16Latest
- }
- if r.Favicon32 == "" {
- r.Favicon32 = swaggerFavicon32Latest
- }
-}
-
-// SwaggerUI creates a [middleware] to serve a documentation site for a swagger spec.
-//
-// This allows for altering the spec before starting the [http] listener.
-func SwaggerUI(opts SwaggerUIOpts, next http.Handler) http.Handler {
- opts.EnsureDefaults()
-
- pth := path.Join(opts.BasePath, opts.Path)
- tmpl := template.Must(template.New("swaggerui").Parse(opts.Template))
- assets := bytes.NewBuffer(nil)
- if err := tmpl.Execute(assets, opts); err != nil {
- panic(fmt.Errorf("cannot execute template: %w", err))
- }
-
- return serveUI(pth, assets.Bytes(), next)
-}
-
-const (
- swaggerLatest = "https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"
- swaggerPresetLatest = "https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js"
- swaggerStylesLatest = "https://unpkg.com/swagger-ui-dist/swagger-ui.css"
- swaggerFavicon32Latest = "https://unpkg.com/swagger-ui-dist/favicon-32x32.png"
- swaggerFavicon16Latest = "https://unpkg.com/swagger-ui-dist/favicon-16x16.png"
- swaggeruiTemplate = `
-
-
-
-
- {{ .Title }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`
-)
diff --git a/vendor/github.com/go-openapi/runtime/middleware/swaggerui_oauth2.go b/vendor/github.com/go-openapi/runtime/middleware/swaggerui_oauth2.go
deleted file mode 100644
index 879bdbaadea..00000000000
--- a/vendor/github.com/go-openapi/runtime/middleware/swaggerui_oauth2.go
+++ /dev/null
@@ -1,108 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
-// SPDX-License-Identifier: Apache-2.0
-
-package middleware
-
-import (
- "bytes"
- "fmt"
- "net/http"
- "text/template"
-)
-
-func SwaggerUIOAuth2Callback(opts SwaggerUIOpts, next http.Handler) http.Handler {
- opts.EnsureDefaultsOauth2()
-
- pth := opts.OAuthCallbackURL
- tmpl := template.Must(template.New("swaggeroauth").Parse(opts.Template))
- assets := bytes.NewBuffer(nil)
- if err := tmpl.Execute(assets, opts); err != nil {
- panic(fmt.Errorf("cannot execute template: %w", err))
- }
-
- return serveUI(pth, assets.Bytes(), next)
-}
-
-const (
- swaggerOAuthTemplate = `
-
-
-
- {{ .Title }}
-
-
-
-
-
-`
-)
diff --git a/vendor/github.com/go-openapi/runtime/middleware/typeutils.go b/vendor/github.com/go-openapi/runtime/middleware/typeutils.go
new file mode 100644
index 00000000000..3f7d7976a1f
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/middleware/typeutils.go
@@ -0,0 +1,30 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package middleware
+
+import "strings"
+
+// normalizeOffer strips the parameter section (";...") from a media-type
+// string.
+func normalizeOffer(orig string) string {
+ // NOTE(maintainers): Despite its name (kept for historical reasons), this helper is
+ // not about Accept negotiation — it is used to derive the bare type that
+ // keys the producer/consumer maps registered on a [RoutableAPI].
+ // Those maps are looked up by the bare media type, so an entry registered as
+ // "application/json" satisfies a route that declares "application/json;
+ // charset=utf-8" and vice-versa.
+ const maxParts = 2
+
+ return strings.SplitN(orig, ";", maxParts)[0]
+}
+
+// normalizeOffers is the slice form of [normalizeOffer].
+func normalizeOffers(orig []string) []string {
+ norm := make([]string, 0, len(orig))
+ for _, o := range orig {
+ norm = append(norm, normalizeOffer(o))
+ }
+
+ return norm
+}
diff --git a/vendor/github.com/go-openapi/runtime/middleware/ui_options.go b/vendor/github.com/go-openapi/runtime/middleware/ui_options.go
deleted file mode 100644
index ed255426ad8..00000000000
--- a/vendor/github.com/go-openapi/runtime/middleware/ui_options.go
+++ /dev/null
@@ -1,176 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
-// SPDX-License-Identifier: Apache-2.0
-
-package middleware
-
-import (
- "bytes"
- "encoding/gob"
- "fmt"
- "net/http"
- "path"
- "strings"
-)
-
-const (
- // constants that are common to all UI-serving middlewares.
- defaultDocsPath = "docs"
- defaultDocsURL = "/swagger.json"
- defaultDocsTitle = "API Documentation"
-)
-
-// uiOptions defines common options for UI serving middlewares.
-type uiOptions struct {
- // BasePath for the UI, defaults to: /
- BasePath string
-
- // Path combines with BasePath to construct the path to the UI, defaults to: "docs".
- Path string
-
- // SpecURL is the URL of the spec document.
- //
- // Defaults to: /swagger.json
- SpecURL string
-
- // Title for the documentation site, default to: API documentation
- Title string
-
- // Template specifies a custom template to serve the UI
- Template string
-}
-
-// toCommonUIOptions converts any UI option type to retain the common options.
-//
-// This uses gob encoding/decoding to convert common fields from one struct to another.
-func toCommonUIOptions(opts any) uiOptions {
- var buf bytes.Buffer
- enc := gob.NewEncoder(&buf)
- dec := gob.NewDecoder(&buf)
- var o uiOptions
- err := enc.Encode(opts)
- if err != nil {
- panic(err)
- }
-
- err = dec.Decode(&o)
- if err != nil {
- panic(err)
- }
-
- return o
-}
-
-func fromCommonToAnyOptions[T any](source uiOptions, target *T) {
- var buf bytes.Buffer
- enc := gob.NewEncoder(&buf)
- dec := gob.NewDecoder(&buf)
- err := enc.Encode(source)
- if err != nil {
- panic(err)
- }
-
- err = dec.Decode(target)
- if err != nil {
- panic(err)
- }
-}
-
-// UIOption can be applied to UI serving [middleware], such as Context.[APIHandler] or
-// Context.[APIHandlerSwaggerUI] to alter the default behavior.
-type UIOption func(*uiOptions)
-
-func uiOptionsWithDefaults(opts []UIOption) uiOptions {
- var o uiOptions
- for _, apply := range opts {
- apply(&o)
- }
-
- return o
-}
-
-// WithUIBasePath sets the base path from where to serve the UI assets.
-//
-// By default, Context [middleware] sets this value to the API base path.
-func WithUIBasePath(base string) UIOption {
- return func(o *uiOptions) {
- if !strings.HasPrefix(base, "/") {
- base = "/" + base
- }
- o.BasePath = base
- }
-}
-
-// WithUIPath sets the path from where to serve the UI assets (i.e. /{basepath}/{path}.
-func WithUIPath(pth string) UIOption {
- return func(o *uiOptions) {
- o.Path = pth
- }
-}
-
-// WithUISpecURL sets the path from where to serve swagger spec document.
-//
-// This may be specified as a full URL or a path.
-//
-// By default, this is "/swagger.json".
-func WithUISpecURL(specURL string) UIOption {
- return func(o *uiOptions) {
- o.SpecURL = specURL
- }
-}
-
-// WithUITitle sets the title of the UI.
-//
-// By default, Context [middleware] sets this value to the title found in the API spec.
-func WithUITitle(title string) UIOption {
- return func(o *uiOptions) {
- o.Title = title
- }
-}
-
-// WithTemplate allows to set a custom template for the UI.
-//
-// UI [middleware] will panic if the template does not parse or execute properly.
-func WithTemplate(tpl string) UIOption {
- return func(o *uiOptions) {
- o.Template = tpl
- }
-}
-
-// EnsureDefaults in case some options are missing.
-func (r *uiOptions) EnsureDefaults() {
- if r.BasePath == "" {
- r.BasePath = "/"
- }
- if r.Path == "" {
- r.Path = defaultDocsPath
- }
- if r.SpecURL == "" {
- r.SpecURL = defaultDocsURL
- }
- if r.Title == "" {
- r.Title = defaultDocsTitle
- }
-}
-
-// serveUI creates a middleware that serves a templated asset as text/html.
-func serveUI(pth string, assets []byte, next http.Handler) http.Handler {
- return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
- if path.Clean(r.URL.Path) == pth {
- rw.Header().Set(contentTypeHeader, "text/html; charset=utf-8")
- rw.WriteHeader(http.StatusOK)
- _, _ = rw.Write(assets)
-
- return
- }
-
- if next != nil {
- next.ServeHTTP(rw, r)
-
- return
- }
-
- rw.Header().Set(contentTypeHeader, "text/plain")
- rw.WriteHeader(http.StatusNotFound)
- _, _ = fmt.Fprintf(rw, "%q not found", pth)
- })
-}
diff --git a/vendor/github.com/go-openapi/runtime/middleware/validation.go b/vendor/github.com/go-openapi/runtime/middleware/validation.go
index 8a56490639e..63a78d482a8 100644
--- a/vendor/github.com/go-openapi/runtime/middleware/validation.go
+++ b/vendor/github.com/go-openapi/runtime/middleware/validation.go
@@ -4,13 +4,14 @@
package middleware
import (
- "mime"
+ stderrors "errors"
"net/http"
"strings"
"github.com/go-openapi/errors"
+
"github.com/go-openapi/runtime"
- "github.com/go-openapi/swag/stringutils"
+ "github.com/go-openapi/runtime/server-middleware/mediatype"
)
type validation struct {
@@ -21,24 +22,28 @@ type validation struct {
bound map[string]any
}
-// ContentType validates the content type of a request.
-func validateContentType(allowed []string, actual string) error {
+// validateContentType maps [mediatype.MatchFirst] to the runtime's
+// validation errors:
+//
+// - actual fails to parse → HTTP 400 ([errors.NewParseError]).
+// - actual is well-formed but
+// no allowed entry accepts it → HTTP 415 ([errors.InvalidContentType]).
+//
+// In the standard runtime flow, malformed Content-Type headers are
+// already caught upstream by [runtime.ContentType] (which itself returns
+// a 400 [errors.ParseError]). This function therefore only sees the
+// malformed case when invoked directly by callers that have bypassed
+// that step.
+func validateContentType(allowed []string, actual string, opts ...mediatype.MatchOption) error {
if len(allowed) == 0 {
return nil
}
- mt, _, err := mime.ParseMediaType(actual)
- if err != nil {
- return errors.InvalidContentType(actual, allowed)
- }
- if stringutils.ContainsStringsCI(allowed, mt) {
- return nil
- }
- if stringutils.ContainsStringsCI(allowed, "*/*") {
+ _, ok, err := mediatype.MatchFirst(allowed, actual, opts...)
+ if ok {
return nil
}
- parts := strings.Split(actual, "/")
- if len(parts) == 2 && stringutils.ContainsStringsCI(allowed, parts[0]+"/*") {
- return nil
+ if err != nil {
+ return errors.NewParseError(runtime.HeaderContentType, "header", actual, err)
}
return errors.InvalidContentType(actual, allowed)
}
@@ -69,46 +74,53 @@ func (v *validation) debugLogf(format string, args ...any) {
func (v *validation) parameters() {
v.debugLogf("validating request parameters for %s %s", v.request.Method, v.request.URL.EscapedPath())
- if result := v.route.Binder.Bind(v.request, v.route.Params, v.route.Consumer, v.bound); result != nil {
- if result.Error() == "validation failure list" {
- for _, e := range result.(*errors.Validation).Value.([]any) {
- v.result = append(v.result, e.(error))
- }
- return
+ result := v.route.Binder.bind(v.request, v.route.Params, v.route.Consumer, v.bound)
+ if result == nil {
+ return
+ }
+
+ for _, e := range result.Errors {
+ var validationErr *errors.Validation
+ if stderrors.As(e, &validationErr) {
+ v.result = append(v.result, validationErr)
}
- v.result = append(v.result, result)
}
}
func (v *validation) contentType() {
- if len(v.result) == 0 && runtime.HasBody(v.request) {
- v.debugLogf("validating body content type for %s %s", v.request.Method, v.request.URL.EscapedPath())
- ct, _, req, err := v.context.ContentType(v.request)
- if err != nil {
+ if len(v.result) > 0 || !runtime.HasBody(v.request) {
+ return
+ }
+
+ v.debugLogf("validating body content type for %s %s", v.request.Method, v.request.URL.EscapedPath())
+ ct, _, req, err := v.context.ContentType(v.request)
+ if err != nil {
+ v.result = append(v.result, err)
+ } else {
+ v.request = req
+ }
+
+ if len(v.result) == 0 {
+ v.debugLogf("validating content type for %q against [%s]", ct, strings.Join(v.route.Consumes, ", "))
+ if err := validateContentType(v.route.Consumes, ct, v.context.matchOpts()...); err != nil {
v.result = append(v.result, err)
- } else {
- v.request = req
}
+ }
- if len(v.result) == 0 {
- v.debugLogf("validating content type for %q against [%s]", ct, strings.Join(v.route.Consumes, ", "))
- if err := validateContentType(v.route.Consumes, ct); err != nil {
- v.result = append(v.result, err)
- }
- }
- if ct != "" && v.route.Consumer == nil {
- cons, ok := v.route.Consumers[ct]
- if !ok {
- v.result = append(v.result, errors.New(http.StatusInternalServerError, "no consumer registered for %s", ct))
- } else {
- v.route.Consumer = cons
- }
- }
+ if ct == "" || v.route.Consumer != nil {
+ return
+ }
+
+ cons, ok := mediatype.Lookup(v.route.Consumers, ct, v.context.matchOpts()...)
+ if !ok {
+ v.result = append(v.result, errors.New(http.StatusInternalServerError, "no consumer registered for %s", ct))
+ } else {
+ v.route.Consumer = cons
}
}
func (v *validation) responseFormat() {
- // if the route provides values for Produces and no format could be identify then return an error.
+ // if the route provides values for Produces and no format could be identified then return an error.
// if the route does not specify values for Produces then treat request as valid since the API designer
// choose not to specify the format for responses.
if str, rCtx := v.context.ResponseFormat(v.request, v.route.Produces); str == "" && len(v.route.Produces) > 0 {
diff --git a/vendor/github.com/go-openapi/runtime/security/authenticator.go b/vendor/github.com/go-openapi/runtime/security/authenticator.go
index 4c091018265..e521d95ef16 100644
--- a/vendor/github.com/go-openapi/runtime/security/authenticator.go
+++ b/vendor/github.com/go-openapi/runtime/security/authenticator.go
@@ -19,8 +19,8 @@ const (
accessTokenParam = "access_token"
)
-// HttpAuthenticator is a function that authenticates a HTTP request.
-func HttpAuthenticator(handler func(*http.Request) (bool, any, error)) runtime.Authenticator { //nolint:revive
+// HTTPAuthenticator is a function that authenticates a HTTP request.
+func HTTPAuthenticator(handler func(*http.Request) (bool, any, error)) runtime.Authenticator {
return runtime.AuthenticatorFunc(func(params any) (bool, any, error) {
if request, ok := params.(*http.Request); ok {
return handler(request)
@@ -32,7 +32,14 @@ func HttpAuthenticator(handler func(*http.Request) (bool, any, error)) runtime.A
})
}
-// ScopedAuthenticator is a function that authenticates a HTTP request against a list of valid scopes.
+// HttpAuthenticator aliases [HTTPAuthenticator] for backward-compatibility.
+//
+// Deprecated: use [HTTPAuthenticator] instead.
+func HttpAuthenticator(handler func(*http.Request) (bool, any, error)) runtime.Authenticator { //nolint:revive
+ return HTTPAuthenticator(handler)
+}
+
+// ScopedAuthenticator is a function that authenticates an [http.Request] against a list of valid scopes.
func ScopedAuthenticator(handler func(*ScopedAuthRequest) (bool, any, error)) runtime.Authenticator {
return runtime.AuthenticatorFunc(func(params any) (bool, any, error) {
if request, ok := params.(*ScopedAuthRequest); ok {
@@ -42,22 +49,42 @@ func ScopedAuthenticator(handler func(*ScopedAuthRequest) (bool, any, error)) ru
})
}
-// UserPassAuthentication authentication function.
+// UserPassAuthentication validates a basic-auth credential.
+//
+// Implementations comparing the password (or any derived secret) against a
+// known value MUST use [crypto/subtle.ConstantTimeCompare]: the runtime
+// extracts the credential from the request and delegates the comparison
+// here, and does not enforce a constant-time posture on the caller's behalf.
type UserPassAuthentication func(string, string) (any, error)
-// UserPassAuthenticationCtx authentication function with [context.Context].
+// UserPassAuthenticationCtx is the [context.Context]-aware variant of
+// [UserPassAuthentication]. The same constant-time-comparison guidance
+// applies.
type UserPassAuthenticationCtx func(context.Context, string, string) (context.Context, any, error)
-// TokenAuthentication authentication function.
+// TokenAuthentication validates an API-key token.
+//
+// Implementations comparing the token against a known value MUST use
+// [crypto/subtle.ConstantTimeCompare]; the runtime delegates the comparison
+// here and does not enforce a constant-time posture on the caller's behalf.
type TokenAuthentication func(string) (any, error)
-// TokenAuthenticationCtx authentication function with [context.Context].
+// TokenAuthenticationCtx is the [context.Context]-aware variant of
+// [TokenAuthentication]. The same constant-time-comparison guidance
+// applies.
type TokenAuthenticationCtx func(context.Context, string) (context.Context, any, error)
-// ScopedTokenAuthentication authentication function.
+// ScopedTokenAuthentication validates a bearer/OAuth2 token along with the
+// scopes required for the operation.
+//
+// Implementations comparing the token against a known value MUST use
+// [crypto/subtle.ConstantTimeCompare]; the runtime delegates the comparison
+// here and does not enforce a constant-time posture on the caller's behalf.
type ScopedTokenAuthentication func(string, []string) (any, error)
-// ScopedTokenAuthenticationCtx authentication function with [context.Context].
+// ScopedTokenAuthenticationCtx is the [context.Context]-aware variant of
+// [ScopedTokenAuthentication]. The same constant-time-comparison guidance
+// applies.
type ScopedTokenAuthenticationCtx func(context.Context, string, []string) (context.Context, any, error)
var DefaultRealmName = "API"
@@ -199,7 +226,7 @@ func APIKeyAuthCtx(name, in string, authenticate TokenAuthenticationCtx) runtime
})
}
-// ScopedAuthRequest contains both a [http] request and the required scopes for a particular operation.
+// ScopedAuthRequest contains both the [http.Request] and the required scopes for a particular operation.
type ScopedAuthRequest struct {
Request *http.Request
RequiredScopes []string
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/LICENSE b/vendor/github.com/go-openapi/runtime/server-middleware/LICENSE
new file mode 100644
index 00000000000..d6456956733
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/docui/doc.go b/vendor/github.com/go-openapi/runtime/server-middleware/docui/doc.go
new file mode 100644
index 00000000000..809296d5c4f
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/docui/doc.go
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package docui provides standalone HTTP middlewares that serve OpenAPI
+// documentation UIs (Swagger UI, ReDoc, RapiDoc) and the spec document
+// itself.
+//
+// The package is stdlib-only and has no transitive dependency on any
+// OpenAPI spec, loading or validation library, so it may be imported by
+// any net/http application that simply wants to mount a documentation
+// site.
+package docui
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/docui/options.go b/vendor/github.com/go-openapi/runtime/server-middleware/docui/options.go
new file mode 100644
index 00000000000..c9e45f77946
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/docui/options.go
@@ -0,0 +1,253 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package docui
+
+import (
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+const (
+ // constants that are common to all UI-serving middlewares.
+ defaultDocsPath = "docs"
+ defaultDocsURL = "/swagger.json"
+ defaultDocsTitle = "API Documentation"
+
+ contentTypeHeader = "Content-Type"
+ applicationJSON = "application/json"
+)
+
+// UIMiddleware is a function returning a http middleware which accepts UI [Option].
+type UIMiddleware func(...Option) func(http.Handler) http.Handler
+
+// Option to tune your swagger documentation UI middleware.
+//
+// Options may be combined to alter the route at which the UI asset is served,
+// the URL of the spec document, the source URL of the UI asset and the title of the UI page.
+//
+// The embedded js scriptlet served may be modified using [WithUITemplate].
+type Option func(*options)
+
+// SpecOption can be applied to the [ServeSpec] middleware.
+type SpecOption func(*specOptions)
+
+// SwaggerUIOptions define a group of extra options specific to the SwaggerUI component.
+type SwaggerUIOptions struct {
+ // OAuth2CallbackURL sets the URL called after OAuth2 login
+ OAuth2CallbackURL string
+
+ // Defines the URL of the swagger UI assets with presets.
+ //
+ // Default: https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js
+ SwaggerPresetURL string
+
+ // Defines style sheet URL.
+ //
+ // Default: https://unpkg.com/swagger-ui-dist/swagger-ui.css
+ SwaggerStylesURL string
+
+ // Define the favicons URLs.
+ //
+ // Defaults:
+ //
+ // - 16x16: https://unpkg.com/swagger-ui-dist/favicon-16x16.png
+ // - 32x32: https://unpkg.com/swagger-ui-dist/favicon-32x32.png
+ Favicon32 string
+ Favicon16 string
+}
+
+func (o *SwaggerUIOptions) applySwaggerUIDefaults() {
+ if o.SwaggerPresetURL == "" {
+ o.SwaggerPresetURL = swaggerPresetLatest
+ }
+ if o.SwaggerStylesURL == "" {
+ o.SwaggerStylesURL = swaggerStylesLatest
+ }
+ if o.Favicon16 == "" || o.Favicon32 == "" {
+ o.Favicon16 = swaggerFavicon16Latest
+ o.Favicon32 = swaggerFavicon32Latest
+ }
+}
+
+type (
+ options struct {
+ SwaggerUIOptions
+
+ // BasePath for the UI, defaults to: /
+ BasePath string
+
+ // Path combines with BasePath to construct the path to the UI, defaults to: "docs".
+ Path string
+
+ // SpecURL is the URL of the spec document.
+ SpecURL string
+
+ // Title for the documentation site, default to: API documentation
+ Title string
+
+ // Template specifies a custom template to serve the UI
+ Template string
+
+ // AssetsURL points to the js asset that generates the documentation page.
+ AssetsURL string
+ }
+
+ specOptions struct {
+ Path string
+ Document string
+ }
+)
+
+////////////////////////////////////////////////////////////
+// Common UI options
+////////////////////////////////////////////////////////////
+
+// WithUIBasePath sets the base path from where to serve the UI assets.
+//
+// Default: "/"
+func WithUIBasePath(base string) Option {
+ return func(o *options) {
+ if !strings.HasPrefix(base, "/") {
+ base = "/" + base
+ }
+ o.BasePath = base
+ }
+}
+
+// WithUIPath sets the path from where to serve the UI assets (i.e. /{basepath}/{path}).
+//
+// Default: "docs"
+func WithUIPath(pth string) Option {
+ return func(o *options) {
+ o.Path = pth
+ }
+}
+
+// WithUITitle sets the title of the UI.
+//
+// Default: "API documentation"
+func WithUITitle(title string) Option {
+ return func(o *options) {
+ o.Title = title
+ }
+}
+
+// WithUIAssetsURL sets the URL from where to fetch the js assets.
+//
+// Defaults:
+//
+// - for Redoc: https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js
+// - for RapiDoc, this defaults to: https://unpkg.com/rapidoc/dist/rapidoc-min.js
+// - for SwaggerUI: https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js
+func WithUIAssetsURL(assets string) Option {
+ return func(o *options) {
+ o.AssetsURL = assets
+ }
+}
+
+// WithUITemplate allows to set a custom template for the UI.
+//
+// This allows the caller to fully customize the rendered UI, using the advanced options
+// provided by any UI.
+//
+// The UI [middleware] will panic if the template does not parse or execute properly.
+//
+// Reference documentations to customize your js scriptlet:
+//
+// - for Redoc: https://github.com/Redocly/redoc/blob/main/docs/deployment/html.md
+// - for RapiDoc: https://github.com/rapi-doc/RapiDoc
+// - for SwaggerUI: https://github.com/swagger-api/swagger-ui
+func WithUITemplate[StringOrBytes ~string | ~[]byte](tpl StringOrBytes) Option {
+ return func(o *options) {
+ o.Template = string(tpl)
+ }
+}
+
+// WithSpecURL sets the URL of the spec document.
+//
+// Defaults to: /swagger.json
+func WithSpecURL(u string) Option {
+ return func(o *options) {
+ o.SpecURL = u
+ }
+}
+
+////////////////////////////////////////////////////////////
+// SwaggerUI UI options
+////////////////////////////////////////////////////////////
+
+func WithSwaggerUIOptions(opts SwaggerUIOptions) Option {
+ return func(o *options) {
+ o.SwaggerUIOptions = opts
+ }
+}
+
+////////////////////////////////////////////////////////////
+// Spec options
+////////////////////////////////////////////////////////////
+
+// WithSpecPath sets the path of the spec document.
+//
+// This is "/swagger.json" by default.
+func WithSpecPath(pth string) SpecOption {
+ return func(o *specOptions) {
+ if pth == "" {
+ return
+ }
+
+ o.Path = pth
+ }
+}
+
+// WithSpecPathFromOptions reuses the same SpecPath as the one specified in
+// a set of UI [Option] (extract the path from the URL provided by [WithSpecURL]).
+func WithSpecPathFromOptions(opts ...Option) SpecOption {
+ return func(o *specOptions) {
+ uiOpts := optionsWithDefaults(opts)
+
+ // If the spec URL is provided, there is a non-default path to serve the spec.
+ //
+ // This makes sure that the UI middleware is aligned with the Spec middleware.
+ u, _ := url.Parse(uiOpts.SpecURL)
+
+ if u.Path == "" {
+ return
+ }
+
+ o.Path = u.Path
+ }
+}
+
+func optionsWithDefaults(opts []Option, prepend ...Option) options {
+ o := options{
+ BasePath: "/",
+ Path: defaultDocsPath,
+ SpecURL: defaultDocsURL,
+ Title: defaultDocsTitle,
+ }
+
+ prepend = append(prepend, opts...)
+ for _, apply := range prepend {
+ apply(&o)
+ }
+
+ return o
+}
+
+func specOptionsWithDefaults(opts []SpecOption) specOptions {
+ o := specOptions{
+ Path: defaultDocsURL,
+ }
+
+ for _, apply := range opts {
+ apply(&o)
+ }
+
+ if !strings.HasPrefix(o.Path, "/") {
+ o.Path = "/" + o.Path
+ }
+
+ return o
+}
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/docui/rapidoc.go b/vendor/github.com/go-openapi/runtime/server-middleware/docui/rapidoc.go
new file mode 100644
index 00000000000..c050331b4b0
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/docui/rapidoc.go
@@ -0,0 +1,67 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package docui
+
+import (
+ "bytes"
+ "fmt"
+ "html/template"
+ "net/http"
+ "path"
+)
+
+// UseRapiDoc creates a middleware to serve a documentation site for a swagger spec using [RapidDoc].
+//
+// [RapiDoc]: https://github.com/rapi-doc/RapiDoc
+func UseRapiDoc(opts ...Option) func(next http.Handler) http.Handler {
+ pth, assets := rapiDocSetup(opts)
+ return func(next http.Handler) http.Handler {
+ return serveUI(pth, assets, next)
+ }
+}
+
+// RapiDoc creates a [http.Handler] to serve a documentation site for a swagger spec using [RapidDoc].
+//
+// By default, the UI is served at route "/docs"
+//
+// This allows for altering the spec before starting the [http] listener.
+//
+// [RapiDoc]: https://github.com/rapi-doc/RapiDoc
+func RapiDoc(next http.Handler, opts ...Option) http.Handler {
+ pth, assets := rapiDocSetup(opts)
+
+ return serveUI(pth, assets, next)
+}
+
+func rapiDocSetup(opts []Option) (pth string, assets []byte) {
+ o := optionsWithDefaults(opts,
+ // defaults for rapiDoc
+ WithUITemplate(rapidocTemplate),
+ WithUIAssetsURL(rapidocLatest),
+ )
+ pth = path.Join(o.BasePath, o.Path)
+ tmpl := template.Must(template.New("rapidoc").Parse(o.Template))
+ buf := bytes.NewBuffer(nil)
+ if err := tmpl.Execute(buf, o); err != nil {
+ panic(fmt.Errorf("cannot execute template: %w", err))
+ }
+
+ return pth, buf.Bytes()
+}
+
+const (
+ rapidocLatest = "https://unpkg.com/rapidoc/dist/rapidoc-min.js"
+ rapidocTemplate = `
+
+
+ {{ .Title }}
+
+
+
+
+
+
+
+`
+)
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/docui/redoc.go b/vendor/github.com/go-openapi/runtime/server-middleware/docui/redoc.go
new file mode 100644
index 00000000000..31054a2476e
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/docui/redoc.go
@@ -0,0 +1,82 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package docui
+
+import (
+ "bytes"
+ "fmt"
+ "html/template"
+ "net/http"
+ "path"
+)
+
+// UseRedoc creates a middleware to serve a documentation site for a swagger spec using [Redoc].
+//
+// [Redoc]: https://redocly.com/docs/redoc
+func UseRedoc(opts ...Option) func(next http.Handler) http.Handler {
+ pth, assets := redocSetup(opts)
+
+ return func(next http.Handler) http.Handler {
+ return serveUI(pth, assets, next)
+ }
+}
+
+// Redoc creates a [http.Handler] to serve a documentation site for a swagger spec using [Redoc].
+//
+// By default, the UI is served at route "/docs"
+//
+// This allows for altering the spec before starting the [http] listener.
+//
+// [Redoc]: https://redocly.com/docs/redoc
+func Redoc(next http.Handler, opts ...Option) http.Handler {
+ pth, assets := redocSetup(opts)
+
+ return serveUI(pth, assets, next)
+}
+
+func redocSetup(opts []Option) (pth string, assets []byte) {
+ o := optionsWithDefaults(opts,
+ // defaults for redoc
+ WithUITemplate(redocTemplate),
+ WithUIAssetsURL(redocLatest),
+ )
+
+ pth = path.Join(o.BasePath, o.Path)
+ tmpl := template.Must(template.New("redoc").Parse(o.Template))
+ buf := bytes.NewBuffer(nil)
+ if err := tmpl.Execute(buf, o); err != nil {
+ panic(fmt.Errorf("cannot execute template: %w", err))
+ }
+
+ return pth, buf.Bytes()
+}
+
+const (
+ redocLatest = "https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js" // "https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js"
+ redocTemplate = `
+
+
+ {{ .Title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+`
+)
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/docui/render.go b/vendor/github.com/go-openapi/runtime/server-middleware/docui/render.go
new file mode 100644
index 00000000000..1fb744fd005
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/docui/render.go
@@ -0,0 +1,33 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package docui
+
+import (
+ "fmt"
+ "net/http"
+ "path"
+)
+
+// serveUI creates a [http.Handler] that serves a templated asset as text/html.
+func serveUI(pth string, assets []byte, next http.Handler) http.Handler {
+ return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+ if path.Clean(r.URL.Path) == pth {
+ rw.Header().Set(contentTypeHeader, "text/html; charset=utf-8")
+ rw.WriteHeader(http.StatusOK)
+ _, _ = rw.Write(assets)
+
+ return
+ }
+
+ if next != nil {
+ next.ServeHTTP(rw, r)
+
+ return
+ }
+
+ rw.Header().Set(contentTypeHeader, "text/plain")
+ rw.WriteHeader(http.StatusNotFound)
+ _, _ = fmt.Fprintf(rw, "%q not found", pth)
+ })
+}
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/docui/spec.go b/vendor/github.com/go-openapi/runtime/server-middleware/docui/spec.go
new file mode 100644
index 00000000000..59780199d5b
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/docui/spec.go
@@ -0,0 +1,50 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package docui
+
+import (
+ "net/http"
+ "path"
+)
+
+// UseSpec creates a middleware to serve a swagger spec as a JSON document.
+func UseSpec(spec []byte, opts ...SpecOption) func(next http.Handler) http.Handler {
+ o := specOptionsWithDefaults(opts)
+
+ return func(next http.Handler) http.Handler {
+ return handleSpec(o.Path, spec, next)
+ }
+}
+
+// ServeSpec creates a [http.Handler] to serve a swagger spec as a JSON document.
+//
+// This allows for altering the spec before starting the [http] listener.
+//
+// Additional [SpecOption] can be used to change the path and the name of the document (defaults to "/swagger.json").
+func ServeSpec(spec []byte, next http.Handler, opts ...SpecOption) http.Handler {
+ o := specOptionsWithDefaults(opts)
+
+ return handleSpec(o.Path, spec, next)
+}
+
+func handleSpec(pth string, spec []byte, next http.Handler) http.Handler {
+ return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+ if path.Clean(r.URL.Path) == pth {
+ rw.Header().Set(contentTypeHeader, applicationJSON)
+ rw.WriteHeader(http.StatusOK)
+ _, _ = rw.Write(spec)
+
+ return
+ }
+
+ if next != nil {
+ next.ServeHTTP(rw, r)
+
+ return
+ }
+
+ rw.Header().Set(contentTypeHeader, applicationJSON)
+ rw.WriteHeader(http.StatusNotFound)
+ })
+}
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/docui/swaggerui.go b/vendor/github.com/go-openapi/runtime/server-middleware/docui/swaggerui.go
new file mode 100644
index 00000000000..db0aa05e6ab
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/docui/swaggerui.go
@@ -0,0 +1,138 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package docui
+
+import (
+ "bytes"
+ "fmt"
+ "html/template"
+ "net/http"
+ "path"
+)
+
+// UseSwaggerUI creates a middleware to serve a documentation site for a swagger spec using [SwaggerUI].
+//
+// [SwaggerUI]: https://swagger.io/tools/swagger-ui
+func UseSwaggerUI(opts ...Option) func(next http.Handler) http.Handler {
+ pth, assets := swaggeruiSetup(opts)
+
+ return func(next http.Handler) http.Handler {
+ return serveUI(pth, assets, next)
+ }
+}
+
+// SwaggerUI creates a [http.Handler] to serve a documentation site for a swagger spec using [SwaggerUI].
+//
+// By default, the UI is served at route "/docs"
+//
+// This allows for altering the spec before starting the [http] listener.
+//
+// [SwaggerUI]: https://swagger.io/tools/swagger-ui
+func SwaggerUI(next http.Handler, opts ...Option) http.Handler {
+ pth, assets := swaggeruiSetup(opts)
+
+ return serveUI(pth, assets, next)
+}
+
+func swaggeruiSetup(opts []Option) (pth string, assets []byte) {
+ o := optionsWithDefaults(opts,
+ // defaults for SwaggerUI
+ WithUITemplate(swaggeruiTemplate),
+ WithUIAssetsURL(swaggerLatest),
+ )
+ o.applySwaggerUIDefaults()
+ if o.OAuth2CallbackURL == "" {
+ o.OAuth2CallbackURL = path.Join(o.BasePath, o.Path, "oauth2-callback")
+ }
+
+ pth = path.Join(o.BasePath, o.Path)
+ tmpl := template.Must(template.New("swaggerui").Parse(o.Template))
+ buf := bytes.NewBuffer(nil)
+ if err := tmpl.Execute(buf, o); err != nil {
+ panic(fmt.Errorf("cannot execute template: %w", err))
+ }
+
+ return pth, buf.Bytes()
+}
+
+const (
+ swaggerLatest = "https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"
+ swaggerPresetLatest = "https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js"
+ swaggerStylesLatest = "https://unpkg.com/swagger-ui-dist/swagger-ui.css"
+ swaggerFavicon32Latest = "https://unpkg.com/swagger-ui-dist/favicon-32x32.png"
+ swaggerFavicon16Latest = "https://unpkg.com/swagger-ui-dist/favicon-16x16.png"
+ swaggeruiTemplate = `
+
+
+
+
+ {{ .Title }}
+
+ {{- if .SwaggerStylesURL }}
+
+ {{- end }}
+ {{- if .Favicon32 }}
+
+ {{- end }}
+ {{- if .Favicon16 }}
+
+ {{- end }}
+
+
+
+
+
+
+
+ {{- if .SwaggerPresetURL }}
+
+ {{- end }}
+
+
+
+`
+)
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/docui/swaggerui_oauth2.go b/vendor/github.com/go-openapi/runtime/server-middleware/docui/swaggerui_oauth2.go
new file mode 100644
index 00000000000..a38e408f153
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/docui/swaggerui_oauth2.go
@@ -0,0 +1,133 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package docui
+
+import (
+ "bytes"
+ "fmt"
+ "net/http"
+ "path"
+ "text/template"
+)
+
+// UseSwaggerUIOAuth2Callback creates a middleware that serves a callback URL to complete
+// a OAuth2 token handshake.
+func UseSwaggerUIOAuth2Callback(opts ...Option) func(next http.Handler) http.Handler {
+ pth, assets := swaggeruiOAuth2Setup(opts)
+
+ return func(next http.Handler) http.Handler {
+ return serveUI(pth, assets, next)
+ }
+}
+
+// SwaggerUIOAuth2Callback creates a [http.Handler] that serves a callback URL to complete
+// a OAuth2 token handshake.
+func SwaggerUIOAuth2Callback(next http.Handler, opts ...Option) http.Handler {
+ pth, assets := swaggeruiOAuth2Setup(opts)
+
+ return serveUI(pth, assets, next)
+}
+
+func swaggeruiOAuth2Setup(opts []Option) (pth string, assets []byte) {
+ o := optionsWithDefaults(opts,
+ // defaults for SwaggerUI OAuth2 callback endpoint
+ WithUITemplate(swaggerOAuth2Template),
+ WithUIAssetsURL(swaggerLatest),
+ )
+ o.applySwaggerUIDefaults()
+ if o.OAuth2CallbackURL == "" {
+ o.OAuth2CallbackURL = path.Join(o.BasePath, o.Path, "oauth2-callback")
+ }
+
+ pth = o.OAuth2CallbackURL
+ tmpl := template.Must(template.New("swaggeroauth2").Parse(o.Template))
+ buf := bytes.NewBuffer(nil)
+ if err := tmpl.Execute(buf, o); err != nil {
+ panic(fmt.Errorf("cannot execute template: %w", err))
+ }
+
+ return pth, buf.Bytes()
+}
+
+const swaggerOAuth2Template = `
+
+
+
+ {{ .Title }}
+
+
+
+
+
+`
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/doc.go b/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/doc.go
new file mode 100644
index 00000000000..6f8aa313523
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/doc.go
@@ -0,0 +1,30 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package mediatype provides a typed value for media types
+// defined by RFC 7231 and RFC 2045.
+//
+// The matching/selection primitives used by both server-side
+// validation and Accept-header negotiation.
+//
+// The package is stdlib-only.
+//
+// # The matching rule
+//
+// [MediaType.Matches] is asymmetric. The receiver acts as the "bound"
+// (an allowed entry on the server side, or a candidate offer when
+// matching against an Accept entry); the argument is the constraint
+// (the actual incoming request, or the Accept entry being satisfied).
+//
+// - bare type/subtype must agree, with wildcard handling on either
+// side ("*/*" matches anything; "type/*" matches any subtype);
+// - if the receiver carries no parameters, any constraint is
+// accepted regardless of its parameters;
+// - otherwise every (key,value) pair on the constraint must be
+// present on the receiver, with case-insensitive value
+// comparison. The receiver may carry additional parameters the
+// constraint does not list.
+//
+// q-values are NOT considered by [MediaType.Matches] — they are the
+// negotiator's concern, handled inside [Set.BestMatch].
+package mediatype
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/lookup.go b/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/lookup.go
new file mode 100644
index 00000000000..598b60aca35
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/lookup.go
@@ -0,0 +1,116 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package mediatype
+
+// Lookup finds the entry in m matching mediaType, with alias-aware
+// fallback. It is the canonical seam for codec-map lookups in both
+// the client and server runtimes — placing the fallback policy here
+// keeps alias definitions (and any future lookup tolerances) in one
+// place.
+//
+// Lookup tries the following, in order, returning the first hit:
+//
+// 1. mediaType verbatim (fast path for callers that already pass a
+// canonical, parameter-free string and store map keys in the
+// same form).
+// 2. An alias-aware walk against the parsed "type/subtype" form:
+// a direct map hit on the parsed key, on its alias canonical
+// if any, and finally an O(len(m)) scan returning any map
+// entry whose key alias-canonicalizes to the same target.
+// Catches both "map keyed by canonical, query uses alias" and
+// "map keyed by one alias, query uses another alias of the
+// same canonical".
+// 3. When [AllowSuffix] is passed in opts: the same alias-aware
+// walk against the RFC 6839 structured-syntax suffix base.
+// Catches the "spec/traffic divergence" case (request for
+// application/vnd.api+json finds a JSON consumer registered
+// under application/json). Query-side suffix fold only — no
+// map-side suffix folding.
+//
+// Lookup does NOT fall back to "*/*". Callers that want wildcard
+// behavior (the historical resolveConsumer pattern in the client
+// runtime) chain that themselves after a Lookup miss — keeping
+// wildcard semantics explicit at each call site.
+//
+// Map keys are expected in canonical "type/subtype" form (no
+// parameters). The runtime's default Consumers / Producers maps
+// follow this convention.
+//
+// Returns (zero, false) when:
+//
+// - m is empty;
+// - mediaType fails to parse and is not present verbatim;
+// - none of the active steps hits.
+//
+// The malformed-vs-not-found distinction is intentionally elided:
+// codec-lookup callers treat both as the same "no codec" error path.
+func Lookup[T any](m map[string]T, mediaType string, opts ...MatchOption) (T, bool) {
+ var zero T
+ if len(m) == 0 {
+ return zero, false
+ }
+ o := applyMatchOptions(opts)
+ // Fast path: raw key (preserves any caller behaviour that stored
+ // non-canonical strings as map keys, and skips parsing in the
+ // common already-canonical case).
+ if v, ok := m[mediaType]; ok {
+ return v, true
+ }
+ mt, err := Parse(mediaType)
+ if err != nil {
+ return zero, false
+ }
+ key := mt.Type + "/" + mt.Subtype
+ if v, ok := findByCanonical(m, key); ok {
+ return v, true
+ }
+ if o.allowSuffix && mt.Suffix != "" {
+ base := mt.Base()
+ if baseKey := base.Type + "/" + base.Subtype; baseKey != key {
+ if v, ok := findByCanonical(m, baseKey); ok {
+ return v, true
+ }
+ }
+ }
+ return zero, false
+}
+
+// findByCanonical returns the first entry in m whose key
+// alias-canonicalizes to the same value as target.
+//
+// Tries direct hits before the O(len(m)) walk:
+//
+// 1. m[target] — map keyed by the same string.
+// 2. m[aliases[target]] — map keyed by the canonical when target
+// is an alias.
+// 3. Walk m: return any entry where canonical(k) == canonical(target).
+// Catches the "map keyed by an alias different from the query
+// side" case (e.g. registered under text/yaml, queried as
+// application/x-yaml — both canonicalize to application/yaml).
+//
+// Map size is single-digit for the runtime's codec maps, so the
+// walk is negligible.
+func findByCanonical[T any](m map[string]T, target string) (T, bool) {
+ if v, ok := m[target]; ok {
+ return v, true
+ }
+ canonTarget := target
+ if canon, ok := aliases[target]; ok {
+ canonTarget = canon
+ if v, ok := m[canonTarget]; ok {
+ return v, true
+ }
+ }
+ for k, v := range m {
+ kCanon := k
+ if c, ok := aliases[k]; ok {
+ kCanon = c
+ }
+ if kCanon == canonTarget {
+ return v, true
+ }
+ }
+ var zero T
+ return zero, false
+}
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/match.go b/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/match.go
new file mode 100644
index 00000000000..6a16d0b6f2e
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/match.go
@@ -0,0 +1,65 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package mediatype
+
+// MatchFirst reports whether actual matches any entry in allowed,
+// using [MediaType.Match] — the param-aware RFC 7231 rule plus the
+// alias bridge from the package-internal alias table.
+//
+// The scan is multi-pass and tier-ordered: the first pass returns
+// the first allowed entry that matches under [MatchExact] (RFC 7231
+// semantics); the second pass looks for a [MatchAlias] match; when
+// [AllowSuffix] is in opts a third pass looks for a [MatchSuffix]
+// match. This preserves the "stronger tier wins" ordering from
+// [Set.BestMatch] while keeping the "first match wins" semantics
+// within each tier.
+//
+// Return values:
+//
+// - (matched, true, nil) — the first allowed entry that
+// matches, with exact matches preferred over alias matches.
+// - (zero, false, nil) — actual is well-formed but no
+// allowed entry accepts it. Maps to an HTTP 415 outcome.
+// - (zero, false, err) — actual fails to parse. err
+// wraps [ErrMalformed], so callers can use [errors.Is] to
+// distinguish this case. Maps to an HTTP 400 outcome.
+//
+// Allowed entries that themselves fail to parse are skipped (they
+// cannot match any well-formed actual), and no error is surfaced
+// for them.
+//
+// An empty allowed list returns (zero, false, nil). MatchFirst is
+// the primitive; callers decide what no-constraints means in their
+// context.
+func MatchFirst(allowed []string, actual string, opts ...MatchOption) (MediaType, bool, error) {
+ if len(allowed) == 0 {
+ return MediaType{}, false, nil
+ }
+ actualMT, err := Parse(actual)
+ if err != nil {
+ return MediaType{}, false, err
+ }
+ o := applyMatchOptions(opts)
+ // Tier-ordered passes over the allowed list. The list is
+ // typically short (an operation's Consumes set), so re-parsing
+ // each entry on every pass is cheaper than caching parses across
+ // passes.
+ tiers := []MatchKind{MatchExact, MatchAlias}
+ if o.allowSuffix {
+ tiers = append(tiers, MatchSuffix)
+ }
+ for _, want := range tiers {
+ for _, a := range allowed {
+ allowedMT, perr := Parse(a)
+ if perr != nil {
+ continue
+ }
+ if allowedMT.Match(actualMT) == want {
+ return allowedMT, true, nil
+ }
+ }
+ }
+
+ return MediaType{}, false, nil
+}
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/mediatype.go b/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/mediatype.go
new file mode 100644
index 00000000000..41a32a160a8
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/mediatype.go
@@ -0,0 +1,392 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package mediatype
+
+import (
+ "fmt"
+ "mime"
+ "strconv"
+ "strings"
+)
+
+const wildcard = "*"
+
+// Internal constants for the suffixBase table and any future
+// in-package references to the well-known base media types.
+const (
+ typeApplication = "application"
+ subtypeJSON = "json"
+ subtypeXML = "xml"
+ subtypeYAML = "yaml"
+
+ mtYAML = typeApplication + "/" + subtypeYAML
+)
+
+// Specificity scores returned by [MediaType.Specificity], ordered from
+// least to most specific.
+const (
+ SpecificityAny = iota // "*/*"
+ SpecificityType // "type/*"
+ SpecificityExact // "type/subtype" (no params)
+ SpecificityExactWithParams // "type/subtype;k=v"
+)
+
+// MatchKind classifies the strength of a match between two media
+// types. Larger values represent stronger matches and win in
+// negotiation tie-breaks.
+//
+// MatchExact covers direct subtype or wildcard agreement under RFC
+// 7231 rules; MatchAlias is returned when the strict comparison
+// fails but the two values agree after canonicalization through the
+// internal alias table (see [MediaType.Canonical]); MatchSuffix is
+// returned only when both alias and exact comparisons fail but the
+// two values agree after folding the RFC 6839 structured-syntax
+// suffix (see [MediaType.Base]).
+//
+// MatchSuffix matches are off by default at the negotiation /
+// lookup callers — they count only when [AllowSuffix] is passed to
+// [Set.BestMatch], [MatchFirst], or [Lookup]. The opt-in is the
+// single user-visible knob; [MediaType.Match] itself always returns
+// the strongest tier that succeeds.
+type MatchKind int
+
+// MatchKind values. Returned by [MediaType.Match].
+const (
+ MatchNone MatchKind = iota // no match
+ MatchSuffix // matched via the RFC 6839 suffix base
+ MatchAlias // matched via the alias table
+ MatchExact // matched directly (RFC 7231 semantics)
+)
+
+// MatchOption configures the matching tolerances used by
+// [Set.BestMatch], [MatchFirst], and [Lookup]. The zero behaviour
+// is strict: only [MatchAlias] and [MatchExact] count.
+type MatchOption func(*matchOptions)
+
+type matchOptions struct {
+ allowSuffix bool
+}
+
+func applyMatchOptions(opts []MatchOption) matchOptions {
+ var o matchOptions
+ for _, opt := range opts {
+ opt(&o)
+ }
+ return o
+}
+
+// AllowSuffix returns a [MatchOption] that lets the caller count
+// [MatchSuffix] results as valid matches. Use this to opt into
+// RFC 6839 structured-syntax suffix tolerance for situations where
+// the client/server traffic does not strictly abide by the spec
+// (typical example: server returning application/problem+json
+// against operations that only declare application/json in
+// produces).
+func AllowSuffix() MatchOption {
+ return func(o *matchOptions) {
+ o.allowSuffix = true
+ }
+}
+
+type mediaTypeError string
+
+func (e mediaTypeError) Error() string {
+ return string(e)
+}
+
+// ErrMalformed is the sentinel returned (wrapped) by [Parse] when its input
+// cannot be parsed as an RFC 7231 media type.
+//
+// Callers can test for it with [errors.Is] to distinguish a client-side
+// malformed Content-Type header (an HTTP 400 outcome) from a well-formed
+// value that simply matches no allowed entry (an HTTP 415 outcome).
+const ErrMalformed mediaTypeError = "mediatype: malformed"
+
+// MediaType is a parsed RFC 7231 media type with optional parameters and
+// an optional q-value (used by Accept negotiation).
+//
+// Type, Subtype and the keys of Params are lowercased. Parameter values
+// are preserved verbatim; comparisons are case-insensitive (matching the
+// pre-v0.30 behaviour and the common convention for charset, version, etc.).
+//
+// Suffix exposes the RFC 6839 structured syntax suffix (the token after
+// the final '+' in Subtype) as a parallel hint. Subtype itself retains
+// the full wire value, so existing callers comparing Subtype against a
+// string see no change.
+type MediaType struct {
+ Type string
+ Subtype string
+ Suffix string
+ Params map[string]string
+ Q float64
+}
+
+// suffixBase maps a known RFC 6839 / RFC 9512 structured syntax
+// suffix (without the leading '+', lowercased) to its base media
+// type. It is the authoritative table consulted by [MediaType.Base].
+//
+// The table is intentionally small: only suffixes whose base type
+// has a codec in the default runtime maps are listed. CBOR, zip,
+// BER, DER, FastInfoset and WBXML are registered by IANA but have
+// no default codec in this runtime; adding them is gated on having
+// something to do with them.
+//
+// Package-internal by design: the external API is [MediaType.Base].
+// If users ever need to extend the table, a Register-style function
+// is the right answer, not an exported mutable map.
+var suffixBase = map[string]MediaType{
+ subtypeJSON: {Type: typeApplication, Subtype: subtypeJSON},
+ subtypeXML: {Type: typeApplication, Subtype: subtypeXML},
+ subtypeYAML: {Type: typeApplication, Subtype: subtypeYAML},
+}
+
+// aliases maps a deprecated or legacy media-type name to its
+// canonical registered equivalent. Keys are the lowercased
+// "type/subtype" form with no parameters; values are the canonical
+// "type/subtype" form, also without parameters.
+//
+// Entries are limited to media types whose authoritative RFC
+// explicitly names the alias. The seed entries cite RFC 9512 §2.1,
+// which enumerates "Deprecated alias names for this type:
+// application/x-yaml, text/yaml, and text/x-yaml" as part of the
+// IANA registration template for application/yaml.
+//
+// Pull requests adding entries need an analogous citation in the
+// commit message; entries without authoritative backing belong in
+// caller-side canonicalization, not here.
+//
+// Package-internal by design: the external API is
+// [MediaType.Canonical] and [MediaType.Match]. If users ever need
+// to register their own aliases, a Register-style function is the
+// right answer, not an exported mutable map.
+var aliases = map[string]string{
+ "application/x-yaml": mtYAML, // RFC 9512 §2.1
+ "text/yaml": mtYAML, // RFC 9512 §2.1
+ "text/x-yaml": mtYAML, // RFC 9512 §2.1
+}
+
+// Parse parses a single media type. The input may carry parameters and a
+// q-value; the q-value is extracted into [MediaType.Q] and removed from
+// [MediaType.Params].
+//
+// An empty input returns an error.
+func Parse(s string) (MediaType, error) {
+ s = strings.TrimSpace(s)
+ if s == "" {
+ return MediaType{}, fmt.Errorf("%w: empty value", ErrMalformed)
+ }
+ full, params, err := mime.ParseMediaType(s)
+ if err != nil {
+ return MediaType{}, fmt.Errorf("%w: %w", ErrMalformed, err)
+ }
+ slash := strings.IndexByte(full, '/')
+ if slash <= 0 || slash == len(full)-1 {
+ return MediaType{}, fmt.Errorf("%w: %q has no subtype", ErrMalformed, s)
+ }
+ mt := MediaType{
+ Type: full[:slash],
+ Subtype: full[slash+1:],
+ Q: 1.0,
+ }
+ // RFC 6839: structured syntax suffix is the trailing '+'-delimited
+ // token of the subtype. Only the last '+' counts ("foo+bar+json" →
+ // suffix "json"). A trailing '+' with nothing after it is not a
+ // valid suffix and is ignored. mime.ParseMediaType has already
+ // lowercased the subtype, so no further ToLower is needed.
+ if plus := strings.LastIndexByte(mt.Subtype, '+'); plus >= 0 && plus < len(mt.Subtype)-1 {
+ mt.Suffix = mt.Subtype[plus+1:]
+ }
+
+ if q, ok := params["q"]; ok {
+ if qf, isFloat := boundedQ(q); isFloat {
+ mt.Q = qf
+ }
+ delete(params, "q")
+ }
+
+ if len(params) > 0 {
+ mt.Params = params
+ }
+
+ return mt, nil
+}
+
+// String renders the canonical "type/subtype;k=v;k=v" form. Parameters are
+// emitted in lexicographic key order (the standard library guarantees this)
+// so the result is stable. The q-value is NOT emitted — it is meta, not
+// part of the media type identity.
+func (m MediaType) String() string {
+ if m.Type == "" && m.Subtype == "" {
+ return ""
+ }
+
+ return mime.FormatMediaType(m.Type+"/"+m.Subtype, m.Params)
+}
+
+// Matches reports whether the receiver accepts other, per the package
+// documentation: the receiver is the bound, other is the constraint.
+func (m MediaType) Matches(other MediaType) bool {
+ if !typeAgrees(m.Type, other.Type) {
+ return false
+ }
+ if !subtypeAgrees(m.Type, m.Subtype, other.Type, other.Subtype) {
+ return false
+ }
+ if len(m.Params) == 0 {
+ return true
+ }
+ for k, v := range other.Params {
+ sv, ok := m.Params[k]
+ if !ok || !strings.EqualFold(sv, v) {
+ return false
+ }
+ }
+
+ return true
+}
+
+// Specificity returns a numeric score for ordering matches. Higher is more
+// specific. The returned value is one of [SpecificityAny],
+// [SpecificityType], [SpecificityExact] or [SpecificityExactWithParams].
+func (m MediaType) Specificity() int {
+ if m.Type == wildcard && m.Subtype == wildcard {
+ return SpecificityAny
+ }
+ if m.Subtype == wildcard {
+ return SpecificityType
+ }
+ if len(m.Params) == 0 {
+ return SpecificityExact
+ }
+
+ return SpecificityExactWithParams
+}
+
+func boundedQ(q string) (float64, bool) {
+ qf, err := strconv.ParseFloat(q, 64)
+ if err != nil {
+ return 0, false
+ }
+
+ if qf < 0 {
+ qf = 0
+ }
+
+ if qf > 1 {
+ qf = 1
+ }
+
+ return qf, true
+}
+
+// typeAgrees reports whether two top-level types match, allowing "*" on
+// either side. A type of "*" without a "*" subtype is rejected per RFC
+// 7231 §5.3.2 ("*/sub" is not valid), but Parse never produces such a
+// shape — it goes through mime.ParseMediaType.
+func typeAgrees(a, b string) bool {
+ return a == wildcard || b == wildcard || a == b
+}
+
+// subtypeAgrees handles the "type/*" wildcard: the bare type must match
+// (a "*/*" pair has already been accepted by typeAgrees above).
+func subtypeAgrees(at, asub, bt, bsub string) bool {
+ if at == wildcard || bt == wildcard {
+ // at least one side is "*/*" or "*/sub". With typeAgrees having
+ // returned true, we accept.
+ return true
+ }
+ if asub == wildcard || bsub == wildcard {
+ return true
+ }
+
+ return asub == bsub
+}
+
+// StripParams returns a copy of m with no parameters. Q is preserved
+// because it drives negotiation ordering, not media-type identity.
+//
+// Useful for the legacy "ignore parameters" negotiation mode.
+func (m MediaType) StripParams() MediaType {
+ return MediaType{Type: m.Type, Subtype: m.Subtype, Suffix: m.Suffix, Q: m.Q}
+}
+
+// Base returns the base media type implied by the RFC 6839 structured
+// syntax suffix, or m unchanged when:
+//
+// - Suffix is empty;
+// - Suffix is not present in the package-internal suffix→base table.
+//
+// The returned value represents the structural base only: it carries
+// no parameters and no q-value. Use it to find a codec for the
+// underlying wire format — for example, "application/vnd.api+json"
+// resolves to "application/json".
+//
+// Base does not mutate the receiver.
+func (m MediaType) Base() MediaType {
+ if m.Suffix == "" {
+ return m
+ }
+ base, ok := suffixBase[m.Suffix]
+ if !ok {
+ return m
+ }
+ return base
+}
+
+// Canonical returns m rewritten to its canonical media type via
+// the package-internal alias table, or m unchanged when
+// (Type, Subtype) is not a known alias. Params and Q are preserved on the returned value; Suffix
+// is recomputed from the canonical Subtype (none of the current
+// entries carry a suffix, but the contract is forward-safe).
+//
+// Canonical does not mutate the receiver.
+func (m MediaType) Canonical() MediaType {
+ key := m.Type + "/" + m.Subtype
+ canon, ok := aliases[key]
+ if !ok {
+ return m
+ }
+ slash := strings.IndexByte(canon, '/')
+ out := m
+ out.Type = canon[:slash]
+ out.Subtype = canon[slash+1:]
+ out.Suffix = ""
+ if plus := strings.LastIndexByte(out.Subtype, '+'); plus >= 0 && plus < len(out.Subtype)-1 {
+ out.Suffix = out.Subtype[plus+1:]
+ }
+ return out
+}
+
+// Match reports how m matches other, classifying the result by
+// [MatchKind]. Used by negotiation to rank candidate offers:
+// stronger tiers win when both apply.
+//
+// Returns, strongest first:
+//
+// - MatchExact when m.Matches(other) is true under the strict
+// RFC 7231 rules (including wildcards and the param subset
+// rule).
+// - MatchAlias when m.Canonical().Matches(other.Canonical())
+// is true but the strict comparison failed.
+// - MatchSuffix when m.Base().Canonical().Matches(
+// other.Base().Canonical()) is true but the alias comparison
+// failed (RFC 6839 structured-syntax suffix fold).
+// - MatchNone otherwise.
+//
+// The asymmetric "bound vs constraint" rule of [MediaType.Matches]
+// is preserved at every tier. Match itself is always lenient — the
+// opt-in to count MatchSuffix lives one level up at [Set.BestMatch],
+// [MatchFirst], and [Lookup] via [AllowSuffix].
+func (m MediaType) Match(other MediaType) MatchKind {
+ if m.Matches(other) {
+ return MatchExact
+ }
+ if m.Canonical().Matches(other.Canonical()) {
+ return MatchAlias
+ }
+ if m.Base().Canonical().Matches(other.Base().Canonical()) {
+ return MatchSuffix
+ }
+ return MatchNone
+}
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/set.go b/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/set.go
new file mode 100644
index 00000000000..70f62a18d41
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/set.go
@@ -0,0 +1,138 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package mediatype
+
+import (
+ "strings"
+)
+
+// Set is a list of media types — typically the parsed value of an Accept
+// header, or a list of server-side offers.
+type Set []MediaType
+
+// ParseAccept parses a comma-separated list of media types, as found in
+// the Accept, Accept-Charset (etc.) HTTP headers. Malformed entries are
+// skipped silently — be liberal in what you accept.
+//
+// An empty input returns nil.
+func ParseAccept(s string) Set {
+ parts := splitTopLevel(s)
+ if len(parts) == 0 {
+ return nil
+ }
+ out := make(Set, 0, len(parts))
+ for _, p := range parts {
+ mt, err := Parse(p)
+ if err != nil {
+ continue
+ }
+ out = append(out, mt)
+ }
+
+ return out
+}
+
+// BestMatch picks the offer most acceptable to the receiver's Accept
+// entries. Selection follows RFC 7231 §5.3.2 plus tier-aware
+// ranking:
+//
+// - highest q-value wins;
+// - ties on q broken by the highest [MediaType.Specificity] of the
+// matching Accept entry;
+// - ties on specificity broken by [MatchKind] (MatchExact beats
+// MatchAlias beats MatchSuffix);
+// - ties on match kind broken by earliest position in offered.
+//
+// Accept entries with q=0 are treated as exclusions and never match.
+// MatchSuffix results are only counted when [AllowSuffix] is passed.
+// Returns ok=false if no offer matched any non-zero-q entry.
+func (s Set) BestMatch(offered Set, opts ...MatchOption) (best MediaType, ok bool) {
+ if len(s) == 0 || len(offered) == 0 {
+ return MediaType{}, false
+ }
+ o := applyMatchOptions(opts)
+ bestQ := -1.0
+ bestSpec := -1
+ bestKind := MatchNone
+ bestIdx := -1
+ for i, offer := range offered {
+ for _, entry := range s {
+ if entry.Q == 0 {
+ continue
+ }
+ kind := offer.Match(entry)
+ if kind == MatchNone {
+ continue
+ }
+ if kind == MatchSuffix && !o.allowSuffix {
+ continue
+ }
+ spec := entry.Specificity()
+ switch {
+ case entry.Q > bestQ:
+ best, ok = offer, true
+ bestQ = entry.Q
+ bestSpec = spec
+ bestKind = kind
+ bestIdx = i
+ case entry.Q < bestQ:
+ // not better
+ case spec > bestSpec:
+ best, ok = offer, true
+ bestSpec = spec
+ bestKind = kind
+ bestIdx = i
+ case spec < bestSpec:
+ // not better
+ case kind > bestKind:
+ best, ok = offer, true
+ bestKind = kind
+ bestIdx = i
+ case kind < bestKind:
+ // not better
+ case bestIdx < 0 || i < bestIdx:
+ best, ok = offer, true
+ bestIdx = i
+ }
+ }
+ }
+
+ return best, ok
+}
+
+// splitTopLevel splits s on top-level commas, respecting double-quoted
+// strings (RFC 7230 §3.2.6 — quoted-string).
+func splitTopLevel(s string) []string {
+ if strings.IndexByte(s, ',') < 0 {
+ if t := strings.TrimSpace(s); t != "" {
+ return []string{t}
+ }
+ return nil
+ }
+ var out []string
+ start := 0
+ inQuote := false
+ escape := false
+ for i := range len(s) {
+ c := s[i]
+ switch {
+ case escape:
+ escape = false
+ case inQuote && c == '\\':
+ escape = true
+ case c == '"':
+ inQuote = !inQuote
+ case c == ',' && !inQuote:
+ if t := strings.TrimSpace(s[start:i]); t != "" {
+ out = append(out, t)
+ }
+ start = i + 1
+ }
+ }
+ if t := strings.TrimSpace(s[start:]); t != "" {
+ out = append(out, t)
+ }
+
+ return out
+}
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/doc.go b/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/doc.go
new file mode 100644
index 00000000000..a9f278c31b1
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/doc.go
@@ -0,0 +1,13 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package negotiate provides server-side HTTP content negotiation
+// helpers — selecting the response Content-Type from an Accept header
+// and the response Content-Encoding from an Accept-Encoding header.
+//
+// The package is stdlib-only (modulo the typed [mediatype.MediaType]
+// values it consumes).
+//
+// The exported [ContentType] honours MIME-type parameters by default;
+// use [WithIgnoreParameters] to restore the pre-v0.30 looser match.
+package negotiate
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/header/header.go b/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/header/header.go
new file mode 100644
index 00000000000..6f3c3f00382
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/header/header.go
@@ -0,0 +1,345 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Copyright 2013 The Go Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd.
+
+// this file was taken from the github.com/golang/gddo repository
+
+// Package header provides functions for parsing HTTP headers.
+package header
+
+import (
+ "maps"
+ "net/http"
+ "strings"
+ "time"
+)
+
+// Octet types from RFC 2616.
+var octetTypes [256]octetType
+
+type octetType byte
+
+const (
+ isToken octetType = 1 << iota
+ isSpace
+)
+
+const (
+ asciiMaxControlChar = 31
+ asciiMaxChar = 127
+)
+
+func init() {
+ // OCTET =
+ // CHAR =
+ // CTL =
+ // CR =
+ // LF =
+ // SP =
+ // HT =
+ // <"> =
+ // CRLF = CR LF
+ // LWS = [CRLF] 1*( SP | HT )
+ // TEXT =
+ // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
+ // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
+ // token = 1*
+ // qdtext = >
+
+ for c := range 256 {
+ var t octetType
+ isCtl := c <= asciiMaxControlChar || c == asciiMaxChar
+ isChar := 0 <= c && c <= asciiMaxChar
+ isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
+ if strings.ContainsRune(" \t\r\n", rune(c)) {
+ t |= isSpace
+ }
+ if isChar && !isCtl && !isSeparator {
+ t |= isToken
+ }
+ octetTypes[c] = t
+ }
+}
+
+// Copy returns a shallow copy of the header.
+func Copy(header http.Header) http.Header {
+ h := make(http.Header)
+ maps.Copy(h, header)
+ return h
+}
+
+var timeLayouts = []string{"Mon, 02 Jan 2006 15:04:05 GMT", time.RFC850, time.ANSIC}
+
+// ParseTime parses the header as time. The zero value is returned if the
+// header is not present or there is an error parsing the
+// header.
+func ParseTime(header http.Header, key string) time.Time {
+ if s := header.Get(key); s != "" {
+ for _, layout := range timeLayouts {
+ if t, err := time.Parse(layout, s); err == nil {
+ return t.UTC()
+ }
+ }
+ }
+ return time.Time{}
+}
+
+// ParseList parses a comma separated list of values. Commas are ignored in
+// quoted strings. Quoted values are not unescaped or unquoted. Whitespace is
+// trimmed.
+func ParseList(header http.Header, key string) []string {
+ var result []string
+ for _, s := range header[http.CanonicalHeaderKey(key)] {
+ begin := 0
+ end := 0
+ escape := false
+ quote := false
+ for i := range len(s) {
+ b := s[i]
+ switch {
+ case escape:
+ escape = false
+ end = i + 1
+ case quote:
+ switch b {
+ case '\\':
+ escape = true
+ case '"':
+ quote = false
+ }
+ end = i + 1
+ case b == '"':
+ quote = true
+ end = i + 1
+ case octetTypes[b]&isSpace != 0:
+ if begin == end {
+ begin = i + 1
+ end = begin
+ }
+ case b == ',':
+ if begin < end {
+ result = append(result, s[begin:end])
+ }
+ begin = i + 1
+ end = begin
+ default:
+ end = i + 1
+ }
+ }
+ if begin < end {
+ result = append(result, s[begin:end])
+ }
+ }
+ return result
+}
+
+// ParseValueAndParams parses a comma separated list of values with optional
+// semicolon separated name-value pairs. Content-Type and Content-Disposition
+// headers are in this format.
+func ParseValueAndParams(header http.Header, key string) (string, map[string]string) {
+ return parseValueAndParams(header.Get(key))
+}
+
+func parseValueAndParams(s string) (value string, params map[string]string) {
+ params = make(map[string]string)
+ value, s = expectTokenSlash(s)
+ if value == "" {
+ return
+ }
+ value = strings.ToLower(value)
+ s = skipSpace(s)
+ for strings.HasPrefix(s, ";") {
+ var pkey string
+ pkey, s = expectToken(skipSpace(s[1:]))
+ if pkey == "" {
+ return
+ }
+ if !strings.HasPrefix(s, "=") {
+ return
+ }
+ var pvalue string
+ pvalue, s = expectTokenOrQuoted(s[1:])
+ if pvalue == "" {
+ return
+ }
+ pkey = strings.ToLower(pkey)
+ params[pkey] = pvalue
+ s = skipSpace(s)
+ }
+ return
+}
+
+// AcceptSpec ...
+type AcceptSpec struct {
+ Value string
+ Q float64
+}
+
+// ParseAccept2 ...
+func ParseAccept2(header http.Header, key string) (specs []AcceptSpec) {
+ for _, en := range ParseList(header, key) {
+ v, p := parseValueAndParams(en)
+ var spec AcceptSpec
+ spec.Value = v
+ spec.Q = 1.0
+ if p != nil {
+ if q, ok := p["q"]; ok {
+ spec.Q, _ = expectQuality(q)
+ }
+ }
+ if spec.Q < 0.0 {
+ continue
+ }
+ specs = append(specs, spec)
+ }
+
+ return
+}
+
+// ParseAccept parses Accept* headers.
+func ParseAccept(header http.Header, key string) []AcceptSpec {
+ var specs []AcceptSpec
+loop:
+ for _, s := range header[key] {
+ for {
+ var spec AcceptSpec
+ spec.Value, s = expectTokenSlash(s)
+ if spec.Value == "" {
+ continue loop
+ }
+ spec.Q = 1.0
+ s = skipSpace(s)
+ if strings.HasPrefix(s, ";") {
+ s = skipSpace(s[1:])
+ for !strings.HasPrefix(s, "q=") && s != "" && !strings.HasPrefix(s, ",") {
+ s = skipSpace(s[1:])
+ }
+ if strings.HasPrefix(s, "q=") {
+ spec.Q, s = expectQuality(s[2:])
+ if spec.Q < 0.0 {
+ continue loop
+ }
+ }
+ }
+
+ specs = append(specs, spec)
+ s = skipSpace(s)
+ if !strings.HasPrefix(s, ",") {
+ continue loop
+ }
+ s = skipSpace(s[1:])
+ }
+ }
+
+ return specs
+}
+
+func skipSpace(s string) (rest string) {
+ i := 0
+ for ; i < len(s); i++ {
+ if octetTypes[s[i]]&isSpace == 0 {
+ break
+ }
+ }
+ return s[i:]
+}
+
+func expectToken(s string) (token, rest string) {
+ i := 0
+ for ; i < len(s); i++ {
+ if octetTypes[s[i]]&isToken == 0 {
+ break
+ }
+ }
+ return s[:i], s[i:]
+}
+
+func expectTokenSlash(s string) (token, rest string) {
+ i := 0
+ for ; i < len(s); i++ {
+ b := s[i]
+ if (octetTypes[b]&isToken == 0) && b != '/' {
+ break
+ }
+ }
+ return s[:i], s[i:]
+}
+
+func expectQuality(s string) (q float64, rest string) {
+ switch {
+ case len(s) == 0:
+ return -1, ""
+ case s[0] == '0':
+ // q is already 0
+ s = s[1:]
+ case s[0] == '1':
+ s = s[1:]
+ q = 1
+ case s[0] == '.':
+ // q is already 0
+ default:
+ return -1, ""
+ }
+ if !strings.HasPrefix(s, ".") {
+ return q, s
+ }
+ s = s[1:]
+ i := 0
+ n := 0
+ d := 1
+ for ; i < len(s); i++ {
+ b := s[i]
+ if b < '0' || b > '9' {
+ break
+ }
+ n = n*10 + int(b) - '0'
+ d *= 10
+ }
+ result := q + float64(n)/float64(d)
+ // RFC 7231 §5.3.1: qvalue is in [0, 1]. Inputs like "1.1"
+ // would otherwise yield > 1; reject as malformed.
+ if result > 1 {
+ return -1, s[i:]
+ }
+ return result, s[i:]
+}
+
+func expectTokenOrQuoted(s string) (value string, rest string) {
+ if !strings.HasPrefix(s, "\"") {
+ return expectToken(s)
+ }
+ s = s[1:]
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ case '"':
+ return s[:i], s[i+1:]
+ case '\\':
+ p := make([]byte, len(s)-1)
+ j := copy(p, s[:i])
+ escape := true
+ for i++; i < len(s); i++ {
+ b := s[i]
+ switch {
+ case escape:
+ escape = false
+ p[j] = b
+ j++
+ case b == '\\':
+ escape = true
+ case b == '"':
+ return string(p[:j]), s[i+1:]
+ default:
+ p[j] = b
+ j++
+ }
+ }
+ return "", ""
+ }
+ }
+ return "", ""
+}
diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/negotiate.go b/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/negotiate.go
new file mode 100644
index 00000000000..3c932a1969d
--- /dev/null
+++ b/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/negotiate.go
@@ -0,0 +1,215 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package negotiate
+
+import (
+ "net/http"
+ "strings"
+
+ "github.com/go-openapi/runtime/server-middleware/mediatype"
+ "github.com/go-openapi/runtime/server-middleware/negotiate/header"
+)
+
+// Option configures [ContentType] behaviour.
+type Option func(*options)
+
+type options struct {
+ ignoreParameters bool
+ matchSuffix bool
+}
+
+func optionsWithDefaults(opts []Option) options {
+ var o options
+ for _, apply := range opts {
+ apply(&o)
+ }
+
+ return o
+}
+
+// WithIgnoreParameters returns an [Option] that strips MIME-type
+// parameters from both Accept entries and offers before matching, restoring
+// the behaviour the runtime had before v0.30.
+//
+// New code should leave parameters honoured (the default). This option
+// exists for applications that depend on the looser pre-v0.30 match —
+// most often because their producers and Accept clients use mismatched
+// charset or version params that they treat as informational.
+//
+// Example — per-call opt-out:
+//
+// chosen := negotiate.ContentType(r, offers, "",
+// negotiate.WithIgnoreParameters(true),
+// )
+//
+// Example — server-wide opt-out (via [middleware.Context]):
+//
+// ctx := middleware.NewContext(spec, api, nil).SetIgnoreParameters(true)
+func WithIgnoreParameters(ignore bool) Option {
+ return func(o *options) {
+ o.ignoreParameters = ignore
+ }
+}
+
+// WithMatchSuffix returns an [Option] that extends content
+// negotiation to tolerate RFC 6839 structured-syntax suffix media
+// types. When enabled, an Accept entry of "application/json"
+// matches an offer of "application/vnd.api+json" and vice versa,
+// for the suffixes recognised by the runtime (+json, +xml, +yaml).
+//
+// Default: strict (false). Use only when interoperating with
+// clients or servers that do not strictly abide by the spec — for
+// example, servers returning application/problem+json error
+// responses against operations that only declare application/json
+// in produces.
+//
+// Suffix matches always lose to exact and alias matches when those
+// are on offer; see [mediatype.MatchKind] for the tier ordering.
+//
+// Example — per-call opt-in:
+//
+// chosen := negotiate.ContentType(r, offers, "",
+// negotiate.WithMatchSuffix(true),
+// )
+//
+// Example — server-wide opt-in (via [middleware.Context]):
+//
+// ctx := middleware.NewContext(spec, api, nil).SetMatchSuffix(true)
+func WithMatchSuffix(enable bool) Option {
+ return func(o *options) {
+ o.matchSuffix = enable
+ }
+}
+
+// ContentEncoding returns the best offered content encoding for the
+// request's Accept-Encoding header. If two offers match with equal
+// weight then the offer earlier in the list is preferred. If no offers
+// are acceptable, then "" is returned.
+//
+// Encoding tokens have no parameters, so this function is unaffected by
+// the v0.30 parameter-honouring change to [ContentType].
+//
+// Deprecated: ContentEncoding negotiation is not used by the components
+// of this project.
+//
+// This historical addition has never been associated with proper
+// compression middleware and is thus half a feature.
+// The runtime does not ship compression.
+// Use github.com/CAFxX/httpcompression or github.com/klauspost/compress/gzhttp
+// at the http.Handler level, or github.com/klauspost/compress/* for client
+// transport wrapping. See docs/examples/middleware for a recipe.
+func ContentEncoding(r *http.Request, offers []string) string {
+ bestOffer := "identity"
+ bestQ := -1.0
+ specs := header.ParseAccept(r.Header, "Accept-Encoding")
+ for _, offer := range offers {
+ for _, spec := range specs {
+ if spec.Q > bestQ &&
+ (spec.Value == "*" || spec.Value == offer) {
+ bestQ = spec.Q
+ bestOffer = offer
+ }
+ }
+ }
+ if bestQ == 0 {
+ bestOffer = ""
+ }
+
+ return bestOffer
+}
+
+// ContentType returns the best offered content type for the request's
+// Accept header. If two offers match with equal weight, then the more
+// specific offer is preferred (text/* trumps */*; type/subtype trumps
+// type/*). If two offers match with equal weight and specificity, then
+// the offer earlier in the list is preferred. If no offers match, then
+// defaultOffer is returned.
+//
+// As of v0.30 the matching rule honours MIME-type parameters: an Accept
+// entry of "text/plain;charset=utf-8" matches an offer of bare
+// "text/plain" (offer carries no constraint), but it does NOT match an
+// offer of "text/plain;charset=ascii" (charset values disagree). Pass
+// [WithIgnoreParameters](true) to restore the pre-v0.30 behaviour where
+// parameters were stripped before matching — see [WithIgnoreParameters]
+// for details and an example.
+//
+// When the Accept header is absent, the first offer is returned
+// unchanged (param-stripping is irrelevant in that case).
+func ContentType(r *http.Request, offers []string, defaultOffer string, opts ...Option) string {
+ if len(offers) == 0 {
+ return defaultOffer
+ }
+ o := optionsWithDefaults(opts)
+
+ // Per RFC 7230 §3.2.2, multiple Accept headers are equivalent to a
+ // single comma-joined value. Join before parsing so we don't drop
+ // later entries.
+ acceptValues := r.Header.Values("Accept")
+ if len(acceptValues) == 0 {
+ return offers[0]
+ }
+ acceptSet := mediatype.ParseAccept(strings.Join(acceptValues, ", "))
+ if len(acceptSet) == 0 {
+ return defaultOffer
+ }
+
+ offerSet := make(mediatype.Set, 0, len(offers))
+ rawByIdx := make([]string, 0, len(offers))
+ for _, raw := range offers {
+ mt, err := mediatype.Parse(raw)
+ if err != nil {
+ continue
+ }
+ offerSet = append(offerSet, mt)
+ rawByIdx = append(rawByIdx, raw)
+ }
+ if len(offerSet) == 0 {
+ return defaultOffer
+ }
+
+ if o.ignoreParameters {
+ acceptSet = stripSet(acceptSet)
+ offerSet = stripSet(offerSet)
+ }
+
+ var matchOpts []mediatype.MatchOption
+ if o.matchSuffix {
+ matchOpts = append(matchOpts, mediatype.AllowSuffix())
+ }
+ best, ok := acceptSet.BestMatch(offerSet, matchOpts...)
+ if !ok {
+ return defaultOffer
+ }
+ // Return the original raw offer string so callers receive the value
+ // they declared, with its parameters preserved.
+ for i, mt := range offerSet {
+ if mt.Type == best.Type && mt.Subtype == best.Subtype && sameParams(mt.Params, best.Params) {
+ return rawByIdx[i]
+ }
+ }
+
+ return best.String()
+}
+
+func stripSet(s mediatype.Set) mediatype.Set {
+ out := make(mediatype.Set, len(s))
+ for i, m := range s {
+ out[i] = m.StripParams()
+ }
+
+ return out
+}
+
+func sameParams(a, b map[string]string) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for k, v := range a {
+ if b[k] != v {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/vendor/github.com/go-openapi/runtime/statuses.go b/vendor/github.com/go-openapi/runtime/statuses.go
index c0f3e6b4477..273d9c6ced3 100644
--- a/vendor/github.com/go-openapi/runtime/statuses.go
+++ b/vendor/github.com/go-openapi/runtime/statuses.go
@@ -60,7 +60,7 @@ var Statuses = map[int]string{
444: "No Response",
449: "Retry With",
450: "Blocked by Windows Parental Controls",
- 451: "Wrong Exchange Server",
+ 451: "Unavailable For Legal Reasons",
499: "Client Closed Request",
500: "Internal Server Error",
501: "Not Implemented",
diff --git a/vendor/github.com/go-openapi/runtime/text.go b/vendor/github.com/go-openapi/runtime/text.go
index 1252ac88c71..3764a87fe51 100644
--- a/vendor/github.com/go-openapi/runtime/text.go
+++ b/vendor/github.com/go-openapi/runtime/text.go
@@ -36,14 +36,14 @@ func TextConsumer() Consumer {
if tu, ok := data.(encoding.TextUnmarshaler); ok {
err := tu.UnmarshalText(b)
if err != nil {
- return fmt.Errorf("text consumer: %v", err)
+ return fmt.Errorf("text consumer: %w", err)
}
return nil
}
t := reflect.TypeOf(data)
- if data != nil && t.Kind() == reflect.Ptr {
+ if data != nil && t.Kind() == reflect.Pointer {
v := reflect.Indirect(reflect.ValueOf(data))
if t.Elem().Kind() == reflect.String {
v.SetString(string(b))
@@ -70,7 +70,7 @@ func TextProducer() Producer {
if tm, ok := data.(encoding.TextMarshaler); ok {
txt, err := tm.MarshalText()
if err != nil {
- return fmt.Errorf("text producer: %v", err)
+ return fmt.Errorf("text producer: %w", err)
}
_, err = writer.Write(txt)
return err
diff --git a/vendor/github.com/go-openapi/runtime/yamlpc/yaml.go b/vendor/github.com/go-openapi/runtime/yamlpc/yaml.go
index ca71edbb1ba..b7fab88906c 100644
--- a/vendor/github.com/go-openapi/runtime/yamlpc/yaml.go
+++ b/vendor/github.com/go-openapi/runtime/yamlpc/yaml.go
@@ -6,8 +6,9 @@ package yamlpc
import (
"io"
- "github.com/go-openapi/runtime"
yaml "go.yaml.in/yaml/v3"
+
+ "github.com/go-openapi/runtime"
)
// YAMLConsumer creates a consumer for [yaml] data.
diff --git a/vendor/github.com/go-openapi/spec/.gitignore b/vendor/github.com/go-openapi/spec/.gitignore
index 885dc27ab0b..d8f4186fe59 100644
--- a/vendor/github.com/go-openapi/spec/.gitignore
+++ b/vendor/github.com/go-openapi/spec/.gitignore
@@ -3,4 +3,3 @@
.idea
.env
.mcp.json
-.claude/
diff --git a/vendor/github.com/go-openapi/spec/.golangci.yml b/vendor/github.com/go-openapi/spec/.golangci.yml
index dc7c96053de..9d2733176ea 100644
--- a/vendor/github.com/go-openapi/spec/.golangci.yml
+++ b/vendor/github.com/go-openapi/spec/.golangci.yml
@@ -4,7 +4,10 @@ linters:
disable:
- depguard
- funlen
+ - goconst
- godox
+ - gomodguard
+ - gomodguard_v2
- exhaustruct
- nlreturn
- nonamedreturns
diff --git a/vendor/github.com/go-openapi/spec/CONTRIBUTORS.md b/vendor/github.com/go-openapi/spec/CONTRIBUTORS.md
index 2967e3cedd9..2fd257bbeeb 100644
--- a/vendor/github.com/go-openapi/spec/CONTRIBUTORS.md
+++ b/vendor/github.com/go-openapi/spec/CONTRIBUTORS.md
@@ -4,12 +4,12 @@
| Total Contributors | Total Contributions |
| --- | --- |
-| 38 | 392 |
+| 38 | 398 |
| Username | All Time Contribution Count | All Commits |
| --- | --- | --- |
| @casualjim | 191 | |
-| @fredbi | 90 | |
+| @fredbi | 96 | |
| @pytlesk4 | 26 | |
| @kul-amr | 10 | |
| @keramix | 10 | |
@@ -47,4 +47,4 @@
| @ChandanChainani | 1 | |
| @bvwells | 1 | |
- _this file was generated by the [Contributors GitHub Action](https://github.com/github/contributors)_
+ _this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_
diff --git a/vendor/github.com/go-openapi/spec/README.md b/vendor/github.com/go-openapi/spec/README.md
index 134809fd77a..7c96eb9a586 100644
--- a/vendor/github.com/go-openapi/spec/README.md
+++ b/vendor/github.com/go-openapi/spec/README.md
@@ -18,12 +18,9 @@ The object model for OpenAPI v2 specification documents.
* **2025-12-19** : new community chat on discord
* a new discord community channel is available to be notified of changes and support users
- * our venerable Slack channel remains open, and will be eventually discontinued on **2026-03-31**
You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url]
-Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url]
-
## Status
API is stable.
@@ -95,9 +92,9 @@ This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
## Other documentation
* [All-time contributors](./CONTRIBUTORS.md)
-* [Contributing guidelines](.github/CONTRIBUTING.md)
-* [Maintainers documentation](docs/MAINTAINERS.md)
-* [Code style](docs/STYLE.md)
+* [Contributing guidelines][contributing-doc-site]
+* [Maintainers documentation][maintainers-doc-site]
+* [Code style][style-doc-site]
## Cutting a new release
@@ -132,11 +129,8 @@ Maintainers can cut a new release by either:
[doc-url]: https://goswagger.io/go-openapi
[godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/spec
[godoc-url]: http://pkg.go.dev/github.com/go-openapi/spec
-[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png
-[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM
-[slack-url]: https://goswagger.slack.com/archives/C04R30YMU
[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue
-[discord-url]: https://discord.gg/twZ9BwT3
+[discord-url]: https://discord.gg/FfnFYaC3k5
[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
@@ -146,3 +140,7 @@ Maintainers can cut a new release by either:
[goversion-url]: https://github.com/go-openapi/spec/blob/master/go.mod
[top-badge]: https://img.shields.io/github/languages/top/go-openapi/spec
[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/spec/latest
+
+[contributing-doc-site]: https://go-openapi.github.io/doc-site/contributing/contributing/index.html
+[maintainers-doc-site]: https://go-openapi.github.io/doc-site/maintainers/index.html
+[style-doc-site]: https://go-openapi.github.io/doc-site/contributing/style/index.html
diff --git a/vendor/github.com/go-openapi/spec/header.go b/vendor/github.com/go-openapi/spec/header.go
index 599ba2c5d7e..f656e0789a1 100644
--- a/vendor/github.com/go-openapi/spec/header.go
+++ b/vendor/github.com/go-openapi/spec/header.go
@@ -150,7 +150,11 @@ func (h Header) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
- return jsonutils.ConcatJSON(b1, b2, b3), nil
+ b4, err := json.Marshal(h.VendorExtensible)
+ if err != nil {
+ return nil, err
+ }
+ return jsonutils.ConcatJSON(b1, b2, b3, b4), nil
}
// UnmarshalJSON unmarshals this header from JSON.
diff --git a/vendor/github.com/go-openapi/spec/schema_loader.go b/vendor/github.com/go-openapi/spec/schema_loader.go
index 0894c932c6b..1e346069e2d 100644
--- a/vendor/github.com/go-openapi/spec/schema_loader.go
+++ b/vendor/github.com/go-openapi/spec/schema_loader.go
@@ -117,7 +117,7 @@ func (r *schemaLoader) updateBasePath(transitive *schemaLoader, basePath string)
func (r *schemaLoader) resolveRef(ref *Ref, target any, basePath string) error {
tgt := reflect.ValueOf(target)
- if tgt.Kind() != reflect.Ptr {
+ if tgt.Kind() != reflect.Pointer {
return ErrResolveRefNeedsAPointer
}
diff --git a/vendor/github.com/go-openapi/strfmt/.gitignore b/vendor/github.com/go-openapi/strfmt/.gitignore
index 885dc27ab0b..bbdffea78a0 100644
--- a/vendor/github.com/go-openapi/strfmt/.gitignore
+++ b/vendor/github.com/go-openapi/strfmt/.gitignore
@@ -3,4 +3,4 @@
.idea
.env
.mcp.json
-.claude/
+go.work.sum
diff --git a/vendor/github.com/go-openapi/strfmt/CONTRIBUTORS.md b/vendor/github.com/go-openapi/strfmt/CONTRIBUTORS.md
index e49700d4d25..b6d62d76eb0 100644
--- a/vendor/github.com/go-openapi/strfmt/CONTRIBUTORS.md
+++ b/vendor/github.com/go-openapi/strfmt/CONTRIBUTORS.md
@@ -4,12 +4,12 @@
| Total Contributors | Total Contributions |
| --- | --- |
-| 40 | 225 |
+| 40 | 234 |
| Username | All Time Contribution Count | All Commits |
| --- | --- | --- |
| @casualjim | 88 | |
-| @fredbi | 57 | |
+| @fredbi | 66 | |
| @youyuanwu | 13 | |
| @jlambatl | 9 | |
| @GlenDC | 5 | |
diff --git a/vendor/github.com/go-openapi/strfmt/README.md b/vendor/github.com/go-openapi/strfmt/README.md
index a0cf6427541..4afef43733d 100644
--- a/vendor/github.com/go-openapi/strfmt/README.md
+++ b/vendor/github.com/go-openapi/strfmt/README.md
@@ -16,14 +16,6 @@ Golang support for string formats defined by JSON Schema and OpenAPI.
## Announcements
-* **2025-12-19** : new community chat on discord
- * a new discord community channel is available to be notified of changes and support users
- * our venerable Slack channel remains open, and will be eventually discontinued on **2026-03-31**
-
-You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url]
-
-Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url]
-
* **2026-03-07** : v0.26.0 **dropped dependency to the mongodb driver**
* mongodb users can still use this package without any change
* however, we have frozen the back-compatible support for mongodb driver at v2.5.0
@@ -177,9 +169,9 @@ This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
## Other documentation
* [All-time contributors](./CONTRIBUTORS.md)
-* [Contributing guidelines](.github/CONTRIBUTING.md)
-* [Maintainers documentation](docs/MAINTAINERS.md)
-* [Code style](docs/STYLE.md)
+* [Contributing guidelines][contributing-doc-site]
+* [Maintainers documentation][maintainers-doc-site]
+* [Code style][style-doc-site]
## Cutting a new release
@@ -214,9 +206,6 @@ Maintainers can cut a new release by either:
[doc-url]: https://goswagger.io/go-openapi
[godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/strfmt
[godoc-url]: http://pkg.go.dev/github.com/go-openapi/strfmt
-[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png
-[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM
-[slack-url]: https://goswagger.slack.com/archives/C04R30YMU
[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue
[discord-url]: https://discord.gg/FfnFYaC3k5
@@ -228,3 +217,7 @@ Maintainers can cut a new release by either:
[goversion-url]: https://github.com/go-openapi/strfmt/blob/master/go.mod
[top-badge]: https://img.shields.io/github/languages/top/go-openapi/strfmt
[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/strfmt/latest
+
+[contributing-doc-site]: https://go-openapi.github.io/doc-site/contributing/contributing/index.html
+[maintainers-doc-site]: https://go-openapi.github.io/doc-site/maintainers/index.html
+[style-doc-site]: https://go-openapi.github.io/doc-site/contributing/style/index.html
diff --git a/vendor/github.com/go-openapi/strfmt/duration.go b/vendor/github.com/go-openapi/strfmt/duration.go
index b710bfbf53c..f2ab7ff8348 100644
--- a/vendor/github.com/go-openapi/strfmt/duration.go
+++ b/vendor/github.com/go-openapi/strfmt/duration.go
@@ -7,11 +7,9 @@ import (
"database/sql/driver"
"encoding/json"
"fmt"
- "math"
- "regexp"
- "strconv"
"strings"
"time"
+ "unicode"
)
func init() { //nolint:gochecknoinits // registers duration format in the default registry
@@ -22,34 +20,62 @@ func init() { //nolint:gochecknoinits // registers duration format in the defaul
const (
hoursInDay = 24
daysInWeek = 7
+ nanos = uint64(time.Nanosecond)
+ micros = uint64(time.Microsecond)
+ millis = uint64(time.Millisecond)
+ seconds = uint64(time.Second)
+ minutes = uint64(time.Minute)
+ hours = uint64(time.Hour)
+ days = uint64(hoursInDay * time.Hour)
+ weeks = uint64(hoursInDay * daysInWeek * time.Hour)
+ maxUint64 = uint64(1 << 63)
)
+// timeMultiplier holds all supported aliases for duration units, including their plural form.
+//
//nolint:gochecknoglobals // package-level lookup tables for duration parsing
-var (
- timeUnits = [][]string{
- {"ns", "nano"},
- {"us", "µs", "micro"},
- {"ms", "milli"},
- {"s", "sec"},
- {"m", "min"},
- {"h", "hr", "hour"},
- {"d", "day"},
- {"w", "wk", "week"},
- }
-
- timeMultiplier = map[string]time.Duration{
- "ns": time.Nanosecond,
- "us": time.Microsecond,
- "ms": time.Millisecond,
- "s": time.Second,
- "m": time.Minute,
- "h": time.Hour,
- "d": hoursInDay * time.Hour,
- "w": hoursInDay * daysInWeek * time.Hour,
- }
-
- durationMatcher = regexp.MustCompile(`^(((?:-\s?)?\d+)(\.\d+)?\s*([A-Za-zµ]+))`)
-)
+var timeMultiplier = map[string]uint64{
+ "ns": nanos,
+ "nano": nanos,
+ "nanosecond": nanos,
+ "nanoseconds": nanos,
+ "nanos": nanos,
+ "us": micros,
+ "µs": micros, // U+00B5 = micro symbol
+ "μs": micros, // U+03BC = Greek letter mu
+ "micro": micros,
+ "micros": micros,
+ "microsecond": micros,
+ "microseconds": micros,
+ "ms": millis,
+ "milli": millis,
+ "millis": millis,
+ "millisecond": millis,
+ "milliseconds": millis,
+ "s": seconds,
+ "sec": seconds,
+ "secs": seconds,
+ "second": seconds,
+ "seconds": seconds,
+ "m": minutes,
+ "min": minutes,
+ "mins": minutes,
+ "minute": minutes,
+ "minutes": minutes,
+ "h": hours,
+ "hr": hours,
+ "hrs": hours,
+ "hour": hours,
+ "hours": hours,
+ "d": days,
+ "day": days,
+ "days": days,
+ "w": weeks,
+ "wk": weeks,
+ "wks": weeks,
+ "week": weeks,
+ "weeks": weeks,
+}
// IsDuration returns true if the provided string is a valid duration.
func IsDuration(str string) bool {
@@ -80,64 +106,157 @@ func (d *Duration) UnmarshalText(data []byte) error { // validation is performed
return nil
}
-// ParseDuration parses a duration from a string, compatible with scala duration syntax.
-func ParseDuration(cand string) (time.Duration, error) {
- if dur, err := time.ParseDuration(cand); err == nil {
- return dur, nil
+// ParseDuration parses a duration from a string
+//
+// It is similar to [time.ParseDuration] but support additional units like days and weeks,
+// additional abreviations for units and is more tolerant on the presence of blank spaces.
+//
+// A duration may be negative or fractional.
+//
+// # Differences with [time.ParseDuration]
+//
+// - more supported units and aliases (see below)
+// - sign followed by blank space is tolerated
+// - tolerates blanks between duration and unit (e.g. "300 ms")
+//
+// # Supported units
+//
+// Units may be specified using aliases or a plural form.
+//
+// - "ns", "nano", "nanosecond", "nanoseconds", "nanos"
+// - "us", "µs" (U+00B5 = micro symbol), "μs" (U+03BC = Greek letter mu), "micro", "micros", "microsecond", "microseconds"
+// - "ms", "milli", "millis", "millisecond", "milliseconds"
+// - "s", "sec", "secs", "second", "seconds"
+// - "m", "min", "mins", "minute", "minutes"
+// - "h", "hr", "hrs", "hour", "hours"
+// - "d", "day", "days"
+// - "w", "wk", "wks", "week", "weeks"
+//
+// NOTE: inspired by scala duration syntax.
+//
+// # Examples
+//
+// "300ms", "-1.5h", "2h45m",
+// ".5 week",
+// "2 minutes 45 seconds".
+//
+//nolint:gocognit,gocyclo,cyclop // complexity is only slightly above the usual level, may be tolerated as it mimicks the stdlib.
+func ParseDuration(s string) (time.Duration, error) {
+ // NOTE: this code is largely inspired by the standard library.
+ orig := s
+ var d uint64
+ neg := false
+
+ // Consume [-+]?
+ if s != "" {
+ c := s[0]
+ if c == '-' || c == '+' {
+ neg = c == '-'
+ s = s[1:]
+ }
}
- var dur time.Duration
- ok := false
- const expectGroups = 4
- for _, match := range durationMatcher.FindAllStringSubmatch(cand, -1) {
- if len(match) < expectGroups {
- continue
+ // Consume space
+ s = strings.TrimLeftFunc(s, unicode.IsSpace)
+
+ // Special case: if all that is left is "0", this is zero.
+ if s == "0" {
+ return 0, nil
+ }
+
+ if s == "" {
+ return 0, parseDurationError(orig, "empty duration")
+ }
+
+ for s != "" {
+ var (
+ v, f uint64 // integers before, after decimal point
+ scale float64 = 1 // value = v + f/scale
+ )
+ s = strings.TrimLeftFunc(s, unicode.IsSpace)
+
+ // The next character must be 0-9.]
+ if s[0] != '.' && ('0' > s[0] || s[0] > '9') {
+ return 0, parseDurationError(orig, fmt.Sprintf("expected a numerical value, but got %q", s[0]))
+ }
+
+ // Consume integer part [0-9]*
+ pl := len(s)
+ var ok bool
+ v, s, ok = leadingInt(s)
+ if !ok {
+ return 0, parseDurationError(orig, "expected a leading integer part")
}
+ pre := pl != len(s) // whether we consumed anything before a period
- // remove possible leading - and spaces
- value, negative := strings.CutPrefix(match[2], "-")
+ // Consume fractional part (\.[0-9]*)?
+ post := false
+ if s != "" && s[0] == '.' {
+ s = s[1:]
+ pl := len(s)
+ f, scale, s = leadingFraction(s)
+ post = pl != len(s)
+ }
- // if the duration contains a decimal separator determine a divising factor
- const neutral = 1.0
- divisor := neutral
- decimal, hasDecimal := strings.CutPrefix(match[3], ".")
- if hasDecimal {
- divisor = math.Pow10(len(decimal))
- value += decimal // consider the value as an integer: will change units later on
+ if !pre && !post {
+ // no digits (e.g. ".s" or "-.s")
+ return 0, parseDurationError(orig, "expected digits")
}
- // if the string is a valid duration, parse it
- factor, err := strconv.Atoi(strings.TrimSpace(value)) // converts string to int
- if err != nil {
- return 0, err
+ // Consume space.
+ s = strings.TrimLeftFunc(s, unicode.IsSpace)
+
+ // Consume unit.
+ i := 0
+ for ; i < len(s); i++ {
+ c := s[i]
+ if c == '.' || '0' <= c && c <= '9' || unicode.IsSpace(rune(c)) {
+ break
+ }
}
- if negative {
- factor = -factor
+ if i == 0 {
+ return 0, parseDurationError(orig, "missing unit in duration")
}
- unit := strings.ToLower(strings.TrimSpace(match[4]))
+ u := s[:i]
+ s = s[i:]
+ unit, ok := timeMultiplier[u]
+ if !ok {
+ return 0, parseDurationError(orig, fmt.Sprintf("unknown unit %q in duration", u))
+ }
- for _, variants := range timeUnits {
- last := len(variants) - 1
- multiplier := timeMultiplier[variants[0]]
+ if v > maxUint64/unit {
+ // overflow
+ return 0, parseDurationError(orig, "numerical overflow")
+ }
- for i, variant := range variants {
- if (last == i && strings.HasPrefix(unit, variant)) || strings.EqualFold(variant, unit) {
- ok = true
- if divisor != neutral {
- multiplier = time.Duration(float64(multiplier) / divisor) // convert to duration only after having reduced the scale
- }
- dur += (time.Duration(factor) * multiplier)
- }
+ v *= unit
+ if f > 0 {
+ // float64 is needed to be nanosecond accurate for fractions of hours.
+ // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
+ v += uint64(float64(f) * (float64(unit) / scale))
+ if v > maxUint64 {
+ // overflow
+ return 0, parseDurationError(orig, "numerical overflow")
}
}
+
+ d += v
+ if d > maxUint64 {
+ return 0, parseDurationError(orig, "numerical overflow")
+ }
}
- if ok {
- return dur, nil
+ if neg {
+ return -time.Duration(d), nil
}
- return 0, fmt.Errorf("unable to parse %s as duration: %w", cand, ErrFormat)
+
+ if d > maxUint64-1 {
+ return 0, parseDurationError(orig, "numerical overflow")
+ }
+
+ return time.Duration(d), nil
}
// Scan reads a Duration value from database driver type.
@@ -204,3 +323,70 @@ func (d *Duration) DeepCopy() *Duration {
d.DeepCopyInto(out)
return out
}
+
+func parseDurationError(s, msg string) error {
+ if msg == "" {
+ return fmt.Errorf("invalid duration: %s: %w", s, ErrFormat)
+ }
+
+ return fmt.Errorf("invalid duration: %s: %s: %w", s, msg, ErrFormat)
+}
+
+// leadingInt consumes the leading [0-9]* from s.
+func leadingInt[bytes []byte | string](s bytes) (x uint64, rem bytes, ok bool) { //nolint:ireturn // false positive
+ i := 0
+ for ; i < len(s); i++ {
+ c := s[i]
+ if c < '0' || c > '9' {
+ break
+ }
+
+ if x > maxUint64/10 { // overflow
+ return 0, rem, false
+ }
+
+ x = x*10 + uint64(c) - '0'
+ if x > maxUint64 { // overflow
+ return 0, rem, false
+ }
+ }
+
+ return x, s[i:], true
+}
+
+// leadingFraction consumes the leading [0-9]* from s.
+// //
+// It is used only for fractions, so it does not return an error on overflow,
+// it just stops accumulating precision.
+func leadingFraction(s string) (x uint64, scale float64, rem string) {
+ i := 0
+ scale = 1
+ overflow := false
+ for ; i < len(s); i++ {
+ c := s[i]
+ if c < '0' || c > '9' {
+ break
+ }
+
+ if overflow {
+ continue
+ }
+
+ if x > (maxUint64-1)/10 {
+ // It's possible for overflow to give a positive number, so take care.
+ overflow = true
+ continue
+ }
+
+ y := x*10 + uint64(c) - '0'
+ if y > maxUint64 {
+ overflow = true
+ continue
+ }
+
+ x = y
+ scale *= 10
+ }
+
+ return x, scale, s[i:]
+}
diff --git a/vendor/github.com/go-openapi/strfmt/go.work b/vendor/github.com/go-openapi/strfmt/go.work
index 288e7655d45..f233e74cfd0 100644
--- a/vendor/github.com/go-openapi/strfmt/go.work
+++ b/vendor/github.com/go-openapi/strfmt/go.work
@@ -4,4 +4,4 @@ use (
./internal/testintegration
)
-go 1.24.0
+go 1.25.0
diff --git a/vendor/github.com/go-openapi/strfmt/go.work.sum b/vendor/github.com/go-openapi/strfmt/go.work.sum
deleted file mode 100644
index 33dac969b64..00000000000
--- a/vendor/github.com/go-openapi/strfmt/go.work.sum
+++ /dev/null
@@ -1,16 +0,0 @@
-github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
-github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
-github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30 h1:BHT1/DKsYDGkUgQ2jmMaozVcdk+sVfz0+1ZJq4zkWgw=
-github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
-github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
-golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
-golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
-golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
-golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
-golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
-golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
-golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/vendor/github.com/go-openapi/swag/.gitignore b/vendor/github.com/go-openapi/swag/.gitignore
index a0a95a96b3f..1680db44c01 100644
--- a/vendor/github.com/go-openapi/swag/.gitignore
+++ b/vendor/github.com/go-openapi/swag/.gitignore
@@ -4,4 +4,3 @@ Godeps
.idea
*.out
.mcp.json
-.claude/
diff --git a/vendor/github.com/go-openapi/swag/CONTRIBUTORS.md b/vendor/github.com/go-openapi/swag/CONTRIBUTORS.md
index bc76fe820c0..ef1a735293e 100644
--- a/vendor/github.com/go-openapi/swag/CONTRIBUTORS.md
+++ b/vendor/github.com/go-openapi/swag/CONTRIBUTORS.md
@@ -4,11 +4,11 @@
| Total Contributors | Total Contributions |
| --- | --- |
-| 24 | 235 |
+| 24 | 246 |
| Username | All Time Contribution Count | All Commits |
| --- | --- | --- |
-| @fredbi | 105 | |
+| @fredbi | 116 | |
| @casualjim | 98 | |
| @alexandear | 4 | |
| @orisano | 3 | |
@@ -33,4 +33,4 @@
| @davidalpert | 1 | |
| @Xe | 1 | |
- _this file was generated by the [Contributors GitHub Action](https://github.com/github/contributors)_
+ _this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_
diff --git a/vendor/github.com/go-openapi/swag/README.md b/vendor/github.com/go-openapi/swag/README.md
index 834eb2ffb9c..ddbd8735ced 100644
--- a/vendor/github.com/go-openapi/swag/README.md
+++ b/vendor/github.com/go-openapi/swag/README.md
@@ -34,12 +34,9 @@ You may also use it standalone for your projects.
* **2025-12-19** : new community chat on discord
* a new discord community channel is available to be notified of changes and support users
- * our venerable Slack channel remains open, and will be eventually discontinued on **2026-03-31**
You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url]
-Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url]
-
## Status
API is stable.
@@ -171,9 +168,9 @@ on top of which it has been built.
## Other documentation
* [All-time contributors](./CONTRIBUTORS.md)
-* [Contributing guidelines](.github/CONTRIBUTING.md)
-* [Maintainers documentation](docs/MAINTAINERS.md)
-* [Code style](docs/STYLE.md)
+* [Contributing guidelines][contributing-doc-site]
+* [Maintainers documentation][maintainers-doc-site]
+* [Code style][style-doc-site]
## Cutting a new release
@@ -208,11 +205,8 @@ Maintainers can cut a new release by either:
[doc-url]: https://goswagger.io/go-openapi
[godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/swag
[godoc-url]: http://pkg.go.dev/github.com/go-openapi/swag
-[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png
-[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM
-[slack-url]: https://goswagger.slack.com/archives/C04R30YMU
[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue
-[discord-url]: https://discord.gg/twZ9BwT3
+[discord-url]: https://discord.gg/FfnFYaC3k5
[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
@@ -222,3 +216,7 @@ Maintainers can cut a new release by either:
[goversion-url]: https://github.com/go-openapi/swag/blob/master/go.mod
[top-badge]: https://img.shields.io/github/languages/top/go-openapi/swag
[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/swag/latest
+
+[contributing-doc-site]: https://go-openapi.github.io/doc-site/contributing/contributing/index.html
+[maintainers-doc-site]: https://go-openapi.github.io/doc-site/maintainers/index.html
+[style-doc-site]: https://go-openapi.github.io/doc-site/contributing/style/index.html
diff --git a/vendor/github.com/go-openapi/swag/SECURITY.md b/vendor/github.com/go-openapi/swag/SECURITY.md
index 72296a83135..1fea2c5736a 100644
--- a/vendor/github.com/go-openapi/swag/SECURITY.md
+++ b/vendor/github.com/go-openapi/swag/SECURITY.md
@@ -6,14 +6,32 @@ This policy outlines the commitment and practices of the go-openapi maintainers
| Version | Supported |
| ------- | ------------------ |
-| 0.25.x | :white_check_mark: |
+| O.x | :white_check_mark: |
+
+## Vulnerability checks in place
+
+This repository uses automated vulnerability scans, at every merged commit and at least once a week.
+
+We use:
+
+* [`GitHub CodeQL`][codeql-url]
+* [`trivy`][trivy-url]
+* [`govulncheck`][govulncheck-url]
+
+Reports are centralized in github security reports and visible only to the maintainers.
## Reporting a vulnerability
If you become aware of a security vulnerability that affects the current repository,
-please report it privately to the maintainers.
+**please report it privately to the maintainers**
+rather than opening a publicly visible GitHub issue.
+
+Please follow the instructions provided by github to [Privately report a security vulnerability][github-guidance-url].
-Please follow the instructions provided by github to
-[Privately report a security vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability).
+> [!NOTE]
+> On Github, navigate to the project's "Security" tab then click on "Report a vulnerability".
-TL;DR: on Github, navigate to the project's "Security" tab then click on "Report a vulnerability".
+[codeql-url]: https://github.com/github/codeql
+[trivy-url]: https://trivy.dev/docs/latest/getting-started
+[govulncheck-url]: https://go.dev/blog/govulncheck
+[github-guidance-url]: https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability
diff --git a/vendor/github.com/go-openapi/swag/go.work b/vendor/github.com/go-openapi/swag/go.work
index 1e537f0749b..8537cb2a76a 100644
--- a/vendor/github.com/go-openapi/swag/go.work
+++ b/vendor/github.com/go-openapi/swag/go.work
@@ -17,4 +17,4 @@ use (
./yamlutils
)
-go 1.24.0
+go 1.25.0
diff --git a/vendor/github.com/go-openapi/swag/jsonname/go_name_provider.go b/vendor/github.com/go-openapi/swag/jsonname/go_name_provider.go
new file mode 100644
index 00000000000..adc4426873c
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonname/go_name_provider.go
@@ -0,0 +1,286 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package jsonname
+
+import (
+ "reflect"
+ "strings"
+ "sync"
+)
+
+var _ providerIface = (*GoNameProvider)(nil)
+
+// GoNameProvider resolves json property names to go struct field names following
+// the same rules as the standard library's [encoding/json] package.
+//
+// Contrary to [NameProvider], it considers exported fields without a json tag,
+// and promotes fields from anonymous embedded struct types.
+//
+// Rules (aligned with encoding/json):
+//
+// - unexported fields are ignored;
+// - a field tagged `json:"-"` is ignored;
+// - a field tagged `json:"-,"` is kept under the json name "-" (stdlib quirk);
+// - a field tagged `json:""` or with no json tag at all keeps its Go name as json name;
+// - anonymous struct fields without an explicit json tag have their fields
+// promoted into the parent, following breadth-first depth rules:
+// a shallower field wins over a deeper one; at equal depth, a conflict
+// discards all conflicting fields unless exactly one has an explicit json tag.
+//
+// This type is safe for concurrent use.
+type GoNameProvider struct {
+ lock sync.Mutex
+ index map[reflect.Type]nameIndex
+}
+
+// NewGoNameProvider creates a new [GoNameProvider].
+func NewGoNameProvider() *GoNameProvider {
+ return &GoNameProvider{
+ index: make(map[reflect.Type]nameIndex),
+ }
+}
+
+// GetJSONNames gets all the json property names for a type.
+func (n *GoNameProvider) GetJSONNames(subject any) []string {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
+ names := n.nameIndexFor(tpe)
+
+ res := make([]string, 0, len(names.jsonNames))
+ for k := range names.jsonNames {
+ res = append(res, k)
+ }
+
+ return res
+}
+
+// GetJSONName gets the json name for a go property name.
+func (n *GoNameProvider) GetJSONName(subject any, name string) (string, bool) {
+ tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
+
+ return n.GetJSONNameForType(tpe, name)
+}
+
+// GetJSONNameForType gets the json name for a go property name on a given type.
+func (n *GoNameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ names := n.nameIndexFor(tpe)
+ nme, ok := names.goNames[name]
+
+ return nme, ok
+}
+
+// GetGoName gets the go name for a json property name.
+func (n *GoNameProvider) GetGoName(subject any, name string) (string, bool) {
+ tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
+
+ return n.GetGoNameForType(tpe, name)
+}
+
+// GetGoNameForType gets the go name for a given type for a json property name.
+func (n *GoNameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ names := n.nameIndexFor(tpe)
+ nme, ok := names.jsonNames[name]
+
+ return nme, ok
+}
+
+func (n *GoNameProvider) nameIndexFor(tpe reflect.Type) nameIndex {
+ if names, ok := n.index[tpe]; ok {
+ return names
+ }
+
+ names := buildGoNameIndex(tpe)
+ n.index[tpe] = names
+
+ return names
+}
+
+// fieldEntry captures a candidate field discovered while walking a struct
+// along with the indirection path from the root type (used to resolve conflicts
+// by depth in the same way encoding/json does).
+type fieldEntry struct {
+ goName string
+ jsonName string
+ index []int
+ tagged bool
+}
+
+func buildGoNameIndex(tpe reflect.Type) nameIndex {
+ fields := collectGoFields(tpe)
+
+ idx := make(map[string]string, len(fields))
+ reverseIdx := make(map[string]string, len(fields))
+ for _, f := range fields {
+ idx[f.jsonName] = f.goName
+ reverseIdx[f.goName] = f.jsonName
+ }
+
+ return nameIndex{jsonNames: idx, goNames: reverseIdx}
+}
+
+// collectGoFields walks tpe breadth-first along anonymous struct fields,
+// reproducing the field selection performed by encoding/json.typeFields.
+func collectGoFields(tpe reflect.Type) []fieldEntry {
+ if tpe.Kind() != reflect.Struct {
+ return nil
+ }
+
+ type queued struct {
+ typ reflect.Type
+ index []int
+ }
+
+ current := []queued{}
+ next := []queued{{typ: tpe}}
+ visited := map[reflect.Type]bool{tpe: true}
+
+ var (
+ candidates []fieldEntry
+ count = map[string]int{}
+ nextCount = map[string]int{}
+ )
+
+ for len(next) > 0 {
+ current, next = next, current[:0]
+ count, nextCount = nextCount, count
+ for k := range nextCount {
+ delete(nextCount, k)
+ }
+
+ for _, q := range current {
+ for i := 0; i < q.typ.NumField(); i++ {
+ sf := q.typ.Field(i)
+
+ if sf.Anonymous {
+ ft := sf.Type
+ if ft.Kind() == reflect.Ptr {
+ ft = ft.Elem()
+ }
+ if !sf.IsExported() && ft.Kind() != reflect.Struct {
+ continue
+ }
+ } else if !sf.IsExported() {
+ continue
+ }
+
+ tag := sf.Tag.Get("json")
+ if tag == "-" {
+ continue
+ }
+ jsonName, _ := parseJSONTag(tag)
+ tagged := jsonName != ""
+
+ ft := sf.Type
+ if ft.Kind() == reflect.Ptr {
+ ft = ft.Elem()
+ }
+
+ if sf.Anonymous && ft.Kind() == reflect.Struct && !tagged {
+ if visited[ft] {
+ continue
+ }
+ visited[ft] = true
+
+ index := make([]int, len(q.index)+1)
+ copy(index, q.index)
+ index[len(q.index)] = i
+ next = append(next, queued{typ: ft, index: index})
+
+ continue
+ }
+
+ name := jsonName
+ if name == "" {
+ name = sf.Name
+ }
+
+ index := make([]int, len(q.index)+1)
+ copy(index, q.index)
+ index[len(q.index)] = i
+
+ candidates = append(candidates, fieldEntry{
+ goName: sf.Name,
+ jsonName: name,
+ index: index,
+ tagged: tagged,
+ })
+ nextCount[name]++
+ }
+ }
+ }
+
+ return dominantFields(candidates)
+}
+
+// dominantFields applies the Go encoding/json conflict resolution rules:
+// at each JSON name, the shallowest field wins; at equal depth, a uniquely
+// tagged candidate wins; otherwise all candidates for that name are dropped.
+func dominantFields(candidates []fieldEntry) []fieldEntry {
+ byName := make(map[string][]fieldEntry, len(candidates))
+ for _, c := range candidates {
+ byName[c.jsonName] = append(byName[c.jsonName], c)
+ }
+
+ out := make([]fieldEntry, 0, len(byName))
+ for _, group := range byName {
+ if len(group) == 1 {
+ out = append(out, group[0])
+
+ continue
+ }
+
+ minDepth := len(group[0].index)
+ for _, c := range group[1:] {
+ if len(c.index) < minDepth {
+ minDepth = len(c.index)
+ }
+ }
+
+ var shallow []fieldEntry
+ for _, c := range group {
+ if len(c.index) == minDepth {
+ shallow = append(shallow, c)
+ }
+ }
+
+ if len(shallow) == 1 {
+ out = append(out, shallow[0])
+
+ continue
+ }
+
+ var tagged []fieldEntry
+ for _, c := range shallow {
+ if c.tagged {
+ tagged = append(tagged, c)
+ }
+ }
+ if len(tagged) == 1 {
+ out = append(out, tagged[0])
+ }
+ }
+
+ return out
+}
+
+// parseJSONTag returns the name component of a json struct tag and whether
+// it carried any non-name option (kept for future-proofing, e.g. "omitempty").
+func parseJSONTag(tag string) (string, string) {
+ if tag == "" {
+ return "", ""
+ }
+ if idx := strings.IndexByte(tag, ','); idx >= 0 {
+ return tag[:idx], tag[idx+1:]
+ }
+
+ return tag, ""
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonname/ifaces.go b/vendor/github.com/go-openapi/swag/jsonname/ifaces.go
new file mode 100644
index 00000000000..812ace5639f
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonname/ifaces.go
@@ -0,0 +1,14 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package jsonname
+
+import "reflect"
+
+// providerIface is an unexported compile-time contract that every name provider
+// in this package is expected to satisfy.
+// It mirrors the interface declared by the main consumer of this module: [github.com/go-openapi/jsonpointer.NameProvider].
+type providerIface interface {
+ GetGoName(subject any, name string) (string, bool)
+ GetGoNameForType(tpe reflect.Type, name string) (string, bool)
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonname/name_provider.go b/vendor/github.com/go-openapi/swag/jsonname/name_provider.go
index 8eaf1bece8d..9f5da7a0165 100644
--- a/vendor/github.com/go-openapi/swag/jsonname/name_provider.go
+++ b/vendor/github.com/go-openapi/swag/jsonname/name_provider.go
@@ -12,6 +12,8 @@ import (
// DefaultJSONNameProvider is the default cache for types.
var DefaultJSONNameProvider = NewNameProvider()
+var _ providerIface = (*NameProvider)(nil)
+
// NameProvider represents an object capable of translating from go property names
// to json property names.
//
diff --git a/vendor/github.com/go-openapi/swag/loading/doc.go b/vendor/github.com/go-openapi/swag/loading/doc.go
index 8cf7bcb8b9d..112c49968b8 100644
--- a/vendor/github.com/go-openapi/swag/loading/doc.go
+++ b/vendor/github.com/go-openapi/swag/loading/doc.go
@@ -2,4 +2,28 @@
// SPDX-License-Identifier: Apache-2.0
// Package loading provides tools to load a file from http or from a local file system.
+//
+// # Security
+//
+// By default, the local loader reads any path the process can access, including absolute
+// paths and "file://" URIs (for example "file:///etc/passwd"). Applications that pass
+// untrusted input to [LoadFromFileOrHTTP], [JSONDoc] (or to downstream consumers such as
+// go-openapi/loads) must confine local loading to a trusted directory.
+//
+// Use [WithRoot] to do so: it resolves every requested path relative to a chosen directory
+// and rejects anything that escapes it, including via symlink. It is built on [os.Root]
+// and is therefore safer than passing an [os.DirFS] to [WithFS], which does not block
+// symlink escapes.
+//
+// Remote loading uses a standard [net/http] client.
+// By default it follows redirects and performs no destination filtering — exactly like [net/http.DefaultClient].
+//
+// A caller-controlled URL may therefore reach internal services or cloud metadata endpoints
+// (server-side request forgery).
+//
+// This package does not, and should not, embed a network policy:
+// when the URL may derive from untrusted input, supply a restricted client with
+// [WithHTTPClient] whose transport rejects unwanted destinations at dial time — which also
+// covers redirects and DNS rebinding.
+// See the example on [LoadFromFileOrHTTP].
package loading
diff --git a/vendor/github.com/go-openapi/swag/loading/loading.go b/vendor/github.com/go-openapi/swag/loading/loading.go
index 269fb74d167..0b38ac1e384 100644
--- a/vendor/github.com/go-openapi/swag/loading/loading.go
+++ b/vendor/github.com/go-openapi/swag/loading/loading.go
@@ -17,7 +17,11 @@ import (
"strings"
)
-// LoadFromFileOrHTTP loads the bytes from a file or a remote http server based on the path passed in
+// LoadFromFileOrHTTP loads the bytes from a file or a remote http server based on the path passed in.
+//
+// Security: by default a local path is read with no confinement, so a caller-controlled path
+// (including a "file://" URI or an absolute path) may read any file the process can access.
+// When the path may derive from untrusted input, confine local loading with [WithRoot].
func LoadFromFileOrHTTP(pth string, opts ...Option) ([]byte, error) {
o := optionsWithDefaults(opts)
return LoadStrategy(pth, o.ReadFileFunc(), loadHTTPBytes(opts...), opts...)(pth)
@@ -54,11 +58,14 @@ func LoadFromFileOrHTTP(pth string, opts ...Option) ([]byte, error) {
// - `file:///c:/folder/file` becomes `C:\folder\file`
// - `file://c:/folder/file` is tolerated (without leading `/`) and becomes `c:\folder\file`
func LoadStrategy(pth string, local, remote func(string) ([]byte, error), opts ...Option) func(string) ([]byte, error) {
- if strings.HasPrefix(pth, "http") {
+ if hasHTTPScheme(pth) {
return remote
}
o := optionsWithDefaults(opts)
_, isEmbedFS := o.fs.(embed.FS)
+ // any loader backed by an fs.FS or an os.Root consumes forward-slash paths on every
+ // platform, so it must not go through the windows-native file:// preprocessing below.
+ isFSBacked := o.fs != nil || o.root != ""
return func(p string) ([]byte, error) {
upth, err := url.PathUnescape(p)
@@ -67,14 +74,20 @@ func LoadStrategy(pth string, local, remote func(string) ([]byte, error), opts .
}
cpth, hasPrefix := strings.CutPrefix(upth, "file://")
- if !hasPrefix || isEmbedFS || runtime.GOOS != "windows" {
+ if !hasPrefix || isFSBacked || runtime.GOOS != "windows" {
// crude processing: trim the file:// prefix. This leaves full URIs with a host with a (mostly) unexpected result
// regular file path provided: just normalize slashes
if isEmbedFS {
- // on windows, we need to slash the path if FS is an embed FS.
+ // embed.FS always uses "/" as separator, even on windows, and rejects leading "./" or "/".
return local(strings.TrimLeft(filepath.ToSlash(cpth), "./")) // remove invalid leading characters for embed FS
}
+ if isFSBacked {
+ // other fs.FS (e.g. os.DirFS) and os.Root loaders also use "/" on every platform.
+ // Escaping paths (absolute, "..", escaping symlinks) are rejected by the loader, not rewritten here.
+ return local(filepath.ToSlash(cpth))
+ }
+
return local(filepath.FromSlash(cpth))
}
@@ -113,6 +126,21 @@ func LoadStrategy(pth string, local, remote func(string) ([]byte, error), opts .
}
}
+// hasHTTPScheme reports whether pth is an absolute URL with an http or https scheme,
+// selecting the remote loader. The comparison is case-insensitive, as URL schemes are.
+//
+// Requiring the "://" separator (rather than a bare "http" prefix) avoids misrouting a
+// local file whose name merely starts with "http" (e.g. "httpbin.json") to the remote loader.
+func hasHTTPScheme(pth string) bool {
+ for _, scheme := range [...]string{"http://", "https://"} {
+ if len(pth) >= len(scheme) && strings.EqualFold(pth[:len(scheme)], scheme) {
+ return true
+ }
+ }
+
+ return false
+}
+
func loadHTTPBytes(opts ...Option) func(path string) ([]byte, error) {
o := optionsWithDefaults(opts)
diff --git a/vendor/github.com/go-openapi/swag/loading/options.go b/vendor/github.com/go-openapi/swag/loading/options.go
index 6674ac69e62..2c128231728 100644
--- a/vendor/github.com/go-openapi/swag/loading/options.go
+++ b/vendor/github.com/go-openapi/swag/loading/options.go
@@ -4,6 +4,7 @@
package loading
import (
+ "errors"
"io/fs"
"net/http"
"os"
@@ -23,7 +24,8 @@ type (
}
fileOptions struct {
- fs fs.ReadFileFS
+ fs fs.ReadFileFS
+ root string // when non-empty, local reads are confined to this directory via os.Root
}
options struct {
@@ -33,6 +35,20 @@ type (
)
func (fo fileOptions) ReadFileFunc() func(string) ([]byte, error) {
+ if fo.root != "" {
+ root := fo.root
+
+ return func(name string) ([]byte, error) {
+ r, err := os.OpenRoot(root)
+ if err != nil {
+ return nil, errors.Join(err, ErrLoader)
+ }
+ defer func() { _ = r.Close() }()
+
+ return r.ReadFile(name)
+ }
+ }
+
if fo.fs == nil {
return os.ReadFile
}
@@ -87,8 +103,15 @@ func WithHTTPClient(client *http.Client) Option {
// By default, the file system is the one provided by the os package.
//
// For example, this may be set to consume from an embedded file system, or a rooted FS.
+//
+// WithFS and [WithRoot] are mutually exclusive: the last one applied wins.
+//
+// Security note: a file system built from [os.DirFS] confines paths but does NOT protect
+// against symlinks that escape the root. To load from a directory derived from untrusted
+// input, prefer [WithRoot], which is symlink-escape resistant.
func WithFS(filesystem fs.FS) Option {
return func(o *options) {
+ o.root = "" // last-wins vs WithRoot
if rfs, ok := filesystem.(fs.ReadFileFS); ok {
o.fs = rfs
@@ -98,6 +121,28 @@ func WithFS(filesystem fs.FS) Option {
}
}
+// WithRoot confines local file loading to dir.
+//
+// Every requested path is resolved relative to dir, and any path that would escape dir —
+// whether through an absolute path, ".." traversal, or a symlink pointing outside dir — is
+// rejected. This is built on [os.Root] and is therefore resistant to the symlink escapes
+// that a plain [os.DirFS] does not prevent.
+//
+// WithRoot is the recommended option when loading specs from a location derived from
+// untrusted input. It applies to local loading only and has no effect on remote
+// (http/https) loading. WithRoot and [WithFS] are mutually exclusive: the last one applied
+// wins.
+//
+// Note: [os.Root] confines path resolution but does not, by itself, protect against
+// traversal of mount/bind boundaries, /proc special files, or device files. Point WithRoot
+// at a directory that holds only the documents you intend to expose.
+func WithRoot(dir string) Option {
+ return func(o *options) {
+ o.root = dir
+ o.fs = nil // last-wins vs WithFS
+ }
+}
+
type readFileFS struct {
fs.FS
}
diff --git a/vendor/github.com/go-openapi/validate/CONTRIBUTORS.md b/vendor/github.com/go-openapi/validate/CONTRIBUTORS.md
index 7b79b765dc3..0f5497c8bbf 100644
--- a/vendor/github.com/go-openapi/validate/CONTRIBUTORS.md
+++ b/vendor/github.com/go-openapi/validate/CONTRIBUTORS.md
@@ -4,12 +4,12 @@
| Total Contributors | Total Contributions |
| --- | --- |
-| 31 | 295 |
+| 31 | 305 |
| Username | All Time Contribution Count | All Commits |
| --- | --- | --- |
| @casualjim | 169 | |
-| @fredbi | 58 | |
+| @fredbi | 68 | |
| @sttts | 11 | |
| @youyuanwu | 9 | |
| @keramix | 8 | |
@@ -40,4 +40,4 @@
| @dadgar | 1 | |
| @elakito | 1 | |
- _this file was generated by the [Contributors GitHub Action](https://github.com/github/contributors)_
+ _this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_
diff --git a/vendor/github.com/go-openapi/validate/README.md b/vendor/github.com/go-openapi/validate/README.md
index fec42b7c6ed..b814a2ef126 100644
--- a/vendor/github.com/go-openapi/validate/README.md
+++ b/vendor/github.com/go-openapi/validate/README.md
@@ -18,12 +18,9 @@ A validator for OpenAPI v2 specifications and JSON schema draft 4.
* **2025-12-19** : new community chat on discord
* a new discord community channel is available to be notified of changes and support users
- * our venerable Slack channel remains open, and will be eventually discontinued on **2026-03-31**
You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url]
-Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url]
-
## Status
API is stable.
@@ -75,9 +72,9 @@ This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
## Other documentation
* [All-time contributors](./CONTRIBUTORS.md)
-* [Contributing guidelines](.github/CONTRIBUTING.md)
-* [Maintainers documentation](docs/MAINTAINERS.md)
-* [Code style](docs/STYLE.md)
+* [Contributing guidelines][contributing-doc-site]
+* [Maintainers documentation][maintainers-doc-site]
+* [Code style][style-doc-site]
## Cutting a new release
@@ -108,11 +105,8 @@ Maintainers can cut a new release by either:
[godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/validate
[godoc-url]: http://pkg.go.dev/github.com/go-openapi/validate
-[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png
-[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM
-[slack-url]: https://goswagger.slack.com/archives/C04R30YMU
[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue
-[discord-url]: https://discord.gg/twZ9BwT3
+[discord-url]: https://discord.gg/FfnFYaC3k5
[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
@@ -122,3 +116,7 @@ Maintainers can cut a new release by either:
[goversion-url]: https://github.com/go-openapi/validate/blob/master/go.mod
[top-badge]: https://img.shields.io/github/languages/top/go-openapi/validate
[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/validate/latest
+
+[contributing-doc-site]: https://go-openapi.github.io/doc-site/contributing/contributing/index.html
+[maintainers-doc-site]: https://go-openapi.github.io/doc-site/maintainers/index.html
+[style-doc-site]: https://go-openapi.github.io/doc-site/contributing/style/index.html
diff --git a/vendor/github.com/go-openapi/validate/spec.go b/vendor/github.com/go-openapi/validate/spec.go
index b85432f92b1..0849e47ea58 100644
--- a/vendor/github.com/go-openapi/validate/spec.go
+++ b/vendor/github.com/go-openapi/validate/spec.go
@@ -146,7 +146,8 @@ func (s *SpecValidator) Validate(data any) (*Result, *Result) {
errs.Merge(s.validateNonEmptyPathParamNames())
// errs.Merge(s.validateRefNoSibling()) // warning only
- errs.Merge(s.validateReferenced()) // warning only
+ errs.Merge(s.validateReferenced()) // warning only
+ errs.Merge(s.validateDubiousRefs()) // warning only
return errs, warnings
}
@@ -553,8 +554,12 @@ DEFINITIONS:
if schema.Required != nil { // Safeguard
for _, pn := range schema.Required {
red := s.validateRequiredProperties(pn, d, &schema) //#nosec
+ // NOTE: capture validity before merging: Merge may redeem `red` to the
+ // pool (wantsRedeemOnMerge), after which reading it races with a concurrent
+ // BorrowResult().cleared() in another goroutine sharing the global pool.
+ isValid := red.IsValid()
res.Merge(red)
- if !red.IsValid() && !s.Options.ContinueOnErrors {
+ if !isValid && !s.Options.ContinueOnErrors {
break DEFINITIONS // there is an error, let's stop that bleeding
}
}
diff --git a/vendor/github.com/go-openapi/validate/spec_messages.go b/vendor/github.com/go-openapi/validate/spec_messages.go
index 42ce3602852..eeb8a869518 100644
--- a/vendor/github.com/go-openapi/validate/spec_messages.go
+++ b/vendor/github.com/go-openapi/validate/spec_messages.go
@@ -177,6 +177,18 @@ const (
// UnusedResponseWarning ...
UnusedResponseWarning = "response %q is not used anywhere"
+ // DubiousAbsoluteRefWarning flags a $ref pointing to an absolute local file location that escapes the
+ // spec's base path. Absolute local references are legitimate when they stay beneath the base path
+ // (flattening/expansion introduces such anchors for cyclical $refs), but an absolute reference that
+ // escapes the base path - or a file:// reference in a spec with no known base - may indicate an
+ // unsafe or adversarial spec.
+ DubiousAbsoluteRefWarning = "$ref %q points to an absolute or local file location that escapes the spec's base path: this may be unsafe with adversarial specs"
+
+ // DubiousMultipleHostsWarning flags a spec whose remote $refs resolve to several distinct hosts.
+ // A single consistent remote host is common and legitimate; references spread across multiple hosts
+ // may indicate an unsafe or adversarial spec.
+ DubiousMultipleHostsWarning = "$ref values point to %d distinct remote hosts (%s): a spec referencing multiple hosts may be unsafe"
+
InvalidObject = "expected an object in %q.%s"
)
@@ -404,3 +416,11 @@ func someParametersBrokenMsg(path, method, operationID string) errors.Error {
func refShouldNotHaveSiblingsMsg(path, operationID string) errors.Error {
return errors.New(errors.CompositeErrorCode, RefShouldNotHaveSiblingsWarning, operationID, path)
}
+
+func dubiousAbsoluteRefMsg(ref string) errors.Error {
+ return errors.New(errors.CompositeErrorCode, DubiousAbsoluteRefWarning, ref)
+}
+
+func dubiousMultipleHostsMsg(count int, hosts string) errors.Error {
+ return errors.New(errors.CompositeErrorCode, DubiousMultipleHostsWarning, count, hosts)
+}
diff --git a/vendor/github.com/go-openapi/validate/spec_ref_warnings.go b/vendor/github.com/go-openapi/validate/spec_ref_warnings.go
new file mode 100644
index 00000000000..49c72314c94
--- /dev/null
+++ b/vendor/github.com/go-openapi/validate/spec_ref_warnings.go
@@ -0,0 +1,209 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package validate
+
+import (
+ "net/url"
+ "path"
+ "sort"
+ "strings"
+
+ "github.com/go-openapi/spec"
+)
+
+// minDistinctHostsToWarn is the number of distinct remote hosts among $refs at or above which
+// Rule 2 emits a host-spread warning. A single consistent remote host is legitimate.
+const minDistinctHostsToWarn = 2
+
+// validateDubiousRefs emits warnings (never errors) when $ref locations match patterns
+// that may indicate an unsafe or adversarial spec. It inspects refs as authored, on the
+// UNEXPANDED spec, so it must run before expansion flattens them away.
+//
+// Two rules are applied over s.analyzer.AllRefs():
+//
+// - Rule 1 (absolute local escape): a $ref pointing to an absolute local file location
+// (file:// scheme, a Unix absolute path, or a Windows drive path such as C:\) is dubious
+// UNLESS it stays beneath the spec's base path. Absolute refs beneath the base are
+// legitimate: flattening/expansion in go-openapi/spec and analysis introduces absolute
+// anchors to resolve cyclical $refs. Relative and fragment-only refs are always exempt.
+//
+// - Rule 2 (host spread): when remote (http/https, or protocol-relative) refs resolve to
+// two or more distinct hosts, a single aggregate warning lists them. A single consistent
+// remote host is common and legitimate, so it is not flagged.
+//
+// All findings are warnings: they do not affect validity (see Result.IsValid).
+func (s *SpecValidator) validateDubiousRefs() *Result {
+ res := pools.poolOfResults.BorrowResult()
+
+ baseDir, hasBase := s.localBaseDir()
+
+ remoteHosts := make(map[string]struct{})
+ for _, r := range s.analyzer.AllRefs() {
+ u := r.GetURL()
+ if u == nil { // Safeguard: a valid spec always yields parseable refs
+ continue
+ }
+
+ // Rule 1: absolute local reference escaping the base path.
+ if refPath, isLocalAbs := absoluteLocalRefPath(r, u); isLocalAbs {
+ if !hasBase || !isBeneathBase(refPath, baseDir) {
+ res.AddWarnings(dubiousAbsoluteRefMsg(r.String()))
+ }
+ continue
+ }
+
+ // Rule 2: gather remote hosts (http/https and protocol-relative //host/...).
+ if host := remoteRefHost(u); host != "" {
+ remoteHosts[host] = struct{}{}
+ }
+ }
+
+ if len(remoteHosts) >= minDistinctHostsToWarn {
+ hosts := make([]string, 0, len(remoteHosts))
+ for h := range remoteHosts {
+ hosts = append(hosts, h)
+ }
+ sort.Strings(hosts)
+ res.AddWarnings(dubiousMultipleHostsMsg(len(hosts), strings.Join(hosts, ", ")))
+ }
+
+ return res
+}
+
+// absoluteLocalRefPath reports whether r is an absolute LOCAL file reference and, if so,
+// returns the cleaned path it points to (without scheme/fragment, drive letter lower-cased).
+//
+// Classification order matters (see the empirical jsonreference flag behavior):
+// - file:// scheme is local, including UNC file://host/share (inherently dubious).
+// - a non-empty Host with no file scheme means remote (http/https or protocol-relative
+// //host/path) - NOT local; handled by Rule 2. This must be checked before the Unix
+// branch, because protocol-relative refs also set HasFullFilePath.
+// - len(u.Scheme) == 1 is a Windows drive path (C:\ or C:/), whose drive+path land in
+// Scheme/Opaque/Path rather than Path. Checked before the Unix branch because C:/x also
+// sets HasFullFilePath, and reconstructed from the authored ref string to keep the drive.
+// - !r.HasFullURL && r.HasFullFilePath is a plain Unix absolute path (/abs/models.json).
+//
+// Relative (./x.json) and fragment-only (#/definitions/X) refs return false.
+func absoluteLocalRefPath(r spec.Ref, u *url.URL) (string, bool) {
+ switch {
+ case r.HasFileScheme:
+ return fileRefPath(u), true
+ case u.Host != "":
+ // Remote (http/https) or protocol-relative //host/path: handled by Rule 2.
+ return "", false
+ case len(u.Scheme) == 1:
+ // Windows drive letter: reconstruct from the authored ref string.
+ return cleanRefPath(r.String()), true
+ case !r.HasFullURL && r.HasFullFilePath:
+ return cleanRefPath(u.Path), true
+ default:
+ return "", false
+ }
+}
+
+// remoteRefHost returns the host of a remote reference (http/https), or of a protocol-relative
+// reference (//host/path). It returns "" for local and fragment-only refs. file:// hosts (UNC)
+// are deliberately excluded: those are handled as local-absolute refs by Rule 1.
+func remoteRefHost(u *url.URL) string {
+ switch u.Scheme {
+ case "http", "https":
+ return u.Host
+ case "":
+ // Protocol-relative //host/path: empty scheme but a host is present.
+ return u.Host
+ default:
+ return ""
+ }
+}
+
+// localBaseDir returns the directory of the spec file, slash-normalized, when the spec was
+// loaded from a local path. It returns ok=false when the base is unknown (in-memory spec) or
+// remote (http/https), in which case absolute-local refs cannot be proven beneath a base and
+// are treated as dubious.
+func (s *SpecValidator) localBaseDir() (string, bool) {
+ specPath := s.spec.SpecFilePath()
+ if specPath == "" {
+ return "", false
+ }
+
+ // Strip a file:// scheme if present; reject remote bases.
+ if u, err := url.Parse(specPath); err == nil && u.Scheme != "" {
+ switch {
+ case u.Scheme == "file":
+ specPath = u.Path
+ case len(u.Scheme) == 1: // Windows drive letter, treat as local
+ // keep specPath as-is (authored path)
+ default: // http, https, ... : no local base
+ return "", false
+ }
+ }
+
+ return path.Dir(cleanRefPath(specPath)), true
+}
+
+// isBeneathBase reports whether the cleaned target path is located within baseDir, i.e. it does
+// not escape baseDir via "..". Comparison is purely lexical on cleaned paths, which is sufficient
+// (and cross-platform safe) for a non-fatal warning. Both sides are expected to already be
+// cleanRefPath-normalized (slashes, drive-letter case).
+func isBeneathBase(target, baseDir string) bool {
+ if baseDir == "" {
+ return false
+ }
+ if target == baseDir {
+ return true
+ }
+ if !strings.HasSuffix(baseDir, "/") {
+ baseDir += "/"
+ }
+ return strings.HasPrefix(target, baseDir)
+}
+
+// fileRefPath extracts the local path a file:// reference points to, accounting for the way
+// Windows file URLs parse:
+// - file:///abs/x -> /abs/x (empty host)
+// - file:///C:/dir/x -> /c:/dir/x (empty host; drive sits in the path)
+// - file://D:/a/x -> d:/a/x (drive letter lands in Host, rejoin it)
+// - file://host/share -> /host/share/x (real UNC host kept visible so it cannot match a
+// local base and stays flagged as dubious)
+func fileRefPath(u *url.URL) string {
+ switch {
+ case u.Host == "":
+ return cleanRefPath(u.Path)
+ case isDriveHost(u.Host):
+ // Windows path authored as file://D:/... : the drive landed in Host (e.g. "d:").
+ return cleanRefPath(u.Host + u.Path)
+ default:
+ // Real remote/UNC host: keep it in the path so it never matches a local base.
+ return cleanRefPath("//" + u.Host + u.Path)
+ }
+}
+
+// isDriveHost reports whether a URL host is actually a Windows drive letter (e.g. "d:"), which
+// happens when a Windows path is authored as a two-slash file URL: file://D:/path.
+func isDriveHost(host string) bool {
+ h := strings.TrimSuffix(host, ":")
+ if len(h) != 1 {
+ return false
+ }
+ c := h[0]
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+}
+
+// cleanRefPath normalizes a ref or base path for lexical comparison: backslashes to forward
+// slashes, path.Clean, and a lower-cased leading Windows drive letter (matching the behavior of
+// go-openapi/spec's normalizer). Plain Unix paths are unaffected, preserving case-sensitivity.
+func cleanRefPath(p string) string {
+ p = path.Clean(strings.ReplaceAll(p, `\`, `/`))
+ switch {
+ case len(p) >= 2 && p[1] == ':':
+ // drive-letter form: C:/dir -> c:/dir
+ p = strings.ToLower(p[:1]) + p[1:]
+ case len(p) >= 3 && p[0] == '/' && p[2] == ':':
+ // slash-prefixed drive form from canonical file:// URLs: /C:/dir -> c:/dir.
+ // The leading slash is dropped so this matches the base path derived from
+ // SpecFilePath (which has no leading slash), and the bare-drive form.
+ p = strings.ToLower(p[1:2]) + p[2:]
+ }
+ return p
+}
diff --git a/vendor/github.com/google/btree/LICENSE b/vendor/github.com/google/btree/LICENSE
new file mode 100644
index 00000000000..d6456956733
--- /dev/null
+++ b/vendor/github.com/google/btree/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/google/btree/README.md b/vendor/github.com/google/btree/README.md
new file mode 100644
index 00000000000..eab5dbf7ba7
--- /dev/null
+++ b/vendor/github.com/google/btree/README.md
@@ -0,0 +1,10 @@
+# BTree implementation for Go
+
+This package provides an in-memory B-Tree implementation for Go, useful as
+an ordered, mutable data structure.
+
+The API is based off of the wonderful
+http://godoc.org/github.com/petar/GoLLRB/llrb, and is meant to allow btree to
+act as a drop-in replacement for gollrb trees.
+
+See http://godoc.org/github.com/google/btree for documentation.
diff --git a/vendor/github.com/google/btree/btree.go b/vendor/github.com/google/btree/btree.go
new file mode 100644
index 00000000000..6f5184fef7d
--- /dev/null
+++ b/vendor/github.com/google/btree/btree.go
@@ -0,0 +1,893 @@
+// Copyright 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//go:build !go1.18
+// +build !go1.18
+
+// Package btree implements in-memory B-Trees of arbitrary degree.
+//
+// btree implements an in-memory B-Tree for use as an ordered data structure.
+// It is not meant for persistent storage solutions.
+//
+// It has a flatter structure than an equivalent red-black or other binary tree,
+// which in some cases yields better memory usage and/or performance.
+// See some discussion on the matter here:
+// http://google-opensource.blogspot.com/2013/01/c-containers-that-save-memory-and-time.html
+// Note, though, that this project is in no way related to the C++ B-Tree
+// implementation written about there.
+//
+// Within this tree, each node contains a slice of items and a (possibly nil)
+// slice of children. For basic numeric values or raw structs, this can cause
+// efficiency differences when compared to equivalent C++ template code that
+// stores values in arrays within the node:
+// * Due to the overhead of storing values as interfaces (each
+// value needs to be stored as the value itself, then 2 words for the
+// interface pointing to that value and its type), resulting in higher
+// memory use.
+// * Since interfaces can point to values anywhere in memory, values are
+// most likely not stored in contiguous blocks, resulting in a higher
+// number of cache misses.
+// These issues don't tend to matter, though, when working with strings or other
+// heap-allocated structures, since C++-equivalent structures also must store
+// pointers and also distribute their values across the heap.
+//
+// This implementation is designed to be a drop-in replacement to gollrb.LLRB
+// trees, (http://github.com/petar/gollrb), an excellent and probably the most
+// widely used ordered tree implementation in the Go ecosystem currently.
+// Its functions, therefore, exactly mirror those of
+// llrb.LLRB where possible. Unlike gollrb, though, we currently don't
+// support storing multiple equivalent values.
+package btree
+
+import (
+ "fmt"
+ "io"
+ "sort"
+ "strings"
+ "sync"
+)
+
+// Item represents a single object in the tree.
+type Item interface {
+ // Less tests whether the current item is less than the given argument.
+ //
+ // This must provide a strict weak ordering.
+ // If !a.Less(b) && !b.Less(a), we treat this to mean a == b (i.e. we can only
+ // hold one of either a or b in the tree).
+ Less(than Item) bool
+}
+
+const (
+ DefaultFreeListSize = 32
+)
+
+var (
+ nilItems = make(items, 16)
+ nilChildren = make(children, 16)
+)
+
+// FreeList represents a free list of btree nodes. By default each
+// BTree has its own FreeList, but multiple BTrees can share the same
+// FreeList.
+// Two Btrees using the same freelist are safe for concurrent write access.
+type FreeList struct {
+ mu sync.Mutex
+ freelist []*node
+}
+
+// NewFreeList creates a new free list.
+// size is the maximum size of the returned free list.
+func NewFreeList(size int) *FreeList {
+ return &FreeList{freelist: make([]*node, 0, size)}
+}
+
+func (f *FreeList) newNode() (n *node) {
+ f.mu.Lock()
+ index := len(f.freelist) - 1
+ if index < 0 {
+ f.mu.Unlock()
+ return new(node)
+ }
+ n = f.freelist[index]
+ f.freelist[index] = nil
+ f.freelist = f.freelist[:index]
+ f.mu.Unlock()
+ return
+}
+
+// freeNode adds the given node to the list, returning true if it was added
+// and false if it was discarded.
+func (f *FreeList) freeNode(n *node) (out bool) {
+ f.mu.Lock()
+ if len(f.freelist) < cap(f.freelist) {
+ f.freelist = append(f.freelist, n)
+ out = true
+ }
+ f.mu.Unlock()
+ return
+}
+
+// ItemIterator allows callers of Ascend* to iterate in-order over portions of
+// the tree. When this function returns false, iteration will stop and the
+// associated Ascend* function will immediately return.
+type ItemIterator func(i Item) bool
+
+// New creates a new B-Tree with the given degree.
+//
+// New(2), for example, will create a 2-3-4 tree (each node contains 1-3 items
+// and 2-4 children).
+func New(degree int) *BTree {
+ return NewWithFreeList(degree, NewFreeList(DefaultFreeListSize))
+}
+
+// NewWithFreeList creates a new B-Tree that uses the given node free list.
+func NewWithFreeList(degree int, f *FreeList) *BTree {
+ if degree <= 1 {
+ panic("bad degree")
+ }
+ return &BTree{
+ degree: degree,
+ cow: ©OnWriteContext{freelist: f},
+ }
+}
+
+// items stores items in a node.
+type items []Item
+
+// insertAt inserts a value into the given index, pushing all subsequent values
+// forward.
+func (s *items) insertAt(index int, item Item) {
+ *s = append(*s, nil)
+ if index < len(*s) {
+ copy((*s)[index+1:], (*s)[index:])
+ }
+ (*s)[index] = item
+}
+
+// removeAt removes a value at a given index, pulling all subsequent values
+// back.
+func (s *items) removeAt(index int) Item {
+ item := (*s)[index]
+ copy((*s)[index:], (*s)[index+1:])
+ (*s)[len(*s)-1] = nil
+ *s = (*s)[:len(*s)-1]
+ return item
+}
+
+// pop removes and returns the last element in the list.
+func (s *items) pop() (out Item) {
+ index := len(*s) - 1
+ out = (*s)[index]
+ (*s)[index] = nil
+ *s = (*s)[:index]
+ return
+}
+
+// truncate truncates this instance at index so that it contains only the
+// first index items. index must be less than or equal to length.
+func (s *items) truncate(index int) {
+ var toClear items
+ *s, toClear = (*s)[:index], (*s)[index:]
+ for len(toClear) > 0 {
+ toClear = toClear[copy(toClear, nilItems):]
+ }
+}
+
+// find returns the index where the given item should be inserted into this
+// list. 'found' is true if the item already exists in the list at the given
+// index.
+func (s items) find(item Item) (index int, found bool) {
+ i := sort.Search(len(s), func(i int) bool {
+ return item.Less(s[i])
+ })
+ if i > 0 && !s[i-1].Less(item) {
+ return i - 1, true
+ }
+ return i, false
+}
+
+// children stores child nodes in a node.
+type children []*node
+
+// insertAt inserts a value into the given index, pushing all subsequent values
+// forward.
+func (s *children) insertAt(index int, n *node) {
+ *s = append(*s, nil)
+ if index < len(*s) {
+ copy((*s)[index+1:], (*s)[index:])
+ }
+ (*s)[index] = n
+}
+
+// removeAt removes a value at a given index, pulling all subsequent values
+// back.
+func (s *children) removeAt(index int) *node {
+ n := (*s)[index]
+ copy((*s)[index:], (*s)[index+1:])
+ (*s)[len(*s)-1] = nil
+ *s = (*s)[:len(*s)-1]
+ return n
+}
+
+// pop removes and returns the last element in the list.
+func (s *children) pop() (out *node) {
+ index := len(*s) - 1
+ out = (*s)[index]
+ (*s)[index] = nil
+ *s = (*s)[:index]
+ return
+}
+
+// truncate truncates this instance at index so that it contains only the
+// first index children. index must be less than or equal to length.
+func (s *children) truncate(index int) {
+ var toClear children
+ *s, toClear = (*s)[:index], (*s)[index:]
+ for len(toClear) > 0 {
+ toClear = toClear[copy(toClear, nilChildren):]
+ }
+}
+
+// node is an internal node in a tree.
+//
+// It must at all times maintain the invariant that either
+// * len(children) == 0, len(items) unconstrained
+// * len(children) == len(items) + 1
+type node struct {
+ items items
+ children children
+ cow *copyOnWriteContext
+}
+
+func (n *node) mutableFor(cow *copyOnWriteContext) *node {
+ if n.cow == cow {
+ return n
+ }
+ out := cow.newNode()
+ if cap(out.items) >= len(n.items) {
+ out.items = out.items[:len(n.items)]
+ } else {
+ out.items = make(items, len(n.items), cap(n.items))
+ }
+ copy(out.items, n.items)
+ // Copy children
+ if cap(out.children) >= len(n.children) {
+ out.children = out.children[:len(n.children)]
+ } else {
+ out.children = make(children, len(n.children), cap(n.children))
+ }
+ copy(out.children, n.children)
+ return out
+}
+
+func (n *node) mutableChild(i int) *node {
+ c := n.children[i].mutableFor(n.cow)
+ n.children[i] = c
+ return c
+}
+
+// split splits the given node at the given index. The current node shrinks,
+// and this function returns the item that existed at that index and a new node
+// containing all items/children after it.
+func (n *node) split(i int) (Item, *node) {
+ item := n.items[i]
+ next := n.cow.newNode()
+ next.items = append(next.items, n.items[i+1:]...)
+ n.items.truncate(i)
+ if len(n.children) > 0 {
+ next.children = append(next.children, n.children[i+1:]...)
+ n.children.truncate(i + 1)
+ }
+ return item, next
+}
+
+// maybeSplitChild checks if a child should be split, and if so splits it.
+// Returns whether or not a split occurred.
+func (n *node) maybeSplitChild(i, maxItems int) bool {
+ if len(n.children[i].items) < maxItems {
+ return false
+ }
+ first := n.mutableChild(i)
+ item, second := first.split(maxItems / 2)
+ n.items.insertAt(i, item)
+ n.children.insertAt(i+1, second)
+ return true
+}
+
+// insert inserts an item into the subtree rooted at this node, making sure
+// no nodes in the subtree exceed maxItems items. Should an equivalent item be
+// be found/replaced by insert, it will be returned.
+func (n *node) insert(item Item, maxItems int) Item {
+ i, found := n.items.find(item)
+ if found {
+ out := n.items[i]
+ n.items[i] = item
+ return out
+ }
+ if len(n.children) == 0 {
+ n.items.insertAt(i, item)
+ return nil
+ }
+ if n.maybeSplitChild(i, maxItems) {
+ inTree := n.items[i]
+ switch {
+ case item.Less(inTree):
+ // no change, we want first split node
+ case inTree.Less(item):
+ i++ // we want second split node
+ default:
+ out := n.items[i]
+ n.items[i] = item
+ return out
+ }
+ }
+ return n.mutableChild(i).insert(item, maxItems)
+}
+
+// get finds the given key in the subtree and returns it.
+func (n *node) get(key Item) Item {
+ i, found := n.items.find(key)
+ if found {
+ return n.items[i]
+ } else if len(n.children) > 0 {
+ return n.children[i].get(key)
+ }
+ return nil
+}
+
+// min returns the first item in the subtree.
+func min(n *node) Item {
+ if n == nil {
+ return nil
+ }
+ for len(n.children) > 0 {
+ n = n.children[0]
+ }
+ if len(n.items) == 0 {
+ return nil
+ }
+ return n.items[0]
+}
+
+// max returns the last item in the subtree.
+func max(n *node) Item {
+ if n == nil {
+ return nil
+ }
+ for len(n.children) > 0 {
+ n = n.children[len(n.children)-1]
+ }
+ if len(n.items) == 0 {
+ return nil
+ }
+ return n.items[len(n.items)-1]
+}
+
+// toRemove details what item to remove in a node.remove call.
+type toRemove int
+
+const (
+ removeItem toRemove = iota // removes the given item
+ removeMin // removes smallest item in the subtree
+ removeMax // removes largest item in the subtree
+)
+
+// remove removes an item from the subtree rooted at this node.
+func (n *node) remove(item Item, minItems int, typ toRemove) Item {
+ var i int
+ var found bool
+ switch typ {
+ case removeMax:
+ if len(n.children) == 0 {
+ return n.items.pop()
+ }
+ i = len(n.items)
+ case removeMin:
+ if len(n.children) == 0 {
+ return n.items.removeAt(0)
+ }
+ i = 0
+ case removeItem:
+ i, found = n.items.find(item)
+ if len(n.children) == 0 {
+ if found {
+ return n.items.removeAt(i)
+ }
+ return nil
+ }
+ default:
+ panic("invalid type")
+ }
+ // If we get to here, we have children.
+ if len(n.children[i].items) <= minItems {
+ return n.growChildAndRemove(i, item, minItems, typ)
+ }
+ child := n.mutableChild(i)
+ // Either we had enough items to begin with, or we've done some
+ // merging/stealing, because we've got enough now and we're ready to return
+ // stuff.
+ if found {
+ // The item exists at index 'i', and the child we've selected can give us a
+ // predecessor, since if we've gotten here it's got > minItems items in it.
+ out := n.items[i]
+ // We use our special-case 'remove' call with typ=maxItem to pull the
+ // predecessor of item i (the rightmost leaf of our immediate left child)
+ // and set it into where we pulled the item from.
+ n.items[i] = child.remove(nil, minItems, removeMax)
+ return out
+ }
+ // Final recursive call. Once we're here, we know that the item isn't in this
+ // node and that the child is big enough to remove from.
+ return child.remove(item, minItems, typ)
+}
+
+// growChildAndRemove grows child 'i' to make sure it's possible to remove an
+// item from it while keeping it at minItems, then calls remove to actually
+// remove it.
+//
+// Most documentation says we have to do two sets of special casing:
+// 1) item is in this node
+// 2) item is in child
+// In both cases, we need to handle the two subcases:
+// A) node has enough values that it can spare one
+// B) node doesn't have enough values
+// For the latter, we have to check:
+// a) left sibling has node to spare
+// b) right sibling has node to spare
+// c) we must merge
+// To simplify our code here, we handle cases #1 and #2 the same:
+// If a node doesn't have enough items, we make sure it does (using a,b,c).
+// We then simply redo our remove call, and the second time (regardless of
+// whether we're in case 1 or 2), we'll have enough items and can guarantee
+// that we hit case A.
+func (n *node) growChildAndRemove(i int, item Item, minItems int, typ toRemove) Item {
+ if i > 0 && len(n.children[i-1].items) > minItems {
+ // Steal from left child
+ child := n.mutableChild(i)
+ stealFrom := n.mutableChild(i - 1)
+ stolenItem := stealFrom.items.pop()
+ child.items.insertAt(0, n.items[i-1])
+ n.items[i-1] = stolenItem
+ if len(stealFrom.children) > 0 {
+ child.children.insertAt(0, stealFrom.children.pop())
+ }
+ } else if i < len(n.items) && len(n.children[i+1].items) > minItems {
+ // steal from right child
+ child := n.mutableChild(i)
+ stealFrom := n.mutableChild(i + 1)
+ stolenItem := stealFrom.items.removeAt(0)
+ child.items = append(child.items, n.items[i])
+ n.items[i] = stolenItem
+ if len(stealFrom.children) > 0 {
+ child.children = append(child.children, stealFrom.children.removeAt(0))
+ }
+ } else {
+ if i >= len(n.items) {
+ i--
+ }
+ child := n.mutableChild(i)
+ // merge with right child
+ mergeItem := n.items.removeAt(i)
+ mergeChild := n.children.removeAt(i + 1).mutableFor(n.cow)
+ child.items = append(child.items, mergeItem)
+ child.items = append(child.items, mergeChild.items...)
+ child.children = append(child.children, mergeChild.children...)
+ n.cow.freeNode(mergeChild)
+ }
+ return n.remove(item, minItems, typ)
+}
+
+type direction int
+
+const (
+ descend = direction(-1)
+ ascend = direction(+1)
+)
+
+// iterate provides a simple method for iterating over elements in the tree.
+//
+// When ascending, the 'start' should be less than 'stop' and when descending,
+// the 'start' should be greater than 'stop'. Setting 'includeStart' to true
+// will force the iterator to include the first item when it equals 'start',
+// thus creating a "greaterOrEqual" or "lessThanEqual" rather than just a
+// "greaterThan" or "lessThan" queries.
+func (n *node) iterate(dir direction, start, stop Item, includeStart bool, hit bool, iter ItemIterator) (bool, bool) {
+ var ok, found bool
+ var index int
+ switch dir {
+ case ascend:
+ if start != nil {
+ index, _ = n.items.find(start)
+ }
+ for i := index; i < len(n.items); i++ {
+ if len(n.children) > 0 {
+ if hit, ok = n.children[i].iterate(dir, start, stop, includeStart, hit, iter); !ok {
+ return hit, false
+ }
+ }
+ if !includeStart && !hit && start != nil && !start.Less(n.items[i]) {
+ hit = true
+ continue
+ }
+ hit = true
+ if stop != nil && !n.items[i].Less(stop) {
+ return hit, false
+ }
+ if !iter(n.items[i]) {
+ return hit, false
+ }
+ }
+ if len(n.children) > 0 {
+ if hit, ok = n.children[len(n.children)-1].iterate(dir, start, stop, includeStart, hit, iter); !ok {
+ return hit, false
+ }
+ }
+ case descend:
+ if start != nil {
+ index, found = n.items.find(start)
+ if !found {
+ index = index - 1
+ }
+ } else {
+ index = len(n.items) - 1
+ }
+ for i := index; i >= 0; i-- {
+ if start != nil && !n.items[i].Less(start) {
+ if !includeStart || hit || start.Less(n.items[i]) {
+ continue
+ }
+ }
+ if len(n.children) > 0 {
+ if hit, ok = n.children[i+1].iterate(dir, start, stop, includeStart, hit, iter); !ok {
+ return hit, false
+ }
+ }
+ if stop != nil && !stop.Less(n.items[i]) {
+ return hit, false // continue
+ }
+ hit = true
+ if !iter(n.items[i]) {
+ return hit, false
+ }
+ }
+ if len(n.children) > 0 {
+ if hit, ok = n.children[0].iterate(dir, start, stop, includeStart, hit, iter); !ok {
+ return hit, false
+ }
+ }
+ }
+ return hit, true
+}
+
+// Used for testing/debugging purposes.
+func (n *node) print(w io.Writer, level int) {
+ fmt.Fprintf(w, "%sNODE:%v\n", strings.Repeat(" ", level), n.items)
+ for _, c := range n.children {
+ c.print(w, level+1)
+ }
+}
+
+// BTree is an implementation of a B-Tree.
+//
+// BTree stores Item instances in an ordered structure, allowing easy insertion,
+// removal, and iteration.
+//
+// Write operations are not safe for concurrent mutation by multiple
+// goroutines, but Read operations are.
+type BTree struct {
+ degree int
+ length int
+ root *node
+ cow *copyOnWriteContext
+}
+
+// copyOnWriteContext pointers determine node ownership... a tree with a write
+// context equivalent to a node's write context is allowed to modify that node.
+// A tree whose write context does not match a node's is not allowed to modify
+// it, and must create a new, writable copy (IE: it's a Clone).
+//
+// When doing any write operation, we maintain the invariant that the current
+// node's context is equal to the context of the tree that requested the write.
+// We do this by, before we descend into any node, creating a copy with the
+// correct context if the contexts don't match.
+//
+// Since the node we're currently visiting on any write has the requesting
+// tree's context, that node is modifiable in place. Children of that node may
+// not share context, but before we descend into them, we'll make a mutable
+// copy.
+type copyOnWriteContext struct {
+ freelist *FreeList
+}
+
+// Clone clones the btree, lazily. Clone should not be called concurrently,
+// but the original tree (t) and the new tree (t2) can be used concurrently
+// once the Clone call completes.
+//
+// The internal tree structure of b is marked read-only and shared between t and
+// t2. Writes to both t and t2 use copy-on-write logic, creating new nodes
+// whenever one of b's original nodes would have been modified. Read operations
+// should have no performance degredation. Write operations for both t and t2
+// will initially experience minor slow-downs caused by additional allocs and
+// copies due to the aforementioned copy-on-write logic, but should converge to
+// the original performance characteristics of the original tree.
+func (t *BTree) Clone() (t2 *BTree) {
+ // Create two entirely new copy-on-write contexts.
+ // This operation effectively creates three trees:
+ // the original, shared nodes (old b.cow)
+ // the new b.cow nodes
+ // the new out.cow nodes
+ cow1, cow2 := *t.cow, *t.cow
+ out := *t
+ t.cow = &cow1
+ out.cow = &cow2
+ return &out
+}
+
+// maxItems returns the max number of items to allow per node.
+func (t *BTree) maxItems() int {
+ return t.degree*2 - 1
+}
+
+// minItems returns the min number of items to allow per node (ignored for the
+// root node).
+func (t *BTree) minItems() int {
+ return t.degree - 1
+}
+
+func (c *copyOnWriteContext) newNode() (n *node) {
+ n = c.freelist.newNode()
+ n.cow = c
+ return
+}
+
+type freeType int
+
+const (
+ ftFreelistFull freeType = iota // node was freed (available for GC, not stored in freelist)
+ ftStored // node was stored in the freelist for later use
+ ftNotOwned // node was ignored by COW, since it's owned by another one
+)
+
+// freeNode frees a node within a given COW context, if it's owned by that
+// context. It returns what happened to the node (see freeType const
+// documentation).
+func (c *copyOnWriteContext) freeNode(n *node) freeType {
+ if n.cow == c {
+ // clear to allow GC
+ n.items.truncate(0)
+ n.children.truncate(0)
+ n.cow = nil
+ if c.freelist.freeNode(n) {
+ return ftStored
+ } else {
+ return ftFreelistFull
+ }
+ } else {
+ return ftNotOwned
+ }
+}
+
+// ReplaceOrInsert adds the given item to the tree. If an item in the tree
+// already equals the given one, it is removed from the tree and returned.
+// Otherwise, nil is returned.
+//
+// nil cannot be added to the tree (will panic).
+func (t *BTree) ReplaceOrInsert(item Item) Item {
+ if item == nil {
+ panic("nil item being added to BTree")
+ }
+ if t.root == nil {
+ t.root = t.cow.newNode()
+ t.root.items = append(t.root.items, item)
+ t.length++
+ return nil
+ } else {
+ t.root = t.root.mutableFor(t.cow)
+ if len(t.root.items) >= t.maxItems() {
+ item2, second := t.root.split(t.maxItems() / 2)
+ oldroot := t.root
+ t.root = t.cow.newNode()
+ t.root.items = append(t.root.items, item2)
+ t.root.children = append(t.root.children, oldroot, second)
+ }
+ }
+ out := t.root.insert(item, t.maxItems())
+ if out == nil {
+ t.length++
+ }
+ return out
+}
+
+// Delete removes an item equal to the passed in item from the tree, returning
+// it. If no such item exists, returns nil.
+func (t *BTree) Delete(item Item) Item {
+ return t.deleteItem(item, removeItem)
+}
+
+// DeleteMin removes the smallest item in the tree and returns it.
+// If no such item exists, returns nil.
+func (t *BTree) DeleteMin() Item {
+ return t.deleteItem(nil, removeMin)
+}
+
+// DeleteMax removes the largest item in the tree and returns it.
+// If no such item exists, returns nil.
+func (t *BTree) DeleteMax() Item {
+ return t.deleteItem(nil, removeMax)
+}
+
+func (t *BTree) deleteItem(item Item, typ toRemove) Item {
+ if t.root == nil || len(t.root.items) == 0 {
+ return nil
+ }
+ t.root = t.root.mutableFor(t.cow)
+ out := t.root.remove(item, t.minItems(), typ)
+ if len(t.root.items) == 0 && len(t.root.children) > 0 {
+ oldroot := t.root
+ t.root = t.root.children[0]
+ t.cow.freeNode(oldroot)
+ }
+ if out != nil {
+ t.length--
+ }
+ return out
+}
+
+// AscendRange calls the iterator for every value in the tree within the range
+// [greaterOrEqual, lessThan), until iterator returns false.
+func (t *BTree) AscendRange(greaterOrEqual, lessThan Item, iterator ItemIterator) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(ascend, greaterOrEqual, lessThan, true, false, iterator)
+}
+
+// AscendLessThan calls the iterator for every value in the tree within the range
+// [first, pivot), until iterator returns false.
+func (t *BTree) AscendLessThan(pivot Item, iterator ItemIterator) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(ascend, nil, pivot, false, false, iterator)
+}
+
+// AscendGreaterOrEqual calls the iterator for every value in the tree within
+// the range [pivot, last], until iterator returns false.
+func (t *BTree) AscendGreaterOrEqual(pivot Item, iterator ItemIterator) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(ascend, pivot, nil, true, false, iterator)
+}
+
+// Ascend calls the iterator for every value in the tree within the range
+// [first, last], until iterator returns false.
+func (t *BTree) Ascend(iterator ItemIterator) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(ascend, nil, nil, false, false, iterator)
+}
+
+// DescendRange calls the iterator for every value in the tree within the range
+// [lessOrEqual, greaterThan), until iterator returns false.
+func (t *BTree) DescendRange(lessOrEqual, greaterThan Item, iterator ItemIterator) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(descend, lessOrEqual, greaterThan, true, false, iterator)
+}
+
+// DescendLessOrEqual calls the iterator for every value in the tree within the range
+// [pivot, first], until iterator returns false.
+func (t *BTree) DescendLessOrEqual(pivot Item, iterator ItemIterator) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(descend, pivot, nil, true, false, iterator)
+}
+
+// DescendGreaterThan calls the iterator for every value in the tree within
+// the range [last, pivot), until iterator returns false.
+func (t *BTree) DescendGreaterThan(pivot Item, iterator ItemIterator) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(descend, nil, pivot, false, false, iterator)
+}
+
+// Descend calls the iterator for every value in the tree within the range
+// [last, first], until iterator returns false.
+func (t *BTree) Descend(iterator ItemIterator) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(descend, nil, nil, false, false, iterator)
+}
+
+// Get looks for the key item in the tree, returning it. It returns nil if
+// unable to find that item.
+func (t *BTree) Get(key Item) Item {
+ if t.root == nil {
+ return nil
+ }
+ return t.root.get(key)
+}
+
+// Min returns the smallest item in the tree, or nil if the tree is empty.
+func (t *BTree) Min() Item {
+ return min(t.root)
+}
+
+// Max returns the largest item in the tree, or nil if the tree is empty.
+func (t *BTree) Max() Item {
+ return max(t.root)
+}
+
+// Has returns true if the given key is in the tree.
+func (t *BTree) Has(key Item) bool {
+ return t.Get(key) != nil
+}
+
+// Len returns the number of items currently in the tree.
+func (t *BTree) Len() int {
+ return t.length
+}
+
+// Clear removes all items from the btree. If addNodesToFreelist is true,
+// t's nodes are added to its freelist as part of this call, until the freelist
+// is full. Otherwise, the root node is simply dereferenced and the subtree
+// left to Go's normal GC processes.
+//
+// This can be much faster
+// than calling Delete on all elements, because that requires finding/removing
+// each element in the tree and updating the tree accordingly. It also is
+// somewhat faster than creating a new tree to replace the old one, because
+// nodes from the old tree are reclaimed into the freelist for use by the new
+// one, instead of being lost to the garbage collector.
+//
+// This call takes:
+// O(1): when addNodesToFreelist is false, this is a single operation.
+// O(1): when the freelist is already full, it breaks out immediately
+// O(freelist size): when the freelist is empty and the nodes are all owned
+// by this tree, nodes are added to the freelist until full.
+// O(tree size): when all nodes are owned by another tree, all nodes are
+// iterated over looking for nodes to add to the freelist, and due to
+// ownership, none are.
+func (t *BTree) Clear(addNodesToFreelist bool) {
+ if t.root != nil && addNodesToFreelist {
+ t.root.reset(t.cow)
+ }
+ t.root, t.length = nil, 0
+}
+
+// reset returns a subtree to the freelist. It breaks out immediately if the
+// freelist is full, since the only benefit of iterating is to fill that
+// freelist up. Returns true if parent reset call should continue.
+func (n *node) reset(c *copyOnWriteContext) bool {
+ for _, child := range n.children {
+ if !child.reset(c) {
+ return false
+ }
+ }
+ return c.freeNode(n) != ftFreelistFull
+}
+
+// Int implements the Item interface for integers.
+type Int int
+
+// Less returns true if int(a) < int(b).
+func (a Int) Less(b Item) bool {
+ return a < b.(Int)
+}
diff --git a/vendor/github.com/google/btree/btree_generic.go b/vendor/github.com/google/btree/btree_generic.go
new file mode 100644
index 00000000000..e44a0f48804
--- /dev/null
+++ b/vendor/github.com/google/btree/btree_generic.go
@@ -0,0 +1,1083 @@
+// Copyright 2014-2022 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//go:build go1.18
+// +build go1.18
+
+// In Go 1.18 and beyond, a BTreeG generic is created, and BTree is a specific
+// instantiation of that generic for the Item interface, with a backwards-
+// compatible API. Before go1.18, generics are not supported,
+// and BTree is just an implementation based around the Item interface.
+
+// Package btree implements in-memory B-Trees of arbitrary degree.
+//
+// btree implements an in-memory B-Tree for use as an ordered data structure.
+// It is not meant for persistent storage solutions.
+//
+// It has a flatter structure than an equivalent red-black or other binary tree,
+// which in some cases yields better memory usage and/or performance.
+// See some discussion on the matter here:
+// http://google-opensource.blogspot.com/2013/01/c-containers-that-save-memory-and-time.html
+// Note, though, that this project is in no way related to the C++ B-Tree
+// implementation written about there.
+//
+// Within this tree, each node contains a slice of items and a (possibly nil)
+// slice of children. For basic numeric values or raw structs, this can cause
+// efficiency differences when compared to equivalent C++ template code that
+// stores values in arrays within the node:
+// * Due to the overhead of storing values as interfaces (each
+// value needs to be stored as the value itself, then 2 words for the
+// interface pointing to that value and its type), resulting in higher
+// memory use.
+// * Since interfaces can point to values anywhere in memory, values are
+// most likely not stored in contiguous blocks, resulting in a higher
+// number of cache misses.
+// These issues don't tend to matter, though, when working with strings or other
+// heap-allocated structures, since C++-equivalent structures also must store
+// pointers and also distribute their values across the heap.
+//
+// This implementation is designed to be a drop-in replacement to gollrb.LLRB
+// trees, (http://github.com/petar/gollrb), an excellent and probably the most
+// widely used ordered tree implementation in the Go ecosystem currently.
+// Its functions, therefore, exactly mirror those of
+// llrb.LLRB where possible. Unlike gollrb, though, we currently don't
+// support storing multiple equivalent values.
+//
+// There are two implementations; those suffixed with 'G' are generics, usable
+// for any type, and require a passed-in "less" function to define their ordering.
+// Those without this prefix are specific to the 'Item' interface, and use
+// its 'Less' function for ordering.
+package btree
+
+import (
+ "fmt"
+ "io"
+ "sort"
+ "strings"
+ "sync"
+)
+
+// Item represents a single object in the tree.
+type Item interface {
+ // Less tests whether the current item is less than the given argument.
+ //
+ // This must provide a strict weak ordering.
+ // If !a.Less(b) && !b.Less(a), we treat this to mean a == b (i.e. we can only
+ // hold one of either a or b in the tree).
+ Less(than Item) bool
+}
+
+const (
+ DefaultFreeListSize = 32
+)
+
+// FreeListG represents a free list of btree nodes. By default each
+// BTree has its own FreeList, but multiple BTrees can share the same
+// FreeList, in particular when they're created with Clone.
+// Two Btrees using the same freelist are safe for concurrent write access.
+type FreeListG[T any] struct {
+ mu sync.Mutex
+ freelist []*node[T]
+}
+
+// NewFreeListG creates a new free list.
+// size is the maximum size of the returned free list.
+func NewFreeListG[T any](size int) *FreeListG[T] {
+ return &FreeListG[T]{freelist: make([]*node[T], 0, size)}
+}
+
+func (f *FreeListG[T]) newNode() (n *node[T]) {
+ f.mu.Lock()
+ index := len(f.freelist) - 1
+ if index < 0 {
+ f.mu.Unlock()
+ return new(node[T])
+ }
+ n = f.freelist[index]
+ f.freelist[index] = nil
+ f.freelist = f.freelist[:index]
+ f.mu.Unlock()
+ return
+}
+
+func (f *FreeListG[T]) freeNode(n *node[T]) (out bool) {
+ f.mu.Lock()
+ if len(f.freelist) < cap(f.freelist) {
+ f.freelist = append(f.freelist, n)
+ out = true
+ }
+ f.mu.Unlock()
+ return
+}
+
+// ItemIteratorG allows callers of {A/De}scend* to iterate in-order over portions of
+// the tree. When this function returns false, iteration will stop and the
+// associated Ascend* function will immediately return.
+type ItemIteratorG[T any] func(item T) bool
+
+// Ordered represents the set of types for which the '<' operator work.
+type Ordered interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64 | ~string
+}
+
+// Less[T] returns a default LessFunc that uses the '<' operator for types that support it.
+func Less[T Ordered]() LessFunc[T] {
+ return func(a, b T) bool { return a < b }
+}
+
+// NewOrderedG creates a new B-Tree for ordered types.
+func NewOrderedG[T Ordered](degree int) *BTreeG[T] {
+ return NewG[T](degree, Less[T]())
+}
+
+// NewG creates a new B-Tree with the given degree.
+//
+// NewG(2), for example, will create a 2-3-4 tree (each node contains 1-3 items
+// and 2-4 children).
+//
+// The passed-in LessFunc determines how objects of type T are ordered.
+func NewG[T any](degree int, less LessFunc[T]) *BTreeG[T] {
+ return NewWithFreeListG(degree, less, NewFreeListG[T](DefaultFreeListSize))
+}
+
+// NewWithFreeListG creates a new B-Tree that uses the given node free list.
+func NewWithFreeListG[T any](degree int, less LessFunc[T], f *FreeListG[T]) *BTreeG[T] {
+ if degree <= 1 {
+ panic("bad degree")
+ }
+ return &BTreeG[T]{
+ degree: degree,
+ cow: ©OnWriteContext[T]{freelist: f, less: less},
+ }
+}
+
+// items stores items in a node.
+type items[T any] []T
+
+// insertAt inserts a value into the given index, pushing all subsequent values
+// forward.
+func (s *items[T]) insertAt(index int, item T) {
+ var zero T
+ *s = append(*s, zero)
+ if index < len(*s) {
+ copy((*s)[index+1:], (*s)[index:])
+ }
+ (*s)[index] = item
+}
+
+// removeAt removes a value at a given index, pulling all subsequent values
+// back.
+func (s *items[T]) removeAt(index int) T {
+ item := (*s)[index]
+ copy((*s)[index:], (*s)[index+1:])
+ var zero T
+ (*s)[len(*s)-1] = zero
+ *s = (*s)[:len(*s)-1]
+ return item
+}
+
+// pop removes and returns the last element in the list.
+func (s *items[T]) pop() (out T) {
+ index := len(*s) - 1
+ out = (*s)[index]
+ var zero T
+ (*s)[index] = zero
+ *s = (*s)[:index]
+ return
+}
+
+// truncate truncates this instance at index so that it contains only the
+// first index items. index must be less than or equal to length.
+func (s *items[T]) truncate(index int) {
+ var toClear items[T]
+ *s, toClear = (*s)[:index], (*s)[index:]
+ var zero T
+ for i := 0; i < len(toClear); i++ {
+ toClear[i] = zero
+ }
+}
+
+// find returns the index where the given item should be inserted into this
+// list. 'found' is true if the item already exists in the list at the given
+// index.
+func (s items[T]) find(item T, less func(T, T) bool) (index int, found bool) {
+ i := sort.Search(len(s), func(i int) bool {
+ return less(item, s[i])
+ })
+ if i > 0 && !less(s[i-1], item) {
+ return i - 1, true
+ }
+ return i, false
+}
+
+// node is an internal node in a tree.
+//
+// It must at all times maintain the invariant that either
+// * len(children) == 0, len(items) unconstrained
+// * len(children) == len(items) + 1
+type node[T any] struct {
+ items items[T]
+ children items[*node[T]]
+ cow *copyOnWriteContext[T]
+}
+
+func (n *node[T]) mutableFor(cow *copyOnWriteContext[T]) *node[T] {
+ if n.cow == cow {
+ return n
+ }
+ out := cow.newNode()
+ if cap(out.items) >= len(n.items) {
+ out.items = out.items[:len(n.items)]
+ } else {
+ out.items = make(items[T], len(n.items), cap(n.items))
+ }
+ copy(out.items, n.items)
+ // Copy children
+ if cap(out.children) >= len(n.children) {
+ out.children = out.children[:len(n.children)]
+ } else {
+ out.children = make(items[*node[T]], len(n.children), cap(n.children))
+ }
+ copy(out.children, n.children)
+ return out
+}
+
+func (n *node[T]) mutableChild(i int) *node[T] {
+ c := n.children[i].mutableFor(n.cow)
+ n.children[i] = c
+ return c
+}
+
+// split splits the given node at the given index. The current node shrinks,
+// and this function returns the item that existed at that index and a new node
+// containing all items/children after it.
+func (n *node[T]) split(i int) (T, *node[T]) {
+ item := n.items[i]
+ next := n.cow.newNode()
+ next.items = append(next.items, n.items[i+1:]...)
+ n.items.truncate(i)
+ if len(n.children) > 0 {
+ next.children = append(next.children, n.children[i+1:]...)
+ n.children.truncate(i + 1)
+ }
+ return item, next
+}
+
+// maybeSplitChild checks if a child should be split, and if so splits it.
+// Returns whether or not a split occurred.
+func (n *node[T]) maybeSplitChild(i, maxItems int) bool {
+ if len(n.children[i].items) < maxItems {
+ return false
+ }
+ first := n.mutableChild(i)
+ item, second := first.split(maxItems / 2)
+ n.items.insertAt(i, item)
+ n.children.insertAt(i+1, second)
+ return true
+}
+
+// insert inserts an item into the subtree rooted at this node, making sure
+// no nodes in the subtree exceed maxItems items. Should an equivalent item be
+// be found/replaced by insert, it will be returned.
+func (n *node[T]) insert(item T, maxItems int) (_ T, _ bool) {
+ i, found := n.items.find(item, n.cow.less)
+ if found {
+ out := n.items[i]
+ n.items[i] = item
+ return out, true
+ }
+ if len(n.children) == 0 {
+ n.items.insertAt(i, item)
+ return
+ }
+ if n.maybeSplitChild(i, maxItems) {
+ inTree := n.items[i]
+ switch {
+ case n.cow.less(item, inTree):
+ // no change, we want first split node
+ case n.cow.less(inTree, item):
+ i++ // we want second split node
+ default:
+ out := n.items[i]
+ n.items[i] = item
+ return out, true
+ }
+ }
+ return n.mutableChild(i).insert(item, maxItems)
+}
+
+// get finds the given key in the subtree and returns it.
+func (n *node[T]) get(key T) (_ T, _ bool) {
+ i, found := n.items.find(key, n.cow.less)
+ if found {
+ return n.items[i], true
+ } else if len(n.children) > 0 {
+ return n.children[i].get(key)
+ }
+ return
+}
+
+// min returns the first item in the subtree.
+func min[T any](n *node[T]) (_ T, found bool) {
+ if n == nil {
+ return
+ }
+ for len(n.children) > 0 {
+ n = n.children[0]
+ }
+ if len(n.items) == 0 {
+ return
+ }
+ return n.items[0], true
+}
+
+// max returns the last item in the subtree.
+func max[T any](n *node[T]) (_ T, found bool) {
+ if n == nil {
+ return
+ }
+ for len(n.children) > 0 {
+ n = n.children[len(n.children)-1]
+ }
+ if len(n.items) == 0 {
+ return
+ }
+ return n.items[len(n.items)-1], true
+}
+
+// toRemove details what item to remove in a node.remove call.
+type toRemove int
+
+const (
+ removeItem toRemove = iota // removes the given item
+ removeMin // removes smallest item in the subtree
+ removeMax // removes largest item in the subtree
+)
+
+// remove removes an item from the subtree rooted at this node.
+func (n *node[T]) remove(item T, minItems int, typ toRemove) (_ T, _ bool) {
+ var i int
+ var found bool
+ switch typ {
+ case removeMax:
+ if len(n.children) == 0 {
+ return n.items.pop(), true
+ }
+ i = len(n.items)
+ case removeMin:
+ if len(n.children) == 0 {
+ return n.items.removeAt(0), true
+ }
+ i = 0
+ case removeItem:
+ i, found = n.items.find(item, n.cow.less)
+ if len(n.children) == 0 {
+ if found {
+ return n.items.removeAt(i), true
+ }
+ return
+ }
+ default:
+ panic("invalid type")
+ }
+ // If we get to here, we have children.
+ if len(n.children[i].items) <= minItems {
+ return n.growChildAndRemove(i, item, minItems, typ)
+ }
+ child := n.mutableChild(i)
+ // Either we had enough items to begin with, or we've done some
+ // merging/stealing, because we've got enough now and we're ready to return
+ // stuff.
+ if found {
+ // The item exists at index 'i', and the child we've selected can give us a
+ // predecessor, since if we've gotten here it's got > minItems items in it.
+ out := n.items[i]
+ // We use our special-case 'remove' call with typ=maxItem to pull the
+ // predecessor of item i (the rightmost leaf of our immediate left child)
+ // and set it into where we pulled the item from.
+ var zero T
+ n.items[i], _ = child.remove(zero, minItems, removeMax)
+ return out, true
+ }
+ // Final recursive call. Once we're here, we know that the item isn't in this
+ // node and that the child is big enough to remove from.
+ return child.remove(item, minItems, typ)
+}
+
+// growChildAndRemove grows child 'i' to make sure it's possible to remove an
+// item from it while keeping it at minItems, then calls remove to actually
+// remove it.
+//
+// Most documentation says we have to do two sets of special casing:
+// 1) item is in this node
+// 2) item is in child
+// In both cases, we need to handle the two subcases:
+// A) node has enough values that it can spare one
+// B) node doesn't have enough values
+// For the latter, we have to check:
+// a) left sibling has node to spare
+// b) right sibling has node to spare
+// c) we must merge
+// To simplify our code here, we handle cases #1 and #2 the same:
+// If a node doesn't have enough items, we make sure it does (using a,b,c).
+// We then simply redo our remove call, and the second time (regardless of
+// whether we're in case 1 or 2), we'll have enough items and can guarantee
+// that we hit case A.
+func (n *node[T]) growChildAndRemove(i int, item T, minItems int, typ toRemove) (T, bool) {
+ if i > 0 && len(n.children[i-1].items) > minItems {
+ // Steal from left child
+ child := n.mutableChild(i)
+ stealFrom := n.mutableChild(i - 1)
+ stolenItem := stealFrom.items.pop()
+ child.items.insertAt(0, n.items[i-1])
+ n.items[i-1] = stolenItem
+ if len(stealFrom.children) > 0 {
+ child.children.insertAt(0, stealFrom.children.pop())
+ }
+ } else if i < len(n.items) && len(n.children[i+1].items) > minItems {
+ // steal from right child
+ child := n.mutableChild(i)
+ stealFrom := n.mutableChild(i + 1)
+ stolenItem := stealFrom.items.removeAt(0)
+ child.items = append(child.items, n.items[i])
+ n.items[i] = stolenItem
+ if len(stealFrom.children) > 0 {
+ child.children = append(child.children, stealFrom.children.removeAt(0))
+ }
+ } else {
+ if i >= len(n.items) {
+ i--
+ }
+ child := n.mutableChild(i)
+ // merge with right child
+ mergeItem := n.items.removeAt(i)
+ mergeChild := n.children.removeAt(i + 1)
+ child.items = append(child.items, mergeItem)
+ child.items = append(child.items, mergeChild.items...)
+ child.children = append(child.children, mergeChild.children...)
+ n.cow.freeNode(mergeChild)
+ }
+ return n.remove(item, minItems, typ)
+}
+
+type direction int
+
+const (
+ descend = direction(-1)
+ ascend = direction(+1)
+)
+
+type optionalItem[T any] struct {
+ item T
+ valid bool
+}
+
+func optional[T any](item T) optionalItem[T] {
+ return optionalItem[T]{item: item, valid: true}
+}
+func empty[T any]() optionalItem[T] {
+ return optionalItem[T]{}
+}
+
+// iterate provides a simple method for iterating over elements in the tree.
+//
+// When ascending, the 'start' should be less than 'stop' and when descending,
+// the 'start' should be greater than 'stop'. Setting 'includeStart' to true
+// will force the iterator to include the first item when it equals 'start',
+// thus creating a "greaterOrEqual" or "lessThanEqual" rather than just a
+// "greaterThan" or "lessThan" queries.
+func (n *node[T]) iterate(dir direction, start, stop optionalItem[T], includeStart bool, hit bool, iter ItemIteratorG[T]) (bool, bool) {
+ var ok, found bool
+ var index int
+ switch dir {
+ case ascend:
+ if start.valid {
+ index, _ = n.items.find(start.item, n.cow.less)
+ }
+ for i := index; i < len(n.items); i++ {
+ if len(n.children) > 0 {
+ if hit, ok = n.children[i].iterate(dir, start, stop, includeStart, hit, iter); !ok {
+ return hit, false
+ }
+ }
+ if !includeStart && !hit && start.valid && !n.cow.less(start.item, n.items[i]) {
+ hit = true
+ continue
+ }
+ hit = true
+ if stop.valid && !n.cow.less(n.items[i], stop.item) {
+ return hit, false
+ }
+ if !iter(n.items[i]) {
+ return hit, false
+ }
+ }
+ if len(n.children) > 0 {
+ if hit, ok = n.children[len(n.children)-1].iterate(dir, start, stop, includeStart, hit, iter); !ok {
+ return hit, false
+ }
+ }
+ case descend:
+ if start.valid {
+ index, found = n.items.find(start.item, n.cow.less)
+ if !found {
+ index = index - 1
+ }
+ } else {
+ index = len(n.items) - 1
+ }
+ for i := index; i >= 0; i-- {
+ if start.valid && !n.cow.less(n.items[i], start.item) {
+ if !includeStart || hit || n.cow.less(start.item, n.items[i]) {
+ continue
+ }
+ }
+ if len(n.children) > 0 {
+ if hit, ok = n.children[i+1].iterate(dir, start, stop, includeStart, hit, iter); !ok {
+ return hit, false
+ }
+ }
+ if stop.valid && !n.cow.less(stop.item, n.items[i]) {
+ return hit, false // continue
+ }
+ hit = true
+ if !iter(n.items[i]) {
+ return hit, false
+ }
+ }
+ if len(n.children) > 0 {
+ if hit, ok = n.children[0].iterate(dir, start, stop, includeStart, hit, iter); !ok {
+ return hit, false
+ }
+ }
+ }
+ return hit, true
+}
+
+// print is used for testing/debugging purposes.
+func (n *node[T]) print(w io.Writer, level int) {
+ fmt.Fprintf(w, "%sNODE:%v\n", strings.Repeat(" ", level), n.items)
+ for _, c := range n.children {
+ c.print(w, level+1)
+ }
+}
+
+// BTreeG is a generic implementation of a B-Tree.
+//
+// BTreeG stores items of type T in an ordered structure, allowing easy insertion,
+// removal, and iteration.
+//
+// Write operations are not safe for concurrent mutation by multiple
+// goroutines, but Read operations are.
+type BTreeG[T any] struct {
+ degree int
+ length int
+ root *node[T]
+ cow *copyOnWriteContext[T]
+}
+
+// LessFunc[T] determines how to order a type 'T'. It should implement a strict
+// ordering, and should return true if within that ordering, 'a' < 'b'.
+type LessFunc[T any] func(a, b T) bool
+
+// copyOnWriteContext pointers determine node ownership... a tree with a write
+// context equivalent to a node's write context is allowed to modify that node.
+// A tree whose write context does not match a node's is not allowed to modify
+// it, and must create a new, writable copy (IE: it's a Clone).
+//
+// When doing any write operation, we maintain the invariant that the current
+// node's context is equal to the context of the tree that requested the write.
+// We do this by, before we descend into any node, creating a copy with the
+// correct context if the contexts don't match.
+//
+// Since the node we're currently visiting on any write has the requesting
+// tree's context, that node is modifiable in place. Children of that node may
+// not share context, but before we descend into them, we'll make a mutable
+// copy.
+type copyOnWriteContext[T any] struct {
+ freelist *FreeListG[T]
+ less LessFunc[T]
+}
+
+// Clone clones the btree, lazily. Clone should not be called concurrently,
+// but the original tree (t) and the new tree (t2) can be used concurrently
+// once the Clone call completes.
+//
+// The internal tree structure of b is marked read-only and shared between t and
+// t2. Writes to both t and t2 use copy-on-write logic, creating new nodes
+// whenever one of b's original nodes would have been modified. Read operations
+// should have no performance degredation. Write operations for both t and t2
+// will initially experience minor slow-downs caused by additional allocs and
+// copies due to the aforementioned copy-on-write logic, but should converge to
+// the original performance characteristics of the original tree.
+func (t *BTreeG[T]) Clone() (t2 *BTreeG[T]) {
+ // Create two entirely new copy-on-write contexts.
+ // This operation effectively creates three trees:
+ // the original, shared nodes (old b.cow)
+ // the new b.cow nodes
+ // the new out.cow nodes
+ cow1, cow2 := *t.cow, *t.cow
+ out := *t
+ t.cow = &cow1
+ out.cow = &cow2
+ return &out
+}
+
+// maxItems returns the max number of items to allow per node.
+func (t *BTreeG[T]) maxItems() int {
+ return t.degree*2 - 1
+}
+
+// minItems returns the min number of items to allow per node (ignored for the
+// root node).
+func (t *BTreeG[T]) minItems() int {
+ return t.degree - 1
+}
+
+func (c *copyOnWriteContext[T]) newNode() (n *node[T]) {
+ n = c.freelist.newNode()
+ n.cow = c
+ return
+}
+
+type freeType int
+
+const (
+ ftFreelistFull freeType = iota // node was freed (available for GC, not stored in freelist)
+ ftStored // node was stored in the freelist for later use
+ ftNotOwned // node was ignored by COW, since it's owned by another one
+)
+
+// freeNode frees a node within a given COW context, if it's owned by that
+// context. It returns what happened to the node (see freeType const
+// documentation).
+func (c *copyOnWriteContext[T]) freeNode(n *node[T]) freeType {
+ if n.cow == c {
+ // clear to allow GC
+ n.items.truncate(0)
+ n.children.truncate(0)
+ n.cow = nil
+ if c.freelist.freeNode(n) {
+ return ftStored
+ } else {
+ return ftFreelistFull
+ }
+ } else {
+ return ftNotOwned
+ }
+}
+
+// ReplaceOrInsert adds the given item to the tree. If an item in the tree
+// already equals the given one, it is removed from the tree and returned,
+// and the second return value is true. Otherwise, (zeroValue, false)
+//
+// nil cannot be added to the tree (will panic).
+func (t *BTreeG[T]) ReplaceOrInsert(item T) (_ T, _ bool) {
+ if t.root == nil {
+ t.root = t.cow.newNode()
+ t.root.items = append(t.root.items, item)
+ t.length++
+ return
+ } else {
+ t.root = t.root.mutableFor(t.cow)
+ if len(t.root.items) >= t.maxItems() {
+ item2, second := t.root.split(t.maxItems() / 2)
+ oldroot := t.root
+ t.root = t.cow.newNode()
+ t.root.items = append(t.root.items, item2)
+ t.root.children = append(t.root.children, oldroot, second)
+ }
+ }
+ out, outb := t.root.insert(item, t.maxItems())
+ if !outb {
+ t.length++
+ }
+ return out, outb
+}
+
+// Delete removes an item equal to the passed in item from the tree, returning
+// it. If no such item exists, returns (zeroValue, false).
+func (t *BTreeG[T]) Delete(item T) (T, bool) {
+ return t.deleteItem(item, removeItem)
+}
+
+// DeleteMin removes the smallest item in the tree and returns it.
+// If no such item exists, returns (zeroValue, false).
+func (t *BTreeG[T]) DeleteMin() (T, bool) {
+ var zero T
+ return t.deleteItem(zero, removeMin)
+}
+
+// DeleteMax removes the largest item in the tree and returns it.
+// If no such item exists, returns (zeroValue, false).
+func (t *BTreeG[T]) DeleteMax() (T, bool) {
+ var zero T
+ return t.deleteItem(zero, removeMax)
+}
+
+func (t *BTreeG[T]) deleteItem(item T, typ toRemove) (_ T, _ bool) {
+ if t.root == nil || len(t.root.items) == 0 {
+ return
+ }
+ t.root = t.root.mutableFor(t.cow)
+ out, outb := t.root.remove(item, t.minItems(), typ)
+ if len(t.root.items) == 0 && len(t.root.children) > 0 {
+ oldroot := t.root
+ t.root = t.root.children[0]
+ t.cow.freeNode(oldroot)
+ }
+ if outb {
+ t.length--
+ }
+ return out, outb
+}
+
+// AscendRange calls the iterator for every value in the tree within the range
+// [greaterOrEqual, lessThan), until iterator returns false.
+func (t *BTreeG[T]) AscendRange(greaterOrEqual, lessThan T, iterator ItemIteratorG[T]) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(ascend, optional[T](greaterOrEqual), optional[T](lessThan), true, false, iterator)
+}
+
+// AscendLessThan calls the iterator for every value in the tree within the range
+// [first, pivot), until iterator returns false.
+func (t *BTreeG[T]) AscendLessThan(pivot T, iterator ItemIteratorG[T]) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(ascend, empty[T](), optional(pivot), false, false, iterator)
+}
+
+// AscendGreaterOrEqual calls the iterator for every value in the tree within
+// the range [pivot, last], until iterator returns false.
+func (t *BTreeG[T]) AscendGreaterOrEqual(pivot T, iterator ItemIteratorG[T]) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(ascend, optional[T](pivot), empty[T](), true, false, iterator)
+}
+
+// Ascend calls the iterator for every value in the tree within the range
+// [first, last], until iterator returns false.
+func (t *BTreeG[T]) Ascend(iterator ItemIteratorG[T]) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(ascend, empty[T](), empty[T](), false, false, iterator)
+}
+
+// DescendRange calls the iterator for every value in the tree within the range
+// [lessOrEqual, greaterThan), until iterator returns false.
+func (t *BTreeG[T]) DescendRange(lessOrEqual, greaterThan T, iterator ItemIteratorG[T]) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(descend, optional[T](lessOrEqual), optional[T](greaterThan), true, false, iterator)
+}
+
+// DescendLessOrEqual calls the iterator for every value in the tree within the range
+// [pivot, first], until iterator returns false.
+func (t *BTreeG[T]) DescendLessOrEqual(pivot T, iterator ItemIteratorG[T]) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(descend, optional[T](pivot), empty[T](), true, false, iterator)
+}
+
+// DescendGreaterThan calls the iterator for every value in the tree within
+// the range [last, pivot), until iterator returns false.
+func (t *BTreeG[T]) DescendGreaterThan(pivot T, iterator ItemIteratorG[T]) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(descend, empty[T](), optional[T](pivot), false, false, iterator)
+}
+
+// Descend calls the iterator for every value in the tree within the range
+// [last, first], until iterator returns false.
+func (t *BTreeG[T]) Descend(iterator ItemIteratorG[T]) {
+ if t.root == nil {
+ return
+ }
+ t.root.iterate(descend, empty[T](), empty[T](), false, false, iterator)
+}
+
+// Get looks for the key item in the tree, returning it. It returns
+// (zeroValue, false) if unable to find that item.
+func (t *BTreeG[T]) Get(key T) (_ T, _ bool) {
+ if t.root == nil {
+ return
+ }
+ return t.root.get(key)
+}
+
+// Min returns the smallest item in the tree, or (zeroValue, false) if the tree is empty.
+func (t *BTreeG[T]) Min() (_ T, _ bool) {
+ return min(t.root)
+}
+
+// Max returns the largest item in the tree, or (zeroValue, false) if the tree is empty.
+func (t *BTreeG[T]) Max() (_ T, _ bool) {
+ return max(t.root)
+}
+
+// Has returns true if the given key is in the tree.
+func (t *BTreeG[T]) Has(key T) bool {
+ _, ok := t.Get(key)
+ return ok
+}
+
+// Len returns the number of items currently in the tree.
+func (t *BTreeG[T]) Len() int {
+ return t.length
+}
+
+// Clear removes all items from the btree. If addNodesToFreelist is true,
+// t's nodes are added to its freelist as part of this call, until the freelist
+// is full. Otherwise, the root node is simply dereferenced and the subtree
+// left to Go's normal GC processes.
+//
+// This can be much faster
+// than calling Delete on all elements, because that requires finding/removing
+// each element in the tree and updating the tree accordingly. It also is
+// somewhat faster than creating a new tree to replace the old one, because
+// nodes from the old tree are reclaimed into the freelist for use by the new
+// one, instead of being lost to the garbage collector.
+//
+// This call takes:
+// O(1): when addNodesToFreelist is false, this is a single operation.
+// O(1): when the freelist is already full, it breaks out immediately
+// O(freelist size): when the freelist is empty and the nodes are all owned
+// by this tree, nodes are added to the freelist until full.
+// O(tree size): when all nodes are owned by another tree, all nodes are
+// iterated over looking for nodes to add to the freelist, and due to
+// ownership, none are.
+func (t *BTreeG[T]) Clear(addNodesToFreelist bool) {
+ if t.root != nil && addNodesToFreelist {
+ t.root.reset(t.cow)
+ }
+ t.root, t.length = nil, 0
+}
+
+// reset returns a subtree to the freelist. It breaks out immediately if the
+// freelist is full, since the only benefit of iterating is to fill that
+// freelist up. Returns true if parent reset call should continue.
+func (n *node[T]) reset(c *copyOnWriteContext[T]) bool {
+ for _, child := range n.children {
+ if !child.reset(c) {
+ return false
+ }
+ }
+ return c.freeNode(n) != ftFreelistFull
+}
+
+// Int implements the Item interface for integers.
+type Int int
+
+// Less returns true if int(a) < int(b).
+func (a Int) Less(b Item) bool {
+ return a < b.(Int)
+}
+
+// BTree is an implementation of a B-Tree.
+//
+// BTree stores Item instances in an ordered structure, allowing easy insertion,
+// removal, and iteration.
+//
+// Write operations are not safe for concurrent mutation by multiple
+// goroutines, but Read operations are.
+type BTree BTreeG[Item]
+
+var itemLess LessFunc[Item] = func(a, b Item) bool {
+ return a.Less(b)
+}
+
+// New creates a new B-Tree with the given degree.
+//
+// New(2), for example, will create a 2-3-4 tree (each node contains 1-3 items
+// and 2-4 children).
+func New(degree int) *BTree {
+ return (*BTree)(NewG[Item](degree, itemLess))
+}
+
+// FreeList represents a free list of btree nodes. By default each
+// BTree has its own FreeList, but multiple BTrees can share the same
+// FreeList.
+// Two Btrees using the same freelist are safe for concurrent write access.
+type FreeList FreeListG[Item]
+
+// NewFreeList creates a new free list.
+// size is the maximum size of the returned free list.
+func NewFreeList(size int) *FreeList {
+ return (*FreeList)(NewFreeListG[Item](size))
+}
+
+// NewWithFreeList creates a new B-Tree that uses the given node free list.
+func NewWithFreeList(degree int, f *FreeList) *BTree {
+ return (*BTree)(NewWithFreeListG[Item](degree, itemLess, (*FreeListG[Item])(f)))
+}
+
+// ItemIterator allows callers of Ascend* to iterate in-order over portions of
+// the tree. When this function returns false, iteration will stop and the
+// associated Ascend* function will immediately return.
+type ItemIterator ItemIteratorG[Item]
+
+// Clone clones the btree, lazily. Clone should not be called concurrently,
+// but the original tree (t) and the new tree (t2) can be used concurrently
+// once the Clone call completes.
+//
+// The internal tree structure of b is marked read-only and shared between t and
+// t2. Writes to both t and t2 use copy-on-write logic, creating new nodes
+// whenever one of b's original nodes would have been modified. Read operations
+// should have no performance degredation. Write operations for both t and t2
+// will initially experience minor slow-downs caused by additional allocs and
+// copies due to the aforementioned copy-on-write logic, but should converge to
+// the original performance characteristics of the original tree.
+func (t *BTree) Clone() (t2 *BTree) {
+ return (*BTree)((*BTreeG[Item])(t).Clone())
+}
+
+// Delete removes an item equal to the passed in item from the tree, returning
+// it. If no such item exists, returns nil.
+func (t *BTree) Delete(item Item) Item {
+ i, _ := (*BTreeG[Item])(t).Delete(item)
+ return i
+}
+
+// DeleteMax removes the largest item in the tree and returns it.
+// If no such item exists, returns nil.
+func (t *BTree) DeleteMax() Item {
+ i, _ := (*BTreeG[Item])(t).DeleteMax()
+ return i
+}
+
+// DeleteMin removes the smallest item in the tree and returns it.
+// If no such item exists, returns nil.
+func (t *BTree) DeleteMin() Item {
+ i, _ := (*BTreeG[Item])(t).DeleteMin()
+ return i
+}
+
+// Get looks for the key item in the tree, returning it. It returns nil if
+// unable to find that item.
+func (t *BTree) Get(key Item) Item {
+ i, _ := (*BTreeG[Item])(t).Get(key)
+ return i
+}
+
+// Max returns the largest item in the tree, or nil if the tree is empty.
+func (t *BTree) Max() Item {
+ i, _ := (*BTreeG[Item])(t).Max()
+ return i
+}
+
+// Min returns the smallest item in the tree, or nil if the tree is empty.
+func (t *BTree) Min() Item {
+ i, _ := (*BTreeG[Item])(t).Min()
+ return i
+}
+
+// Has returns true if the given key is in the tree.
+func (t *BTree) Has(key Item) bool {
+ return (*BTreeG[Item])(t).Has(key)
+}
+
+// ReplaceOrInsert adds the given item to the tree. If an item in the tree
+// already equals the given one, it is removed from the tree and returned.
+// Otherwise, nil is returned.
+//
+// nil cannot be added to the tree (will panic).
+func (t *BTree) ReplaceOrInsert(item Item) Item {
+ i, _ := (*BTreeG[Item])(t).ReplaceOrInsert(item)
+ return i
+}
+
+// AscendRange calls the iterator for every value in the tree within the range
+// [greaterOrEqual, lessThan), until iterator returns false.
+func (t *BTree) AscendRange(greaterOrEqual, lessThan Item, iterator ItemIterator) {
+ (*BTreeG[Item])(t).AscendRange(greaterOrEqual, lessThan, (ItemIteratorG[Item])(iterator))
+}
+
+// AscendLessThan calls the iterator for every value in the tree within the range
+// [first, pivot), until iterator returns false.
+func (t *BTree) AscendLessThan(pivot Item, iterator ItemIterator) {
+ (*BTreeG[Item])(t).AscendLessThan(pivot, (ItemIteratorG[Item])(iterator))
+}
+
+// AscendGreaterOrEqual calls the iterator for every value in the tree within
+// the range [pivot, last], until iterator returns false.
+func (t *BTree) AscendGreaterOrEqual(pivot Item, iterator ItemIterator) {
+ (*BTreeG[Item])(t).AscendGreaterOrEqual(pivot, (ItemIteratorG[Item])(iterator))
+}
+
+// Ascend calls the iterator for every value in the tree within the range
+// [first, last], until iterator returns false.
+func (t *BTree) Ascend(iterator ItemIterator) {
+ (*BTreeG[Item])(t).Ascend((ItemIteratorG[Item])(iterator))
+}
+
+// DescendRange calls the iterator for every value in the tree within the range
+// [lessOrEqual, greaterThan), until iterator returns false.
+func (t *BTree) DescendRange(lessOrEqual, greaterThan Item, iterator ItemIterator) {
+ (*BTreeG[Item])(t).DescendRange(lessOrEqual, greaterThan, (ItemIteratorG[Item])(iterator))
+}
+
+// DescendLessOrEqual calls the iterator for every value in the tree within the range
+// [pivot, first], until iterator returns false.
+func (t *BTree) DescendLessOrEqual(pivot Item, iterator ItemIterator) {
+ (*BTreeG[Item])(t).DescendLessOrEqual(pivot, (ItemIteratorG[Item])(iterator))
+}
+
+// DescendGreaterThan calls the iterator for every value in the tree within
+// the range [last, pivot), until iterator returns false.
+func (t *BTree) DescendGreaterThan(pivot Item, iterator ItemIterator) {
+ (*BTreeG[Item])(t).DescendGreaterThan(pivot, (ItemIteratorG[Item])(iterator))
+}
+
+// Descend calls the iterator for every value in the tree within the range
+// [last, first], until iterator returns false.
+func (t *BTree) Descend(iterator ItemIterator) {
+ (*BTreeG[Item])(t).Descend((ItemIteratorG[Item])(iterator))
+}
+
+// Len returns the number of items currently in the tree.
+func (t *BTree) Len() int {
+ return (*BTreeG[Item])(t).Len()
+}
+
+// Clear removes all items from the btree. If addNodesToFreelist is true,
+// t's nodes are added to its freelist as part of this call, until the freelist
+// is full. Otherwise, the root node is simply dereferenced and the subtree
+// left to Go's normal GC processes.
+//
+// This can be much faster
+// than calling Delete on all elements, because that requires finding/removing
+// each element in the tree and updating the tree accordingly. It also is
+// somewhat faster than creating a new tree to replace the old one, because
+// nodes from the old tree are reclaimed into the freelist for use by the new
+// one, instead of being lost to the garbage collector.
+//
+// This call takes:
+// O(1): when addNodesToFreelist is false, this is a single operation.
+// O(1): when the freelist is already full, it breaks out immediately
+// O(freelist size): when the freelist is empty and the nodes are all owned
+// by this tree, nodes are added to the freelist until full.
+// O(tree size): when all nodes are owned by another tree, all nodes are
+// iterated over looking for nodes to add to the freelist, and due to
+// ownership, none are.
+func (t *BTree) Clear(addNodesToFreelist bool) {
+ (*BTreeG[Item])(t).Clear(addNodesToFreelist)
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go
index 4e684c7de6c..69edf5eff8d 100644
--- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go
@@ -71,6 +71,7 @@ type ServeMux struct {
streamErrorHandler StreamErrorHandlerFunc
routingErrorHandler RoutingErrorHandlerFunc
disablePathLengthFallback bool
+ disableHTTPMethodOverride bool
unescapingMode UnescapingMode
writeContentLength bool
disableChunkedEncoding bool
@@ -271,6 +272,19 @@ func WithDisablePathLengthFallback() ServeMuxOption {
}
}
+// WithDisableHTTPMethodOverride returns a ServeMuxOption that disables the
+// X-HTTP-Method-Override header handling.
+//
+// When this option is used, the mux will no longer allow POST requests with
+// the X-HTTP-Method-Override header to override the HTTP method. The path
+// length fallback (POST with application/x-www-form-urlencoded falling back
+// to a matching GET handler) is not affected by this option.
+func WithDisableHTTPMethodOverride() ServeMuxOption {
+ return func(serveMux *ServeMux) {
+ serveMux.disableHTTPMethodOverride = true
+ }
+}
+
// WithWriteContentLength returns a ServeMuxOption to enable writing content length on non-streaming responses
func WithWriteContentLength() ServeMuxOption {
return func(serveMux *ServeMux) {
@@ -405,7 +419,7 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
path = r.URL.RawPath
}
- if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && s.isPathLengthFallback(r) {
+ if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && !s.disableHTTPMethodOverride && s.isPathLengthFallback(r) {
if err := r.ParseForm(); err != nil {
_, outboundMarshaler := MarshalerForRequest(s, r)
sterr := status.Error(codes.InvalidArgument, err.Error())
@@ -467,6 +481,7 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
HTTPStatus: http.StatusBadRequest,
Err: mse,
})
+ return
}
continue
}
@@ -509,6 +524,7 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
HTTPStatus: http.StatusBadRequest,
Err: mse,
})
+ return
}
continue
}
diff --git a/vendor/github.com/hashicorp/errwrap/LICENSE b/vendor/github.com/hashicorp/errwrap/LICENSE
new file mode 100644
index 00000000000..c33dcc7c928
--- /dev/null
+++ b/vendor/github.com/hashicorp/errwrap/LICENSE
@@ -0,0 +1,354 @@
+Mozilla Public License, version 2.0
+
+1. Definitions
+
+1.1. “Contributor”
+
+ means each individual or legal entity that creates, contributes to the
+ creation of, or owns Covered Software.
+
+1.2. “Contributor Version”
+
+ means the combination of the Contributions of others (if any) used by a
+ Contributor and that particular Contributor’s Contribution.
+
+1.3. “Contribution”
+
+ means Covered Software of a particular Contributor.
+
+1.4. “Covered Software”
+
+ means Source Code Form to which the initial Contributor has attached the
+ notice in Exhibit A, the Executable Form of such Source Code Form, and
+ Modifications of such Source Code Form, in each case including portions
+ thereof.
+
+1.5. “Incompatible With Secondary Licenses”
+ means
+
+ a. that the initial Contributor has attached the notice described in
+ Exhibit B to the Covered Software; or
+
+ b. that the Covered Software was made available under the terms of version
+ 1.1 or earlier of the License, but not also under the terms of a
+ Secondary License.
+
+1.6. “Executable Form”
+
+ means any form of the work other than Source Code Form.
+
+1.7. “Larger Work”
+
+ means a work that combines Covered Software with other material, in a separate
+ file or files, that is not Covered Software.
+
+1.8. “License”
+
+ means this document.
+
+1.9. “Licensable”
+
+ means having the right to grant, to the maximum extent possible, whether at the
+ time of the initial grant or subsequently, any and all of the rights conveyed by
+ this License.
+
+1.10. “Modifications”
+
+ means any of the following:
+
+ a. any file in Source Code Form that results from an addition to, deletion
+ from, or modification of the contents of Covered Software; or
+
+ b. any new file in Source Code Form that contains any Covered Software.
+
+1.11. “Patent Claims” of a Contributor
+
+ means any patent claim(s), including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by such Contributor that
+ would be infringed, but for the grant of the License, by the making,
+ using, selling, offering for sale, having made, import, or transfer of
+ either its Contributions or its Contributor Version.
+
+1.12. “Secondary License”
+
+ means either the GNU General Public License, Version 2.0, the GNU Lesser
+ General Public License, Version 2.1, the GNU Affero General Public
+ License, Version 3.0, or any later versions of those licenses.
+
+1.13. “Source Code Form”
+
+ means the form of the work preferred for making modifications.
+
+1.14. “You” (or “Your”)
+
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, “You” includes any entity that controls, is
+ controlled by, or is under common control with You. For purposes of this
+ definition, “control” means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by contract or
+ otherwise, or (b) ownership of more than fifty percent (50%) of the
+ outstanding shares or beneficial ownership of such entity.
+
+
+2. License Grants and Conditions
+
+2.1. Grants
+
+ Each Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ a. under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or as
+ part of a Larger Work; and
+
+ b. under Patent Claims of such Contributor to make, use, sell, offer for
+ sale, have made, import, and otherwise transfer either its Contributions
+ or its Contributor Version.
+
+2.2. Effective Date
+
+ The licenses granted in Section 2.1 with respect to any Contribution become
+ effective for each Contribution on the date the Contributor first distributes
+ such Contribution.
+
+2.3. Limitations on Grant Scope
+
+ The licenses granted in this Section 2 are the only rights granted under this
+ License. No additional rights or licenses will be implied from the distribution
+ or licensing of Covered Software under this License. Notwithstanding Section
+ 2.1(b) above, no patent license is granted by a Contributor:
+
+ a. for any code that a Contributor has removed from Covered Software; or
+
+ b. for infringements caused by: (i) Your and any other third party’s
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+ c. under Patent Claims infringed by Covered Software in the absence of its
+ Contributions.
+
+ This License does not grant any rights in the trademarks, service marks, or
+ logos of any Contributor (except as may be necessary to comply with the
+ notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+ No Contributor makes additional grants as a result of Your choice to
+ distribute the Covered Software under a subsequent version of this License
+ (see Section 10.2) or under the terms of a Secondary License (if permitted
+ under the terms of Section 3.3).
+
+2.5. Representation
+
+ Each Contributor represents that the Contributor believes its Contributions
+ are its original creation(s) or it has sufficient rights to grant the
+ rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+ This License is not intended to limit any rights You have under applicable
+ copyright doctrines of fair use, fair dealing, or other equivalents.
+
+2.7. Conditions
+
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+ Section 2.1.
+
+
+3. Responsibilities
+
+3.1. Distribution of Source Form
+
+ All distribution of Covered Software in Source Code Form, including any
+ Modifications that You create or to which You contribute, must be under the
+ terms of this License. You must inform recipients that the Source Code Form
+ of the Covered Software is governed by the terms of this License, and how
+ they can obtain a copy of this License. You may not attempt to alter or
+ restrict the recipients’ rights in the Source Code Form.
+
+3.2. Distribution of Executable Form
+
+ If You distribute Covered Software in Executable Form then:
+
+ a. such Covered Software must also be made available in Source Code Form,
+ as described in Section 3.1, and You must inform recipients of the
+ Executable Form how they can obtain a copy of such Source Code Form by
+ reasonable means in a timely manner, at a charge no more than the cost
+ of distribution to the recipient; and
+
+ b. You may distribute such Executable Form under the terms of this License,
+ or sublicense it under different terms, provided that the license for
+ the Executable Form does not attempt to limit or alter the recipients’
+ rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+ You may create and distribute a Larger Work under terms of Your choice,
+ provided that You also comply with the requirements of this License for the
+ Covered Software. If the Larger Work is a combination of Covered Software
+ with a work governed by one or more Secondary Licenses, and the Covered
+ Software is not Incompatible With Secondary Licenses, this License permits
+ You to additionally distribute such Covered Software under the terms of
+ such Secondary License(s), so that the recipient of the Larger Work may, at
+ their option, further distribute the Covered Software under the terms of
+ either this License or such Secondary License(s).
+
+3.4. Notices
+
+ You may not remove or alter the substance of any license notices (including
+ copyright notices, patent notices, disclaimers of warranty, or limitations
+ of liability) contained within the Source Code Form of the Covered
+ Software, except that You may alter any license notices to the extent
+ required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+ You may choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of Covered
+ Software. However, You may do so only on Your own behalf, and not on behalf
+ of any Contributor. You must make it absolutely clear that any such
+ warranty, support, indemnity, or liability obligation is offered by You
+ alone, and You hereby agree to indemnify every Contributor for any
+ liability incurred by such Contributor as a result of warranty, support,
+ indemnity or liability terms You offer. You may include additional
+ disclaimers of warranty and limitations of liability specific to any
+ jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+
+ If it is impossible for You to comply with any of the terms of this License
+ with respect to some or all of the Covered Software due to statute, judicial
+ order, or regulation then You must: (a) comply with the terms of this License
+ to the maximum extent possible; and (b) describe the limitations and the code
+ they affect. Such description must be placed in a text file included with all
+ distributions of the Covered Software under this License. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+
+5. Termination
+
+5.1. The rights granted under this License will terminate automatically if You
+ fail to comply with any of its terms. However, if You become compliant,
+ then the rights granted under this License from a particular Contributor
+ are reinstated (a) provisionally, unless and until such Contributor
+ explicitly and finally terminates Your grants, and (b) on an ongoing basis,
+ if such Contributor fails to notify You of the non-compliance by some
+ reasonable means prior to 60 days after You have come back into compliance.
+ Moreover, Your grants from a particular Contributor are reinstated on an
+ ongoing basis if such Contributor notifies You of the non-compliance by
+ some reasonable means, this is the first time You have received notice of
+ non-compliance with this License from such Contributor, and You become
+ compliant prior to 30 days after Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+ infringement claim (excluding declaratory judgment actions, counter-claims,
+ and cross-claims) alleging that a Contributor Version directly or
+ indirectly infringes any patent, then the rights granted to You by any and
+ all Contributors for the Covered Software under Section 2.1 of this License
+ shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
+ license agreements (excluding distributors and resellers) which have been
+ validly granted by You or Your distributors under this License prior to
+ termination shall survive termination.
+
+6. Disclaimer of Warranty
+
+ Covered Software is provided under this License on an “as is” basis, without
+ warranty of any kind, either expressed, implied, or statutory, including,
+ without limitation, warranties that the Covered Software is free of defects,
+ merchantable, fit for a particular purpose or non-infringing. The entire
+ risk as to the quality and performance of the Covered Software is with You.
+ Should any Covered Software prove defective in any respect, You (not any
+ Contributor) assume the cost of any necessary servicing, repair, or
+ correction. This disclaimer of warranty constitutes an essential part of this
+ License. No use of any Covered Software is authorized under this License
+ except under this disclaimer.
+
+7. Limitation of Liability
+
+ Under no circumstances and under no legal theory, whether tort (including
+ negligence), contract, or otherwise, shall any Contributor, or anyone who
+ distributes Covered Software as permitted above, be liable to You for any
+ direct, indirect, special, incidental, or consequential damages of any
+ character including, without limitation, damages for lost profits, loss of
+ goodwill, work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses, even if such party shall have been
+ informed of the possibility of such damages. This limitation of liability
+ shall not apply to liability for death or personal injury resulting from such
+ party’s negligence to the extent applicable law prohibits such limitation.
+ Some jurisdictions do not allow the exclusion or limitation of incidental or
+ consequential damages, so this exclusion and limitation may not apply to You.
+
+8. Litigation
+
+ Any litigation relating to this License may be brought only in the courts of
+ a jurisdiction where the defendant maintains its principal place of business
+ and such litigation shall be governed by laws of that jurisdiction, without
+ reference to its conflict-of-law provisions. Nothing in this Section shall
+ prevent a party’s ability to bring cross-claims or counter-claims.
+
+9. Miscellaneous
+
+ This License represents the complete agreement concerning the subject matter
+ hereof. If any provision of this License is held to be unenforceable, such
+ provision shall be reformed only to the extent necessary to make it
+ enforceable. Any law or regulation which provides that the language of a
+ contract shall be construed against the drafter shall not be used to construe
+ this License against a Contributor.
+
+
+10. Versions of the License
+
+10.1. New Versions
+
+ Mozilla Foundation is the license steward. Except as provided in Section
+ 10.3, no one other than the license steward has the right to modify or
+ publish new versions of this License. Each version will be given a
+ distinguishing version number.
+
+10.2. Effect of New Versions
+
+ You may distribute the Covered Software under the terms of the version of
+ the License under which You originally received the Covered Software, or
+ under the terms of any subsequent version published by the license
+ steward.
+
+10.3. Modified Versions
+
+ If you create software not governed by this License, and you want to
+ create a new license for such software, you may create and use a modified
+ version of this License if you rename the license and remove any
+ references to the name of the license steward (except to note that such
+ modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
+ If You choose to distribute Source Code Form that is Incompatible With
+ Secondary Licenses under the terms of this version of the License, the
+ notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+
+ This Source Code Form is subject to the
+ terms of the Mozilla Public License, v.
+ 2.0. If a copy of the MPL was not
+ distributed with this file, You can
+ obtain one at
+ http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular file, then
+You may include the notice in a location (such as a LICENSE file in a relevant
+directory) where a recipient would be likely to look for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - “Incompatible With Secondary Licenses” Notice
+
+ This Source Code Form is “Incompatible
+ With Secondary Licenses”, as defined by
+ the Mozilla Public License, v. 2.0.
+
diff --git a/vendor/github.com/hashicorp/errwrap/README.md b/vendor/github.com/hashicorp/errwrap/README.md
new file mode 100644
index 00000000000..444df08f8e7
--- /dev/null
+++ b/vendor/github.com/hashicorp/errwrap/README.md
@@ -0,0 +1,89 @@
+# errwrap
+
+`errwrap` is a package for Go that formalizes the pattern of wrapping errors
+and checking if an error contains another error.
+
+There is a common pattern in Go of taking a returned `error` value and
+then wrapping it (such as with `fmt.Errorf`) before returning it. The problem
+with this pattern is that you completely lose the original `error` structure.
+
+Arguably the _correct_ approach is that you should make a custom structure
+implementing the `error` interface, and have the original error as a field
+on that structure, such [as this example](http://golang.org/pkg/os/#PathError).
+This is a good approach, but you have to know the entire chain of possible
+rewrapping that happens, when you might just care about one.
+
+`errwrap` formalizes this pattern (it doesn't matter what approach you use
+above) by giving a single interface for wrapping errors, checking if a specific
+error is wrapped, and extracting that error.
+
+## Installation and Docs
+
+Install using `go get github.com/hashicorp/errwrap`.
+
+Full documentation is available at
+http://godoc.org/github.com/hashicorp/errwrap
+
+## Usage
+
+#### Basic Usage
+
+Below is a very basic example of its usage:
+
+```go
+// A function that always returns an error, but wraps it, like a real
+// function might.
+func tryOpen() error {
+ _, err := os.Open("/i/dont/exist")
+ if err != nil {
+ return errwrap.Wrapf("Doesn't exist: {{err}}", err)
+ }
+
+ return nil
+}
+
+func main() {
+ err := tryOpen()
+
+ // We can use the Contains helpers to check if an error contains
+ // another error. It is safe to do this with a nil error, or with
+ // an error that doesn't even use the errwrap package.
+ if errwrap.Contains(err, "does not exist") {
+ // Do something
+ }
+ if errwrap.ContainsType(err, new(os.PathError)) {
+ // Do something
+ }
+
+ // Or we can use the associated `Get` functions to just extract
+ // a specific error. This would return nil if that specific error doesn't
+ // exist.
+ perr := errwrap.GetType(err, new(os.PathError))
+}
+```
+
+#### Custom Types
+
+If you're already making custom types that properly wrap errors, then
+you can get all the functionality of `errwraps.Contains` and such by
+implementing the `Wrapper` interface with just one function. Example:
+
+```go
+type AppError {
+ Code ErrorCode
+ Err error
+}
+
+func (e *AppError) WrappedErrors() []error {
+ return []error{e.Err}
+}
+```
+
+Now this works:
+
+```go
+err := &AppError{Err: fmt.Errorf("an error")}
+if errwrap.ContainsType(err, fmt.Errorf("")) {
+ // This will work!
+}
+```
diff --git a/vendor/github.com/hashicorp/errwrap/errwrap.go b/vendor/github.com/hashicorp/errwrap/errwrap.go
new file mode 100644
index 00000000000..44e368e5692
--- /dev/null
+++ b/vendor/github.com/hashicorp/errwrap/errwrap.go
@@ -0,0 +1,178 @@
+// Package errwrap implements methods to formalize error wrapping in Go.
+//
+// All of the top-level functions that take an `error` are built to be able
+// to take any error, not just wrapped errors. This allows you to use errwrap
+// without having to type-check and type-cast everywhere.
+package errwrap
+
+import (
+ "errors"
+ "reflect"
+ "strings"
+)
+
+// WalkFunc is the callback called for Walk.
+type WalkFunc func(error)
+
+// Wrapper is an interface that can be implemented by custom types to
+// have all the Contains, Get, etc. functions in errwrap work.
+//
+// When Walk reaches a Wrapper, it will call the callback for every
+// wrapped error in addition to the wrapper itself. Since all the top-level
+// functions in errwrap use Walk, this means that all those functions work
+// with your custom type.
+type Wrapper interface {
+ WrappedErrors() []error
+}
+
+// Wrap defines that outer wraps inner, returning an error type that
+// can be cleanly used with the other methods in this package, such as
+// Contains, GetAll, etc.
+//
+// This function won't modify the error message at all (the outer message
+// will be used).
+func Wrap(outer, inner error) error {
+ return &wrappedError{
+ Outer: outer,
+ Inner: inner,
+ }
+}
+
+// Wrapf wraps an error with a formatting message. This is similar to using
+// `fmt.Errorf` to wrap an error. If you're using `fmt.Errorf` to wrap
+// errors, you should replace it with this.
+//
+// format is the format of the error message. The string '{{err}}' will
+// be replaced with the original error message.
+//
+// Deprecated: Use fmt.Errorf()
+func Wrapf(format string, err error) error {
+ outerMsg := ""
+ if err != nil {
+ outerMsg = err.Error()
+ }
+
+ outer := errors.New(strings.Replace(
+ format, "{{err}}", outerMsg, -1))
+
+ return Wrap(outer, err)
+}
+
+// Contains checks if the given error contains an error with the
+// message msg. If err is not a wrapped error, this will always return
+// false unless the error itself happens to match this msg.
+func Contains(err error, msg string) bool {
+ return len(GetAll(err, msg)) > 0
+}
+
+// ContainsType checks if the given error contains an error with
+// the same concrete type as v. If err is not a wrapped error, this will
+// check the err itself.
+func ContainsType(err error, v interface{}) bool {
+ return len(GetAllType(err, v)) > 0
+}
+
+// Get is the same as GetAll but returns the deepest matching error.
+func Get(err error, msg string) error {
+ es := GetAll(err, msg)
+ if len(es) > 0 {
+ return es[len(es)-1]
+ }
+
+ return nil
+}
+
+// GetType is the same as GetAllType but returns the deepest matching error.
+func GetType(err error, v interface{}) error {
+ es := GetAllType(err, v)
+ if len(es) > 0 {
+ return es[len(es)-1]
+ }
+
+ return nil
+}
+
+// GetAll gets all the errors that might be wrapped in err with the
+// given message. The order of the errors is such that the outermost
+// matching error (the most recent wrap) is index zero, and so on.
+func GetAll(err error, msg string) []error {
+ var result []error
+
+ Walk(err, func(err error) {
+ if err.Error() == msg {
+ result = append(result, err)
+ }
+ })
+
+ return result
+}
+
+// GetAllType gets all the errors that are the same type as v.
+//
+// The order of the return value is the same as described in GetAll.
+func GetAllType(err error, v interface{}) []error {
+ var result []error
+
+ var search string
+ if v != nil {
+ search = reflect.TypeOf(v).String()
+ }
+ Walk(err, func(err error) {
+ var needle string
+ if err != nil {
+ needle = reflect.TypeOf(err).String()
+ }
+
+ if needle == search {
+ result = append(result, err)
+ }
+ })
+
+ return result
+}
+
+// Walk walks all the wrapped errors in err and calls the callback. If
+// err isn't a wrapped error, this will be called once for err. If err
+// is a wrapped error, the callback will be called for both the wrapper
+// that implements error as well as the wrapped error itself.
+func Walk(err error, cb WalkFunc) {
+ if err == nil {
+ return
+ }
+
+ switch e := err.(type) {
+ case *wrappedError:
+ cb(e.Outer)
+ Walk(e.Inner, cb)
+ case Wrapper:
+ cb(err)
+
+ for _, err := range e.WrappedErrors() {
+ Walk(err, cb)
+ }
+ case interface{ Unwrap() error }:
+ cb(err)
+ Walk(e.Unwrap(), cb)
+ default:
+ cb(err)
+ }
+}
+
+// wrappedError is an implementation of error that has both the
+// outer and inner errors.
+type wrappedError struct {
+ Outer error
+ Inner error
+}
+
+func (w *wrappedError) Error() string {
+ return w.Outer.Error()
+}
+
+func (w *wrappedError) WrappedErrors() []error {
+ return []error{w.Outer, w.Inner}
+}
+
+func (w *wrappedError) Unwrap() error {
+ return w.Inner
+}
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/.gitignore b/vendor/github.com/hashicorp/go-immutable-radix/.gitignore
new file mode 100644
index 00000000000..daf913b1b34
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-immutable-radix/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/CHANGELOG.md b/vendor/github.com/hashicorp/go-immutable-radix/CHANGELOG.md
new file mode 100644
index 00000000000..86c6d03fbaa
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-immutable-radix/CHANGELOG.md
@@ -0,0 +1,23 @@
+# UNRELEASED
+
+# 1.3.0 (September 17th, 2020)
+
+FEATURES
+
+* Add reverse tree traversal [[GH-30](https://github.com/hashicorp/go-immutable-radix/pull/30)]
+
+# 1.2.0 (March 18th, 2020)
+
+FEATURES
+
+* Adds a `Clone` method to `Txn` allowing transactions to be split either into two independently mutable trees. [[GH-26](https://github.com/hashicorp/go-immutable-radix/pull/26)]
+
+# 1.1.0 (May 22nd, 2019)
+
+FEATURES
+
+* Add `SeekLowerBound` to allow for range scans. [[GH-24](https://github.com/hashicorp/go-immutable-radix/pull/24)]
+
+# 1.0.0 (August 30th, 2018)
+
+* go mod adopted
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/LICENSE b/vendor/github.com/hashicorp/go-immutable-radix/LICENSE
new file mode 100644
index 00000000000..e87a115e462
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-immutable-radix/LICENSE
@@ -0,0 +1,363 @@
+Mozilla Public License, version 2.0
+
+1. Definitions
+
+1.1. "Contributor"
+
+ means each individual or legal entity that creates, contributes to the
+ creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+
+ means the combination of the Contributions of others (if any) used by a
+ Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+
+ means Source Code Form to which the initial Contributor has attached the
+ notice in Exhibit A, the Executable Form of such Source Code Form, and
+ Modifications of such Source Code Form, in each case including portions
+ thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ a. that the initial Contributor has attached the notice described in
+ Exhibit B to the Covered Software; or
+
+ b. that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the terms of
+ a Secondary License.
+
+1.6. "Executable Form"
+
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+
+ means a work that combines Covered Software with other material, in a
+ separate file or files, that is not Covered Software.
+
+1.8. "License"
+
+ means this document.
+
+1.9. "Licensable"
+
+ means having the right to grant, to the maximum extent possible, whether
+ at the time of the initial grant or subsequently, any and all of the
+ rights conveyed by this License.
+
+1.10. "Modifications"
+
+ means any of the following:
+
+ a. any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered Software; or
+
+ b. any new file in Source Code Form that contains any Covered Software.
+
+1.11. "Patent Claims" of a Contributor
+
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the License,
+ by the making, using, selling, offering for sale, having made, import,
+ or transfer of either its Contributions or its Contributor Version.
+
+1.12. "Secondary License"
+
+ means either the GNU General Public License, Version 2.0, the GNU Lesser
+ General Public License, Version 2.1, the GNU Affero General Public
+ License, Version 3.0, or any later versions of those licenses.
+
+1.13. "Source Code Form"
+
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that controls, is
+ controlled by, or is under common control with You. For purposes of this
+ definition, "control" means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by contract or
+ otherwise, or (b) ownership of more than fifty percent (50%) of the
+ outstanding shares or beneficial ownership of such entity.
+
+
+2. License Grants and Conditions
+
+2.1. Grants
+
+ Each Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ a. under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+ b. under Patent Claims of such Contributor to make, use, sell, offer for
+ sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+ The licenses granted in Section 2.1 with respect to any Contribution
+ become effective for each Contribution on the date the Contributor first
+ distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+ The licenses granted in this Section 2 are the only rights granted under
+ this License. No additional rights or licenses will be implied from the
+ distribution or licensing of Covered Software under this License.
+ Notwithstanding Section 2.1(b) above, no patent license is granted by a
+ Contributor:
+
+ a. for any code that a Contributor has removed from Covered Software; or
+
+ b. for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+ c. under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+ This License does not grant any rights in the trademarks, service marks,
+ or logos of any Contributor (except as may be necessary to comply with
+ the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+ No Contributor makes additional grants as a result of Your choice to
+ distribute the Covered Software under a subsequent version of this
+ License (see Section 10.2) or under the terms of a Secondary License (if
+ permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+ Each Contributor represents that the Contributor believes its
+ Contributions are its original creation(s) or it has sufficient rights to
+ grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+ This License is not intended to limit any rights You have under
+ applicable copyright doctrines of fair use, fair dealing, or other
+ equivalents.
+
+2.7. Conditions
+
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+ Section 2.1.
+
+
+3. Responsibilities
+
+3.1. Distribution of Source Form
+
+ All distribution of Covered Software in Source Code Form, including any
+ Modifications that You create or to which You contribute, must be under
+ the terms of this License. You must inform recipients that the Source
+ Code Form of the Covered Software is governed by the terms of this
+ License, and how they can obtain a copy of this License. You may not
+ attempt to alter or restrict the recipients' rights in the Source Code
+ Form.
+
+3.2. Distribution of Executable Form
+
+ If You distribute Covered Software in Executable Form then:
+
+ a. such Covered Software must also be made available in Source Code Form,
+ as described in Section 3.1, and You must inform recipients of the
+ Executable Form how they can obtain a copy of such Source Code Form by
+ reasonable means in a timely manner, at a charge no more than the cost
+ of distribution to the recipient; and
+
+ b. You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter the
+ recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+ You may create and distribute a Larger Work under terms of Your choice,
+ provided that You also comply with the requirements of this License for
+ the Covered Software. If the Larger Work is a combination of Covered
+ Software with a work governed by one or more Secondary Licenses, and the
+ Covered Software is not Incompatible With Secondary Licenses, this
+ License permits You to additionally distribute such Covered Software
+ under the terms of such Secondary License(s), so that the recipient of
+ the Larger Work may, at their option, further distribute the Covered
+ Software under the terms of either this License or such Secondary
+ License(s).
+
+3.4. Notices
+
+ You may not remove or alter the substance of any license notices
+ (including copyright notices, patent notices, disclaimers of warranty, or
+ limitations of liability) contained within the Source Code Form of the
+ Covered Software, except that You may alter any license notices to the
+ extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+ You may choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of Covered
+ Software. However, You may do so only on Your own behalf, and not on
+ behalf of any Contributor. You must make it absolutely clear that any
+ such warranty, support, indemnity, or liability obligation is offered by
+ You alone, and You hereby agree to indemnify every Contributor for any
+ liability incurred by such Contributor as a result of warranty, support,
+ indemnity or liability terms You offer. You may include additional
+ disclaimers of warranty and limitations of liability specific to any
+ jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+
+ If it is impossible for You to comply with any of the terms of this License
+ with respect to some or all of the Covered Software due to statute,
+ judicial order, or regulation then You must: (a) comply with the terms of
+ this License to the maximum extent possible; and (b) describe the
+ limitations and the code they affect. Such description must be placed in a
+ text file included with all distributions of the Covered Software under
+ this License. Except to the extent prohibited by statute or regulation,
+ such description must be sufficiently detailed for a recipient of ordinary
+ skill to be able to understand it.
+
+5. Termination
+
+5.1. The rights granted under this License will terminate automatically if You
+ fail to comply with any of its terms. However, if You become compliant,
+ then the rights granted under this License from a particular Contributor
+ are reinstated (a) provisionally, unless and until such Contributor
+ explicitly and finally terminates Your grants, and (b) on an ongoing
+ basis, if such Contributor fails to notify You of the non-compliance by
+ some reasonable means prior to 60 days after You have come back into
+ compliance. Moreover, Your grants from a particular Contributor are
+ reinstated on an ongoing basis if such Contributor notifies You of the
+ non-compliance by some reasonable means, this is the first time You have
+ received notice of non-compliance with this License from such
+ Contributor, and You become compliant prior to 30 days after Your receipt
+ of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+ infringement claim (excluding declaratory judgment actions,
+ counter-claims, and cross-claims) alleging that a Contributor Version
+ directly or indirectly infringes any patent, then the rights granted to
+ You by any and all Contributors for the Covered Software under Section
+ 2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
+ license agreements (excluding distributors and resellers) which have been
+ validly granted by You or Your distributors under this License prior to
+ termination shall survive termination.
+
+6. Disclaimer of Warranty
+
+ Covered Software is provided under this License on an "as is" basis,
+ without warranty of any kind, either expressed, implied, or statutory,
+ including, without limitation, warranties that the Covered Software is free
+ of defects, merchantable, fit for a particular purpose or non-infringing.
+ The entire risk as to the quality and performance of the Covered Software
+ is with You. Should any Covered Software prove defective in any respect,
+ You (not any Contributor) assume the cost of any necessary servicing,
+ repair, or correction. This disclaimer of warranty constitutes an essential
+ part of this License. No use of any Covered Software is authorized under
+ this License except under this disclaimer.
+
+7. Limitation of Liability
+
+ Under no circumstances and under no legal theory, whether tort (including
+ negligence), contract, or otherwise, shall any Contributor, or anyone who
+ distributes Covered Software as permitted above, be liable to You for any
+ direct, indirect, special, incidental, or consequential damages of any
+ character including, without limitation, damages for lost profits, loss of
+ goodwill, work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses, even if such party shall have been
+ informed of the possibility of such damages. This limitation of liability
+ shall not apply to liability for death or personal injury resulting from
+ such party's negligence to the extent applicable law prohibits such
+ limitation. Some jurisdictions do not allow the exclusion or limitation of
+ incidental or consequential damages, so this exclusion and limitation may
+ not apply to You.
+
+8. Litigation
+
+ Any litigation relating to this License may be brought only in the courts
+ of a jurisdiction where the defendant maintains its principal place of
+ business and such litigation shall be governed by laws of that
+ jurisdiction, without reference to its conflict-of-law provisions. Nothing
+ in this Section shall prevent a party's ability to bring cross-claims or
+ counter-claims.
+
+9. Miscellaneous
+
+ This License represents the complete agreement concerning the subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. Any law or regulation which provides that
+ the language of a contract shall be construed against the drafter shall not
+ be used to construe this License against a Contributor.
+
+
+10. Versions of the License
+
+10.1. New Versions
+
+ Mozilla Foundation is the license steward. Except as provided in Section
+ 10.3, no one other than the license steward has the right to modify or
+ publish new versions of this License. Each version will be given a
+ distinguishing version number.
+
+10.2. Effect of New Versions
+
+ You may distribute the Covered Software under the terms of the version
+ of the License under which You originally received the Covered Software,
+ or under the terms of any subsequent version published by the license
+ steward.
+
+10.3. Modified Versions
+
+ If you create software not governed by this License, and you want to
+ create a new license for such software, you may create and use a
+ modified version of this License if you rename the license and remove
+ any references to the name of the license steward (except to note that
+ such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+ Licenses If You choose to distribute Source Code Form that is
+ Incompatible With Secondary Licenses under the terms of this version of
+ the License, the notice described in Exhibit B of this License must be
+ attached.
+
+Exhibit A - Source Code Form License Notice
+
+ This Source Code Form is subject to the
+ terms of the Mozilla Public License, v.
+ 2.0. If a copy of the MPL was not
+ distributed with this file, You can
+ obtain one at
+ http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular file,
+then You may include the notice in a location (such as a LICENSE file in a
+relevant directory) where a recipient would be likely to look for such a
+notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+
+ This Source Code Form is "Incompatible
+ With Secondary Licenses", as defined by
+ the Mozilla Public License, v. 2.0.
+
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/README.md b/vendor/github.com/hashicorp/go-immutable-radix/README.md
new file mode 100644
index 00000000000..aca15a64212
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-immutable-radix/README.md
@@ -0,0 +1,66 @@
+go-immutable-radix [](https://circleci.com/gh/hashicorp/go-immutable-radix/tree/master)
+=========
+
+Provides the `iradix` package that implements an immutable [radix tree](http://en.wikipedia.org/wiki/Radix_tree).
+The package only provides a single `Tree` implementation, optimized for sparse nodes.
+
+As a radix tree, it provides the following:
+ * O(k) operations. In many cases, this can be faster than a hash table since
+ the hash function is an O(k) operation, and hash tables have very poor cache locality.
+ * Minimum / Maximum value lookups
+ * Ordered iteration
+
+A tree supports using a transaction to batch multiple updates (insert, delete)
+in a more efficient manner than performing each operation one at a time.
+
+For a mutable variant, see [go-radix](https://github.com/armon/go-radix).
+
+Documentation
+=============
+
+The full documentation is available on [Godoc](http://godoc.org/github.com/hashicorp/go-immutable-radix).
+
+Example
+=======
+
+Below is a simple example of usage
+
+```go
+// Create a tree
+r := iradix.New()
+r, _, _ = r.Insert([]byte("foo"), 1)
+r, _, _ = r.Insert([]byte("bar"), 2)
+r, _, _ = r.Insert([]byte("foobar"), 2)
+
+// Find the longest prefix match
+m, _, _ := r.Root().LongestPrefix([]byte("foozip"))
+if string(m) != "foo" {
+ panic("should be foo")
+}
+```
+
+Here is an example of performing a range scan of the keys.
+
+```go
+// Create a tree
+r := iradix.New()
+r, _, _ = r.Insert([]byte("001"), 1)
+r, _, _ = r.Insert([]byte("002"), 2)
+r, _, _ = r.Insert([]byte("005"), 5)
+r, _, _ = r.Insert([]byte("010"), 10)
+r, _, _ = r.Insert([]byte("100"), 10)
+
+// Range scan over the keys that sort lexicographically between [003, 050)
+it := r.Root().Iterator()
+it.SeekLowerBound([]byte("003"))
+for key, _, ok := it.Next(); ok; key, _, ok = it.Next() {
+ if key >= "050" {
+ break
+ }
+ fmt.Println(key)
+}
+// Output:
+// 005
+// 010
+```
+
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/edges.go b/vendor/github.com/hashicorp/go-immutable-radix/edges.go
new file mode 100644
index 00000000000..a63674775f2
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-immutable-radix/edges.go
@@ -0,0 +1,21 @@
+package iradix
+
+import "sort"
+
+type edges []edge
+
+func (e edges) Len() int {
+ return len(e)
+}
+
+func (e edges) Less(i, j int) bool {
+ return e[i].label < e[j].label
+}
+
+func (e edges) Swap(i, j int) {
+ e[i], e[j] = e[j], e[i]
+}
+
+func (e edges) Sort() {
+ sort.Sort(e)
+}
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/iradix.go b/vendor/github.com/hashicorp/go-immutable-radix/iradix.go
new file mode 100644
index 00000000000..168bda76dfb
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-immutable-radix/iradix.go
@@ -0,0 +1,676 @@
+package iradix
+
+import (
+ "bytes"
+ "strings"
+
+ "github.com/hashicorp/golang-lru/simplelru"
+)
+
+const (
+ // defaultModifiedCache is the default size of the modified node
+ // cache used per transaction. This is used to cache the updates
+ // to the nodes near the root, while the leaves do not need to be
+ // cached. This is important for very large transactions to prevent
+ // the modified cache from growing to be enormous. This is also used
+ // to set the max size of the mutation notify maps since those should
+ // also be bounded in a similar way.
+ defaultModifiedCache = 8192
+)
+
+// Tree implements an immutable radix tree. This can be treated as a
+// Dictionary abstract data type. The main advantage over a standard
+// hash map is prefix-based lookups and ordered iteration. The immutability
+// means that it is safe to concurrently read from a Tree without any
+// coordination.
+type Tree struct {
+ root *Node
+ size int
+}
+
+// New returns an empty Tree
+func New() *Tree {
+ t := &Tree{
+ root: &Node{
+ mutateCh: make(chan struct{}),
+ },
+ }
+ return t
+}
+
+// Len is used to return the number of elements in the tree
+func (t *Tree) Len() int {
+ return t.size
+}
+
+// Txn is a transaction on the tree. This transaction is applied
+// atomically and returns a new tree when committed. A transaction
+// is not thread safe, and should only be used by a single goroutine.
+type Txn struct {
+ // root is the modified root for the transaction.
+ root *Node
+
+ // snap is a snapshot of the root node for use if we have to run the
+ // slow notify algorithm.
+ snap *Node
+
+ // size tracks the size of the tree as it is modified during the
+ // transaction.
+ size int
+
+ // writable is a cache of writable nodes that have been created during
+ // the course of the transaction. This allows us to re-use the same
+ // nodes for further writes and avoid unnecessary copies of nodes that
+ // have never been exposed outside the transaction. This will only hold
+ // up to defaultModifiedCache number of entries.
+ writable *simplelru.LRU
+
+ // trackChannels is used to hold channels that need to be notified to
+ // signal mutation of the tree. This will only hold up to
+ // defaultModifiedCache number of entries, after which we will set the
+ // trackOverflow flag, which will cause us to use a more expensive
+ // algorithm to perform the notifications. Mutation tracking is only
+ // performed if trackMutate is true.
+ trackChannels map[chan struct{}]struct{}
+ trackOverflow bool
+ trackMutate bool
+}
+
+// Txn starts a new transaction that can be used to mutate the tree
+func (t *Tree) Txn() *Txn {
+ txn := &Txn{
+ root: t.root,
+ snap: t.root,
+ size: t.size,
+ }
+ return txn
+}
+
+// Clone makes an independent copy of the transaction. The new transaction
+// does not track any nodes and has TrackMutate turned off. The cloned transaction will contain any uncommitted writes in the original transaction but further mutations to either will be independent and result in different radix trees on Commit. A cloned transaction may be passed to another goroutine and mutated there independently however each transaction may only be mutated in a single thread.
+func (t *Txn) Clone() *Txn {
+ // reset the writable node cache to avoid leaking future writes into the clone
+ t.writable = nil
+
+ txn := &Txn{
+ root: t.root,
+ snap: t.snap,
+ size: t.size,
+ }
+ return txn
+}
+
+// TrackMutate can be used to toggle if mutations are tracked. If this is enabled
+// then notifications will be issued for affected internal nodes and leaves when
+// the transaction is committed.
+func (t *Txn) TrackMutate(track bool) {
+ t.trackMutate = track
+}
+
+// trackChannel safely attempts to track the given mutation channel, setting the
+// overflow flag if we can no longer track any more. This limits the amount of
+// state that will accumulate during a transaction and we have a slower algorithm
+// to switch to if we overflow.
+func (t *Txn) trackChannel(ch chan struct{}) {
+ // In overflow, make sure we don't store any more objects.
+ if t.trackOverflow {
+ return
+ }
+
+ // If this would overflow the state we reject it and set the flag (since
+ // we aren't tracking everything that's required any longer).
+ if len(t.trackChannels) >= defaultModifiedCache {
+ // Mark that we are in the overflow state
+ t.trackOverflow = true
+
+ // Clear the map so that the channels can be garbage collected. It is
+ // safe to do this since we have already overflowed and will be using
+ // the slow notify algorithm.
+ t.trackChannels = nil
+ return
+ }
+
+ // Create the map on the fly when we need it.
+ if t.trackChannels == nil {
+ t.trackChannels = make(map[chan struct{}]struct{})
+ }
+
+ // Otherwise we are good to track it.
+ t.trackChannels[ch] = struct{}{}
+}
+
+// writeNode returns a node to be modified, if the current node has already been
+// modified during the course of the transaction, it is used in-place. Set
+// forLeafUpdate to true if you are getting a write node to update the leaf,
+// which will set leaf mutation tracking appropriately as well.
+func (t *Txn) writeNode(n *Node, forLeafUpdate bool) *Node {
+ // Ensure the writable set exists.
+ if t.writable == nil {
+ lru, err := simplelru.NewLRU(defaultModifiedCache, nil)
+ if err != nil {
+ panic(err)
+ }
+ t.writable = lru
+ }
+
+ // If this node has already been modified, we can continue to use it
+ // during this transaction. We know that we don't need to track it for
+ // a node update since the node is writable, but if this is for a leaf
+ // update we track it, in case the initial write to this node didn't
+ // update the leaf.
+ if _, ok := t.writable.Get(n); ok {
+ if t.trackMutate && forLeafUpdate && n.leaf != nil {
+ t.trackChannel(n.leaf.mutateCh)
+ }
+ return n
+ }
+
+ // Mark this node as being mutated.
+ if t.trackMutate {
+ t.trackChannel(n.mutateCh)
+ }
+
+ // Mark its leaf as being mutated, if appropriate.
+ if t.trackMutate && forLeafUpdate && n.leaf != nil {
+ t.trackChannel(n.leaf.mutateCh)
+ }
+
+ // Copy the existing node. If you have set forLeafUpdate it will be
+ // safe to replace this leaf with another after you get your node for
+ // writing. You MUST replace it, because the channel associated with
+ // this leaf will be closed when this transaction is committed.
+ nc := &Node{
+ mutateCh: make(chan struct{}),
+ leaf: n.leaf,
+ }
+ if n.prefix != nil {
+ nc.prefix = make([]byte, len(n.prefix))
+ copy(nc.prefix, n.prefix)
+ }
+ if len(n.edges) != 0 {
+ nc.edges = make([]edge, len(n.edges))
+ copy(nc.edges, n.edges)
+ }
+
+ // Mark this node as writable.
+ t.writable.Add(nc, nil)
+ return nc
+}
+
+// Visit all the nodes in the tree under n, and add their mutateChannels to the transaction
+// Returns the size of the subtree visited
+func (t *Txn) trackChannelsAndCount(n *Node) int {
+ // Count only leaf nodes
+ leaves := 0
+ if n.leaf != nil {
+ leaves = 1
+ }
+ // Mark this node as being mutated.
+ if t.trackMutate {
+ t.trackChannel(n.mutateCh)
+ }
+
+ // Mark its leaf as being mutated, if appropriate.
+ if t.trackMutate && n.leaf != nil {
+ t.trackChannel(n.leaf.mutateCh)
+ }
+
+ // Recurse on the children
+ for _, e := range n.edges {
+ leaves += t.trackChannelsAndCount(e.node)
+ }
+ return leaves
+}
+
+// mergeChild is called to collapse the given node with its child. This is only
+// called when the given node is not a leaf and has a single edge.
+func (t *Txn) mergeChild(n *Node) {
+ // Mark the child node as being mutated since we are about to abandon
+ // it. We don't need to mark the leaf since we are retaining it if it
+ // is there.
+ e := n.edges[0]
+ child := e.node
+ if t.trackMutate {
+ t.trackChannel(child.mutateCh)
+ }
+
+ // Merge the nodes.
+ n.prefix = concat(n.prefix, child.prefix)
+ n.leaf = child.leaf
+ if len(child.edges) != 0 {
+ n.edges = make([]edge, len(child.edges))
+ copy(n.edges, child.edges)
+ } else {
+ n.edges = nil
+ }
+}
+
+// insert does a recursive insertion
+func (t *Txn) insert(n *Node, k, search []byte, v interface{}) (*Node, interface{}, bool) {
+ // Handle key exhaustion
+ if len(search) == 0 {
+ var oldVal interface{}
+ didUpdate := false
+ if n.isLeaf() {
+ oldVal = n.leaf.val
+ didUpdate = true
+ }
+
+ nc := t.writeNode(n, true)
+ nc.leaf = &leafNode{
+ mutateCh: make(chan struct{}),
+ key: k,
+ val: v,
+ }
+ return nc, oldVal, didUpdate
+ }
+
+ // Look for the edge
+ idx, child := n.getEdge(search[0])
+
+ // No edge, create one
+ if child == nil {
+ e := edge{
+ label: search[0],
+ node: &Node{
+ mutateCh: make(chan struct{}),
+ leaf: &leafNode{
+ mutateCh: make(chan struct{}),
+ key: k,
+ val: v,
+ },
+ prefix: search,
+ },
+ }
+ nc := t.writeNode(n, false)
+ nc.addEdge(e)
+ return nc, nil, false
+ }
+
+ // Determine longest prefix of the search key on match
+ commonPrefix := longestPrefix(search, child.prefix)
+ if commonPrefix == len(child.prefix) {
+ search = search[commonPrefix:]
+ newChild, oldVal, didUpdate := t.insert(child, k, search, v)
+ if newChild != nil {
+ nc := t.writeNode(n, false)
+ nc.edges[idx].node = newChild
+ return nc, oldVal, didUpdate
+ }
+ return nil, oldVal, didUpdate
+ }
+
+ // Split the node
+ nc := t.writeNode(n, false)
+ splitNode := &Node{
+ mutateCh: make(chan struct{}),
+ prefix: search[:commonPrefix],
+ }
+ nc.replaceEdge(edge{
+ label: search[0],
+ node: splitNode,
+ })
+
+ // Restore the existing child node
+ modChild := t.writeNode(child, false)
+ splitNode.addEdge(edge{
+ label: modChild.prefix[commonPrefix],
+ node: modChild,
+ })
+ modChild.prefix = modChild.prefix[commonPrefix:]
+
+ // Create a new leaf node
+ leaf := &leafNode{
+ mutateCh: make(chan struct{}),
+ key: k,
+ val: v,
+ }
+
+ // If the new key is a subset, add to to this node
+ search = search[commonPrefix:]
+ if len(search) == 0 {
+ splitNode.leaf = leaf
+ return nc, nil, false
+ }
+
+ // Create a new edge for the node
+ splitNode.addEdge(edge{
+ label: search[0],
+ node: &Node{
+ mutateCh: make(chan struct{}),
+ leaf: leaf,
+ prefix: search,
+ },
+ })
+ return nc, nil, false
+}
+
+// delete does a recursive deletion
+func (t *Txn) delete(parent, n *Node, search []byte) (*Node, *leafNode) {
+ // Check for key exhaustion
+ if len(search) == 0 {
+ if !n.isLeaf() {
+ return nil, nil
+ }
+ // Copy the pointer in case we are in a transaction that already
+ // modified this node since the node will be reused. Any changes
+ // made to the node will not affect returning the original leaf
+ // value.
+ oldLeaf := n.leaf
+
+ // Remove the leaf node
+ nc := t.writeNode(n, true)
+ nc.leaf = nil
+
+ // Check if this node should be merged
+ if n != t.root && len(nc.edges) == 1 {
+ t.mergeChild(nc)
+ }
+ return nc, oldLeaf
+ }
+
+ // Look for an edge
+ label := search[0]
+ idx, child := n.getEdge(label)
+ if child == nil || !bytes.HasPrefix(search, child.prefix) {
+ return nil, nil
+ }
+
+ // Consume the search prefix
+ search = search[len(child.prefix):]
+ newChild, leaf := t.delete(n, child, search)
+ if newChild == nil {
+ return nil, nil
+ }
+
+ // Copy this node. WATCH OUT - it's safe to pass "false" here because we
+ // will only ADD a leaf via nc.mergeChild() if there isn't one due to
+ // the !nc.isLeaf() check in the logic just below. This is pretty subtle,
+ // so be careful if you change any of the logic here.
+ nc := t.writeNode(n, false)
+
+ // Delete the edge if the node has no edges
+ if newChild.leaf == nil && len(newChild.edges) == 0 {
+ nc.delEdge(label)
+ if n != t.root && len(nc.edges) == 1 && !nc.isLeaf() {
+ t.mergeChild(nc)
+ }
+ } else {
+ nc.edges[idx].node = newChild
+ }
+ return nc, leaf
+}
+
+// delete does a recursive deletion
+func (t *Txn) deletePrefix(parent, n *Node, search []byte) (*Node, int) {
+ // Check for key exhaustion
+ if len(search) == 0 {
+ nc := t.writeNode(n, true)
+ if n.isLeaf() {
+ nc.leaf = nil
+ }
+ nc.edges = nil
+ return nc, t.trackChannelsAndCount(n)
+ }
+
+ // Look for an edge
+ label := search[0]
+ idx, child := n.getEdge(label)
+ // We make sure that either the child node's prefix starts with the search term, or the search term starts with the child node's prefix
+ // Need to do both so that we can delete prefixes that don't correspond to any node in the tree
+ if child == nil || (!bytes.HasPrefix(child.prefix, search) && !bytes.HasPrefix(search, child.prefix)) {
+ return nil, 0
+ }
+
+ // Consume the search prefix
+ if len(child.prefix) > len(search) {
+ search = []byte("")
+ } else {
+ search = search[len(child.prefix):]
+ }
+ newChild, numDeletions := t.deletePrefix(n, child, search)
+ if newChild == nil {
+ return nil, 0
+ }
+ // Copy this node. WATCH OUT - it's safe to pass "false" here because we
+ // will only ADD a leaf via nc.mergeChild() if there isn't one due to
+ // the !nc.isLeaf() check in the logic just below. This is pretty subtle,
+ // so be careful if you change any of the logic here.
+
+ nc := t.writeNode(n, false)
+
+ // Delete the edge if the node has no edges
+ if newChild.leaf == nil && len(newChild.edges) == 0 {
+ nc.delEdge(label)
+ if n != t.root && len(nc.edges) == 1 && !nc.isLeaf() {
+ t.mergeChild(nc)
+ }
+ } else {
+ nc.edges[idx].node = newChild
+ }
+ return nc, numDeletions
+}
+
+// Insert is used to add or update a given key. The return provides
+// the previous value and a bool indicating if any was set.
+func (t *Txn) Insert(k []byte, v interface{}) (interface{}, bool) {
+ newRoot, oldVal, didUpdate := t.insert(t.root, k, k, v)
+ if newRoot != nil {
+ t.root = newRoot
+ }
+ if !didUpdate {
+ t.size++
+ }
+ return oldVal, didUpdate
+}
+
+// Delete is used to delete a given key. Returns the old value if any,
+// and a bool indicating if the key was set.
+func (t *Txn) Delete(k []byte) (interface{}, bool) {
+ newRoot, leaf := t.delete(nil, t.root, k)
+ if newRoot != nil {
+ t.root = newRoot
+ }
+ if leaf != nil {
+ t.size--
+ return leaf.val, true
+ }
+ return nil, false
+}
+
+// DeletePrefix is used to delete an entire subtree that matches the prefix
+// This will delete all nodes under that prefix
+func (t *Txn) DeletePrefix(prefix []byte) bool {
+ newRoot, numDeletions := t.deletePrefix(nil, t.root, prefix)
+ if newRoot != nil {
+ t.root = newRoot
+ t.size = t.size - numDeletions
+ return true
+ }
+ return false
+
+}
+
+// Root returns the current root of the radix tree within this
+// transaction. The root is not safe across insert and delete operations,
+// but can be used to read the current state during a transaction.
+func (t *Txn) Root() *Node {
+ return t.root
+}
+
+// Get is used to lookup a specific key, returning
+// the value and if it was found
+func (t *Txn) Get(k []byte) (interface{}, bool) {
+ return t.root.Get(k)
+}
+
+// GetWatch is used to lookup a specific key, returning
+// the watch channel, value and if it was found
+func (t *Txn) GetWatch(k []byte) (<-chan struct{}, interface{}, bool) {
+ return t.root.GetWatch(k)
+}
+
+// Commit is used to finalize the transaction and return a new tree. If mutation
+// tracking is turned on then notifications will also be issued.
+func (t *Txn) Commit() *Tree {
+ nt := t.CommitOnly()
+ if t.trackMutate {
+ t.Notify()
+ }
+ return nt
+}
+
+// CommitOnly is used to finalize the transaction and return a new tree, but
+// does not issue any notifications until Notify is called.
+func (t *Txn) CommitOnly() *Tree {
+ nt := &Tree{t.root, t.size}
+ t.writable = nil
+ return nt
+}
+
+// slowNotify does a complete comparison of the before and after trees in order
+// to trigger notifications. This doesn't require any additional state but it
+// is very expensive to compute.
+func (t *Txn) slowNotify() {
+ snapIter := t.snap.rawIterator()
+ rootIter := t.root.rawIterator()
+ for snapIter.Front() != nil || rootIter.Front() != nil {
+ // If we've exhausted the nodes in the old snapshot, we know
+ // there's nothing remaining to notify.
+ if snapIter.Front() == nil {
+ return
+ }
+ snapElem := snapIter.Front()
+
+ // If we've exhausted the nodes in the new root, we know we need
+ // to invalidate everything that remains in the old snapshot. We
+ // know from the loop condition there's something in the old
+ // snapshot.
+ if rootIter.Front() == nil {
+ close(snapElem.mutateCh)
+ if snapElem.isLeaf() {
+ close(snapElem.leaf.mutateCh)
+ }
+ snapIter.Next()
+ continue
+ }
+
+ // Do one string compare so we can check the various conditions
+ // below without repeating the compare.
+ cmp := strings.Compare(snapIter.Path(), rootIter.Path())
+
+ // If the snapshot is behind the root, then we must have deleted
+ // this node during the transaction.
+ if cmp < 0 {
+ close(snapElem.mutateCh)
+ if snapElem.isLeaf() {
+ close(snapElem.leaf.mutateCh)
+ }
+ snapIter.Next()
+ continue
+ }
+
+ // If the snapshot is ahead of the root, then we must have added
+ // this node during the transaction.
+ if cmp > 0 {
+ rootIter.Next()
+ continue
+ }
+
+ // If we have the same path, then we need to see if we mutated a
+ // node and possibly the leaf.
+ rootElem := rootIter.Front()
+ if snapElem != rootElem {
+ close(snapElem.mutateCh)
+ if snapElem.leaf != nil && (snapElem.leaf != rootElem.leaf) {
+ close(snapElem.leaf.mutateCh)
+ }
+ }
+ snapIter.Next()
+ rootIter.Next()
+ }
+}
+
+// Notify is used along with TrackMutate to trigger notifications. This must
+// only be done once a transaction is committed via CommitOnly, and it is called
+// automatically by Commit.
+func (t *Txn) Notify() {
+ if !t.trackMutate {
+ return
+ }
+
+ // If we've overflowed the tracking state we can't use it in any way and
+ // need to do a full tree compare.
+ if t.trackOverflow {
+ t.slowNotify()
+ } else {
+ for ch := range t.trackChannels {
+ close(ch)
+ }
+ }
+
+ // Clean up the tracking state so that a re-notify is safe (will trigger
+ // the else clause above which will be a no-op).
+ t.trackChannels = nil
+ t.trackOverflow = false
+}
+
+// Insert is used to add or update a given key. The return provides
+// the new tree, previous value and a bool indicating if any was set.
+func (t *Tree) Insert(k []byte, v interface{}) (*Tree, interface{}, bool) {
+ txn := t.Txn()
+ old, ok := txn.Insert(k, v)
+ return txn.Commit(), old, ok
+}
+
+// Delete is used to delete a given key. Returns the new tree,
+// old value if any, and a bool indicating if the key was set.
+func (t *Tree) Delete(k []byte) (*Tree, interface{}, bool) {
+ txn := t.Txn()
+ old, ok := txn.Delete(k)
+ return txn.Commit(), old, ok
+}
+
+// DeletePrefix is used to delete all nodes starting with a given prefix. Returns the new tree,
+// and a bool indicating if the prefix matched any nodes
+func (t *Tree) DeletePrefix(k []byte) (*Tree, bool) {
+ txn := t.Txn()
+ ok := txn.DeletePrefix(k)
+ return txn.Commit(), ok
+}
+
+// Root returns the root node of the tree which can be used for richer
+// query operations.
+func (t *Tree) Root() *Node {
+ return t.root
+}
+
+// Get is used to lookup a specific key, returning
+// the value and if it was found
+func (t *Tree) Get(k []byte) (interface{}, bool) {
+ return t.root.Get(k)
+}
+
+// longestPrefix finds the length of the shared prefix
+// of two strings
+func longestPrefix(k1, k2 []byte) int {
+ max := len(k1)
+ if l := len(k2); l < max {
+ max = l
+ }
+ var i int
+ for i = 0; i < max; i++ {
+ if k1[i] != k2[i] {
+ break
+ }
+ }
+ return i
+}
+
+// concat two byte slices, returning a third new copy
+func concat(a, b []byte) []byte {
+ c := make([]byte, len(a)+len(b))
+ copy(c, a)
+ copy(c[len(a):], b)
+ return c
+}
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/iter.go b/vendor/github.com/hashicorp/go-immutable-radix/iter.go
new file mode 100644
index 00000000000..f17d0a644f4
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-immutable-radix/iter.go
@@ -0,0 +1,205 @@
+package iradix
+
+import (
+ "bytes"
+)
+
+// Iterator is used to iterate over a set of nodes
+// in pre-order
+type Iterator struct {
+ node *Node
+ stack []edges
+}
+
+// SeekPrefixWatch is used to seek the iterator to a given prefix
+// and returns the watch channel of the finest granularity
+func (i *Iterator) SeekPrefixWatch(prefix []byte) (watch <-chan struct{}) {
+ // Wipe the stack
+ i.stack = nil
+ n := i.node
+ watch = n.mutateCh
+ search := prefix
+ for {
+ // Check for key exhaustion
+ if len(search) == 0 {
+ i.node = n
+ return
+ }
+
+ // Look for an edge
+ _, n = n.getEdge(search[0])
+ if n == nil {
+ i.node = nil
+ return
+ }
+
+ // Update to the finest granularity as the search makes progress
+ watch = n.mutateCh
+
+ // Consume the search prefix
+ if bytes.HasPrefix(search, n.prefix) {
+ search = search[len(n.prefix):]
+
+ } else if bytes.HasPrefix(n.prefix, search) {
+ i.node = n
+ return
+ } else {
+ i.node = nil
+ return
+ }
+ }
+}
+
+// SeekPrefix is used to seek the iterator to a given prefix
+func (i *Iterator) SeekPrefix(prefix []byte) {
+ i.SeekPrefixWatch(prefix)
+}
+
+func (i *Iterator) recurseMin(n *Node) *Node {
+ // Traverse to the minimum child
+ if n.leaf != nil {
+ return n
+ }
+ nEdges := len(n.edges)
+ if nEdges > 1 {
+ // Add all the other edges to the stack (the min node will be added as
+ // we recurse)
+ i.stack = append(i.stack, n.edges[1:])
+ }
+ if nEdges > 0 {
+ return i.recurseMin(n.edges[0].node)
+ }
+ // Shouldn't be possible
+ return nil
+}
+
+// SeekLowerBound is used to seek the iterator to the smallest key that is
+// greater or equal to the given key. There is no watch variant as it's hard to
+// predict based on the radix structure which node(s) changes might affect the
+// result.
+func (i *Iterator) SeekLowerBound(key []byte) {
+ // Wipe the stack. Unlike Prefix iteration, we need to build the stack as we
+ // go because we need only a subset of edges of many nodes in the path to the
+ // leaf with the lower bound. Note that the iterator will still recurse into
+ // children that we don't traverse on the way to the reverse lower bound as it
+ // walks the stack.
+ i.stack = []edges{}
+ // i.node starts off in the common case as pointing to the root node of the
+ // tree. By the time we return we have either found a lower bound and setup
+ // the stack to traverse all larger keys, or we have not and the stack and
+ // node should both be nil to prevent the iterator from assuming it is just
+ // iterating the whole tree from the root node. Either way this needs to end
+ // up as nil so just set it here.
+ n := i.node
+ i.node = nil
+ search := key
+
+ found := func(n *Node) {
+ i.stack = append(i.stack, edges{edge{node: n}})
+ }
+
+ findMin := func(n *Node) {
+ n = i.recurseMin(n)
+ if n != nil {
+ found(n)
+ return
+ }
+ }
+
+ for {
+ // Compare current prefix with the search key's same-length prefix.
+ var prefixCmp int
+ if len(n.prefix) < len(search) {
+ prefixCmp = bytes.Compare(n.prefix, search[0:len(n.prefix)])
+ } else {
+ prefixCmp = bytes.Compare(n.prefix, search)
+ }
+
+ if prefixCmp > 0 {
+ // Prefix is larger, that means the lower bound is greater than the search
+ // and from now on we need to follow the minimum path to the smallest
+ // leaf under this subtree.
+ findMin(n)
+ return
+ }
+
+ if prefixCmp < 0 {
+ // Prefix is smaller than search prefix, that means there is no lower
+ // bound
+ i.node = nil
+ return
+ }
+
+ // Prefix is equal, we are still heading for an exact match. If this is a
+ // leaf and an exact match we're done.
+ if n.leaf != nil && bytes.Equal(n.leaf.key, key) {
+ found(n)
+ return
+ }
+
+ // Consume the search prefix if the current node has one. Note that this is
+ // safe because if n.prefix is longer than the search slice prefixCmp would
+ // have been > 0 above and the method would have already returned.
+ search = search[len(n.prefix):]
+
+ if len(search) == 0 {
+ // We've exhausted the search key, but the current node is not an exact
+ // match or not a leaf. That means that the leaf value if it exists, and
+ // all child nodes must be strictly greater, the smallest key in this
+ // subtree must be the lower bound.
+ findMin(n)
+ return
+ }
+
+ // Otherwise, take the lower bound next edge.
+ idx, lbNode := n.getLowerBoundEdge(search[0])
+ if lbNode == nil {
+ return
+ }
+
+ // Create stack edges for the all strictly higher edges in this node.
+ if idx+1 < len(n.edges) {
+ i.stack = append(i.stack, n.edges[idx+1:])
+ }
+
+ // Recurse
+ n = lbNode
+ }
+}
+
+// Next returns the next node in order
+func (i *Iterator) Next() ([]byte, interface{}, bool) {
+ // Initialize our stack if needed
+ if i.stack == nil && i.node != nil {
+ i.stack = []edges{
+ {
+ edge{node: i.node},
+ },
+ }
+ }
+
+ for len(i.stack) > 0 {
+ // Inspect the last element of the stack
+ n := len(i.stack)
+ last := i.stack[n-1]
+ elem := last[0].node
+
+ // Update the stack
+ if len(last) > 1 {
+ i.stack[n-1] = last[1:]
+ } else {
+ i.stack = i.stack[:n-1]
+ }
+
+ // Push the edges onto the frontier
+ if len(elem.edges) > 0 {
+ i.stack = append(i.stack, elem.edges)
+ }
+
+ // Return the leaf values if any
+ if elem.leaf != nil {
+ return elem.leaf.key, elem.leaf.val, true
+ }
+ }
+ return nil, nil, false
+}
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/node.go b/vendor/github.com/hashicorp/go-immutable-radix/node.go
new file mode 100644
index 00000000000..35985480872
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-immutable-radix/node.go
@@ -0,0 +1,334 @@
+package iradix
+
+import (
+ "bytes"
+ "sort"
+)
+
+// WalkFn is used when walking the tree. Takes a
+// key and value, returning if iteration should
+// be terminated.
+type WalkFn func(k []byte, v interface{}) bool
+
+// leafNode is used to represent a value
+type leafNode struct {
+ mutateCh chan struct{}
+ key []byte
+ val interface{}
+}
+
+// edge is used to represent an edge node
+type edge struct {
+ label byte
+ node *Node
+}
+
+// Node is an immutable node in the radix tree
+type Node struct {
+ // mutateCh is closed if this node is modified
+ mutateCh chan struct{}
+
+ // leaf is used to store possible leaf
+ leaf *leafNode
+
+ // prefix is the common prefix we ignore
+ prefix []byte
+
+ // Edges should be stored in-order for iteration.
+ // We avoid a fully materialized slice to save memory,
+ // since in most cases we expect to be sparse
+ edges edges
+}
+
+func (n *Node) isLeaf() bool {
+ return n.leaf != nil
+}
+
+func (n *Node) addEdge(e edge) {
+ num := len(n.edges)
+ idx := sort.Search(num, func(i int) bool {
+ return n.edges[i].label >= e.label
+ })
+ n.edges = append(n.edges, e)
+ if idx != num {
+ copy(n.edges[idx+1:], n.edges[idx:num])
+ n.edges[idx] = e
+ }
+}
+
+func (n *Node) replaceEdge(e edge) {
+ num := len(n.edges)
+ idx := sort.Search(num, func(i int) bool {
+ return n.edges[i].label >= e.label
+ })
+ if idx < num && n.edges[idx].label == e.label {
+ n.edges[idx].node = e.node
+ return
+ }
+ panic("replacing missing edge")
+}
+
+func (n *Node) getEdge(label byte) (int, *Node) {
+ num := len(n.edges)
+ idx := sort.Search(num, func(i int) bool {
+ return n.edges[i].label >= label
+ })
+ if idx < num && n.edges[idx].label == label {
+ return idx, n.edges[idx].node
+ }
+ return -1, nil
+}
+
+func (n *Node) getLowerBoundEdge(label byte) (int, *Node) {
+ num := len(n.edges)
+ idx := sort.Search(num, func(i int) bool {
+ return n.edges[i].label >= label
+ })
+ // we want lower bound behavior so return even if it's not an exact match
+ if idx < num {
+ return idx, n.edges[idx].node
+ }
+ return -1, nil
+}
+
+func (n *Node) delEdge(label byte) {
+ num := len(n.edges)
+ idx := sort.Search(num, func(i int) bool {
+ return n.edges[i].label >= label
+ })
+ if idx < num && n.edges[idx].label == label {
+ copy(n.edges[idx:], n.edges[idx+1:])
+ n.edges[len(n.edges)-1] = edge{}
+ n.edges = n.edges[:len(n.edges)-1]
+ }
+}
+
+func (n *Node) GetWatch(k []byte) (<-chan struct{}, interface{}, bool) {
+ search := k
+ watch := n.mutateCh
+ for {
+ // Check for key exhaustion
+ if len(search) == 0 {
+ if n.isLeaf() {
+ return n.leaf.mutateCh, n.leaf.val, true
+ }
+ break
+ }
+
+ // Look for an edge
+ _, n = n.getEdge(search[0])
+ if n == nil {
+ break
+ }
+
+ // Update to the finest granularity as the search makes progress
+ watch = n.mutateCh
+
+ // Consume the search prefix
+ if bytes.HasPrefix(search, n.prefix) {
+ search = search[len(n.prefix):]
+ } else {
+ break
+ }
+ }
+ return watch, nil, false
+}
+
+func (n *Node) Get(k []byte) (interface{}, bool) {
+ _, val, ok := n.GetWatch(k)
+ return val, ok
+}
+
+// LongestPrefix is like Get, but instead of an
+// exact match, it will return the longest prefix match.
+func (n *Node) LongestPrefix(k []byte) ([]byte, interface{}, bool) {
+ var last *leafNode
+ search := k
+ for {
+ // Look for a leaf node
+ if n.isLeaf() {
+ last = n.leaf
+ }
+
+ // Check for key exhaution
+ if len(search) == 0 {
+ break
+ }
+
+ // Look for an edge
+ _, n = n.getEdge(search[0])
+ if n == nil {
+ break
+ }
+
+ // Consume the search prefix
+ if bytes.HasPrefix(search, n.prefix) {
+ search = search[len(n.prefix):]
+ } else {
+ break
+ }
+ }
+ if last != nil {
+ return last.key, last.val, true
+ }
+ return nil, nil, false
+}
+
+// Minimum is used to return the minimum value in the tree
+func (n *Node) Minimum() ([]byte, interface{}, bool) {
+ for {
+ if n.isLeaf() {
+ return n.leaf.key, n.leaf.val, true
+ }
+ if len(n.edges) > 0 {
+ n = n.edges[0].node
+ } else {
+ break
+ }
+ }
+ return nil, nil, false
+}
+
+// Maximum is used to return the maximum value in the tree
+func (n *Node) Maximum() ([]byte, interface{}, bool) {
+ for {
+ if num := len(n.edges); num > 0 {
+ n = n.edges[num-1].node
+ continue
+ }
+ if n.isLeaf() {
+ return n.leaf.key, n.leaf.val, true
+ } else {
+ break
+ }
+ }
+ return nil, nil, false
+}
+
+// Iterator is used to return an iterator at
+// the given node to walk the tree
+func (n *Node) Iterator() *Iterator {
+ return &Iterator{node: n}
+}
+
+// ReverseIterator is used to return an iterator at
+// the given node to walk the tree backwards
+func (n *Node) ReverseIterator() *ReverseIterator {
+ return NewReverseIterator(n)
+}
+
+// rawIterator is used to return a raw iterator at the given node to walk the
+// tree.
+func (n *Node) rawIterator() *rawIterator {
+ iter := &rawIterator{node: n}
+ iter.Next()
+ return iter
+}
+
+// Walk is used to walk the tree
+func (n *Node) Walk(fn WalkFn) {
+ recursiveWalk(n, fn)
+}
+
+// WalkBackwards is used to walk the tree in reverse order
+func (n *Node) WalkBackwards(fn WalkFn) {
+ reverseRecursiveWalk(n, fn)
+}
+
+// WalkPrefix is used to walk the tree under a prefix
+func (n *Node) WalkPrefix(prefix []byte, fn WalkFn) {
+ search := prefix
+ for {
+ // Check for key exhaution
+ if len(search) == 0 {
+ recursiveWalk(n, fn)
+ return
+ }
+
+ // Look for an edge
+ _, n = n.getEdge(search[0])
+ if n == nil {
+ break
+ }
+
+ // Consume the search prefix
+ if bytes.HasPrefix(search, n.prefix) {
+ search = search[len(n.prefix):]
+
+ } else if bytes.HasPrefix(n.prefix, search) {
+ // Child may be under our search prefix
+ recursiveWalk(n, fn)
+ return
+ } else {
+ break
+ }
+ }
+}
+
+// WalkPath is used to walk the tree, but only visiting nodes
+// from the root down to a given leaf. Where WalkPrefix walks
+// all the entries *under* the given prefix, this walks the
+// entries *above* the given prefix.
+func (n *Node) WalkPath(path []byte, fn WalkFn) {
+ search := path
+ for {
+ // Visit the leaf values if any
+ if n.leaf != nil && fn(n.leaf.key, n.leaf.val) {
+ return
+ }
+
+ // Check for key exhaution
+ if len(search) == 0 {
+ return
+ }
+
+ // Look for an edge
+ _, n = n.getEdge(search[0])
+ if n == nil {
+ return
+ }
+
+ // Consume the search prefix
+ if bytes.HasPrefix(search, n.prefix) {
+ search = search[len(n.prefix):]
+ } else {
+ break
+ }
+ }
+}
+
+// recursiveWalk is used to do a pre-order walk of a node
+// recursively. Returns true if the walk should be aborted
+func recursiveWalk(n *Node, fn WalkFn) bool {
+ // Visit the leaf values if any
+ if n.leaf != nil && fn(n.leaf.key, n.leaf.val) {
+ return true
+ }
+
+ // Recurse on the children
+ for _, e := range n.edges {
+ if recursiveWalk(e.node, fn) {
+ return true
+ }
+ }
+ return false
+}
+
+// reverseRecursiveWalk is used to do a reverse pre-order
+// walk of a node recursively. Returns true if the walk
+// should be aborted
+func reverseRecursiveWalk(n *Node, fn WalkFn) bool {
+ // Visit the leaf values if any
+ if n.leaf != nil && fn(n.leaf.key, n.leaf.val) {
+ return true
+ }
+
+ // Recurse on the children in reverse order
+ for i := len(n.edges) - 1; i >= 0; i-- {
+ e := n.edges[i]
+ if reverseRecursiveWalk(e.node, fn) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/raw_iter.go b/vendor/github.com/hashicorp/go-immutable-radix/raw_iter.go
new file mode 100644
index 00000000000..3c6a22525c8
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-immutable-radix/raw_iter.go
@@ -0,0 +1,78 @@
+package iradix
+
+// rawIterator visits each of the nodes in the tree, even the ones that are not
+// leaves. It keeps track of the effective path (what a leaf at a given node
+// would be called), which is useful for comparing trees.
+type rawIterator struct {
+ // node is the starting node in the tree for the iterator.
+ node *Node
+
+ // stack keeps track of edges in the frontier.
+ stack []rawStackEntry
+
+ // pos is the current position of the iterator.
+ pos *Node
+
+ // path is the effective path of the current iterator position,
+ // regardless of whether the current node is a leaf.
+ path string
+}
+
+// rawStackEntry is used to keep track of the cumulative common path as well as
+// its associated edges in the frontier.
+type rawStackEntry struct {
+ path string
+ edges edges
+}
+
+// Front returns the current node that has been iterated to.
+func (i *rawIterator) Front() *Node {
+ return i.pos
+}
+
+// Path returns the effective path of the current node, even if it's not actually
+// a leaf.
+func (i *rawIterator) Path() string {
+ return i.path
+}
+
+// Next advances the iterator to the next node.
+func (i *rawIterator) Next() {
+ // Initialize our stack if needed.
+ if i.stack == nil && i.node != nil {
+ i.stack = []rawStackEntry{
+ {
+ edges: edges{
+ edge{node: i.node},
+ },
+ },
+ }
+ }
+
+ for len(i.stack) > 0 {
+ // Inspect the last element of the stack.
+ n := len(i.stack)
+ last := i.stack[n-1]
+ elem := last.edges[0].node
+
+ // Update the stack.
+ if len(last.edges) > 1 {
+ i.stack[n-1].edges = last.edges[1:]
+ } else {
+ i.stack = i.stack[:n-1]
+ }
+
+ // Push the edges onto the frontier.
+ if len(elem.edges) > 0 {
+ path := last.path + string(elem.prefix)
+ i.stack = append(i.stack, rawStackEntry{path, elem.edges})
+ }
+
+ i.pos = elem
+ i.path = last.path + string(elem.prefix)
+ return
+ }
+
+ i.pos = nil
+ i.path = ""
+}
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/reverse_iter.go b/vendor/github.com/hashicorp/go-immutable-radix/reverse_iter.go
new file mode 100644
index 00000000000..554fa7129c1
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-immutable-radix/reverse_iter.go
@@ -0,0 +1,239 @@
+package iradix
+
+import (
+ "bytes"
+)
+
+// ReverseIterator is used to iterate over a set of nodes
+// in reverse in-order
+type ReverseIterator struct {
+ i *Iterator
+
+ // expandedParents stores the set of parent nodes whose relevant children have
+ // already been pushed into the stack. This can happen during seek or during
+ // iteration.
+ //
+ // Unlike forward iteration we need to recurse into children before we can
+ // output the value stored in an internal leaf since all children are greater.
+ // We use this to track whether we have already ensured all the children are
+ // in the stack.
+ expandedParents map[*Node]struct{}
+}
+
+// NewReverseIterator returns a new ReverseIterator at a node
+func NewReverseIterator(n *Node) *ReverseIterator {
+ return &ReverseIterator{
+ i: &Iterator{node: n},
+ }
+}
+
+// SeekPrefixWatch is used to seek the iterator to a given prefix
+// and returns the watch channel of the finest granularity
+func (ri *ReverseIterator) SeekPrefixWatch(prefix []byte) (watch <-chan struct{}) {
+ return ri.i.SeekPrefixWatch(prefix)
+}
+
+// SeekPrefix is used to seek the iterator to a given prefix
+func (ri *ReverseIterator) SeekPrefix(prefix []byte) {
+ ri.i.SeekPrefixWatch(prefix)
+}
+
+// SeekReverseLowerBound is used to seek the iterator to the largest key that is
+// lower or equal to the given key. There is no watch variant as it's hard to
+// predict based on the radix structure which node(s) changes might affect the
+// result.
+func (ri *ReverseIterator) SeekReverseLowerBound(key []byte) {
+ // Wipe the stack. Unlike Prefix iteration, we need to build the stack as we
+ // go because we need only a subset of edges of many nodes in the path to the
+ // leaf with the lower bound. Note that the iterator will still recurse into
+ // children that we don't traverse on the way to the reverse lower bound as it
+ // walks the stack.
+ ri.i.stack = []edges{}
+ // ri.i.node starts off in the common case as pointing to the root node of the
+ // tree. By the time we return we have either found a lower bound and setup
+ // the stack to traverse all larger keys, or we have not and the stack and
+ // node should both be nil to prevent the iterator from assuming it is just
+ // iterating the whole tree from the root node. Either way this needs to end
+ // up as nil so just set it here.
+ n := ri.i.node
+ ri.i.node = nil
+ search := key
+
+ if ri.expandedParents == nil {
+ ri.expandedParents = make(map[*Node]struct{})
+ }
+
+ found := func(n *Node) {
+ ri.i.stack = append(ri.i.stack, edges{edge{node: n}})
+ // We need to mark this node as expanded in advance too otherwise the
+ // iterator will attempt to walk all of its children even though they are
+ // greater than the lower bound we have found. We've expanded it in the
+ // sense that all of its children that we want to walk are already in the
+ // stack (i.e. none of them).
+ ri.expandedParents[n] = struct{}{}
+ }
+
+ for {
+ // Compare current prefix with the search key's same-length prefix.
+ var prefixCmp int
+ if len(n.prefix) < len(search) {
+ prefixCmp = bytes.Compare(n.prefix, search[0:len(n.prefix)])
+ } else {
+ prefixCmp = bytes.Compare(n.prefix, search)
+ }
+
+ if prefixCmp < 0 {
+ // Prefix is smaller than search prefix, that means there is no exact
+ // match for the search key. But we are looking in reverse, so the reverse
+ // lower bound will be the largest leaf under this subtree, since it is
+ // the value that would come right before the current search key if it
+ // were in the tree. So we need to follow the maximum path in this subtree
+ // to find it. Note that this is exactly what the iterator will already do
+ // if it finds a node in the stack that has _not_ been marked as expanded
+ // so in this one case we don't call `found` and instead let the iterator
+ // do the expansion and recursion through all the children.
+ ri.i.stack = append(ri.i.stack, edges{edge{node: n}})
+ return
+ }
+
+ if prefixCmp > 0 {
+ // Prefix is larger than search prefix, or there is no prefix but we've
+ // also exhausted the search key. Either way, that means there is no
+ // reverse lower bound since nothing comes before our current search
+ // prefix.
+ return
+ }
+
+ // If this is a leaf, something needs to happen! Note that if it's a leaf
+ // and prefixCmp was zero (which it must be to get here) then the leaf value
+ // is either an exact match for the search, or it's lower. It can't be
+ // greater.
+ if n.isLeaf() {
+
+ // Firstly, if it's an exact match, we're done!
+ if bytes.Equal(n.leaf.key, key) {
+ found(n)
+ return
+ }
+
+ // It's not so this node's leaf value must be lower and could still be a
+ // valid contender for reverse lower bound.
+
+ // If it has no children then we are also done.
+ if len(n.edges) == 0 {
+ // This leaf is the lower bound.
+ found(n)
+ return
+ }
+
+ // Finally, this leaf is internal (has children) so we'll keep searching,
+ // but we need to add it to the iterator's stack since it has a leaf value
+ // that needs to be iterated over. It needs to be added to the stack
+ // before its children below as it comes first.
+ ri.i.stack = append(ri.i.stack, edges{edge{node: n}})
+ // We also need to mark it as expanded since we'll be adding any of its
+ // relevant children below and so don't want the iterator to re-add them
+ // on its way back up the stack.
+ ri.expandedParents[n] = struct{}{}
+ }
+
+ // Consume the search prefix. Note that this is safe because if n.prefix is
+ // longer than the search slice prefixCmp would have been > 0 above and the
+ // method would have already returned.
+ search = search[len(n.prefix):]
+
+ if len(search) == 0 {
+ // We've exhausted the search key but we are not at a leaf. That means all
+ // children are greater than the search key so a reverse lower bound
+ // doesn't exist in this subtree. Note that there might still be one in
+ // the whole radix tree by following a different path somewhere further
+ // up. If that's the case then the iterator's stack will contain all the
+ // smaller nodes already and Previous will walk through them correctly.
+ return
+ }
+
+ // Otherwise, take the lower bound next edge.
+ idx, lbNode := n.getLowerBoundEdge(search[0])
+
+ // From here, we need to update the stack with all values lower than
+ // the lower bound edge. Since getLowerBoundEdge() returns -1 when the
+ // search prefix is larger than all edges, we need to place idx at the
+ // last edge index so they can all be place in the stack, since they
+ // come before our search prefix.
+ if idx == -1 {
+ idx = len(n.edges)
+ }
+
+ // Create stack edges for the all strictly lower edges in this node.
+ if len(n.edges[:idx]) > 0 {
+ ri.i.stack = append(ri.i.stack, n.edges[:idx])
+ }
+
+ // Exit if there's no lower bound edge. The stack will have the previous
+ // nodes already.
+ if lbNode == nil {
+ return
+ }
+
+ // Recurse
+ n = lbNode
+ }
+}
+
+// Previous returns the previous node in reverse order
+func (ri *ReverseIterator) Previous() ([]byte, interface{}, bool) {
+ // Initialize our stack if needed
+ if ri.i.stack == nil && ri.i.node != nil {
+ ri.i.stack = []edges{
+ {
+ edge{node: ri.i.node},
+ },
+ }
+ }
+
+ if ri.expandedParents == nil {
+ ri.expandedParents = make(map[*Node]struct{})
+ }
+
+ for len(ri.i.stack) > 0 {
+ // Inspect the last element of the stack
+ n := len(ri.i.stack)
+ last := ri.i.stack[n-1]
+ m := len(last)
+ elem := last[m-1].node
+
+ _, alreadyExpanded := ri.expandedParents[elem]
+
+ // If this is an internal node and we've not seen it already, we need to
+ // leave it in the stack so we can return its possible leaf value _after_
+ // we've recursed through all its children.
+ if len(elem.edges) > 0 && !alreadyExpanded {
+ // record that we've seen this node!
+ ri.expandedParents[elem] = struct{}{}
+ // push child edges onto stack and skip the rest of the loop to recurse
+ // into the largest one.
+ ri.i.stack = append(ri.i.stack, elem.edges)
+ continue
+ }
+
+ // Remove the node from the stack
+ if m > 1 {
+ ri.i.stack[n-1] = last[:m-1]
+ } else {
+ ri.i.stack = ri.i.stack[:n-1]
+ }
+ // We don't need this state any more as it's no longer in the stack so we
+ // won't visit it again
+ if alreadyExpanded {
+ delete(ri.expandedParents, elem)
+ }
+
+ // If this is a leaf, return it
+ if elem.leaf != nil {
+ return elem.leaf.key, elem.leaf.val, true
+ }
+
+ // it's not a leaf so keep walking the stack to find the previous leaf
+ }
+ return nil, nil, false
+}
diff --git a/vendor/github.com/hashicorp/go-metrics/.gitignore b/vendor/github.com/hashicorp/go-metrics/.gitignore
new file mode 100644
index 00000000000..e5750f5720e
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/.gitignore
@@ -0,0 +1,26 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+/metrics.out
+
+.idea
diff --git a/vendor/github.com/hashicorp/go-metrics/.travis.yml b/vendor/github.com/hashicorp/go-metrics/.travis.yml
new file mode 100644
index 00000000000..24faeac3ab5
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/.travis.yml
@@ -0,0 +1,16 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MIT
+
+language: go
+
+go:
+ - "1.x"
+
+env:
+ - GO111MODULE=on
+
+install:
+ - go get ./...
+
+script:
+ - go test ./...
diff --git a/vendor/github.com/hashicorp/go-metrics/LICENSE b/vendor/github.com/hashicorp/go-metrics/LICENSE
new file mode 100644
index 00000000000..800f14ba0d0
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/LICENSE
@@ -0,0 +1,18 @@
+Copyright (c) 2013 HashiCorp, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/hashicorp/go-metrics/README.md b/vendor/github.com/hashicorp/go-metrics/README.md
new file mode 100644
index 00000000000..763fc5eb731
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/README.md
@@ -0,0 +1,131 @@
+go-metrics
+==========
+
+This library provides a `metrics` package which can be used to instrument code,
+expose application metrics, and profile runtime performance in a flexible manner.
+
+Current API: [](https://godoc.org/github.com/hashicorp/go-metrics)
+
+Sinks
+-----
+
+The `metrics` package makes use of a `MetricSink` interface to support delivery
+to any type of backend. Currently the following sinks are provided:
+
+* StatsiteSink : Sinks to a [statsite](https://github.com/statsite/statsite/) instance (TCP)
+* StatsdSink: Sinks to a [StatsD](https://github.com/statsd/statsd/) / statsite instance (UDP)
+* PrometheusSink: Sinks to a [Prometheus](http://prometheus.io/) metrics endpoint (exposed via HTTP for scrapes)
+* InmemSink : Provides in-memory aggregation, can be used to export stats
+* FanoutSink : Sinks to multiple sinks. Enables writing to multiple statsite instances for example.
+* BlackholeSink : Sinks to nowhere
+
+In addition to the sinks, the `InmemSignal` can be used to catch a signal,
+and dump a formatted output of recent metrics. For example, when a process gets
+a SIGUSR1, it can dump to stderr recent performance metrics for debugging.
+
+Labels
+------
+
+Most metrics do have an equivalent ending with `WithLabels`, such methods
+allow to push metrics with labels and use some features of underlying Sinks
+(ex: translated into Prometheus labels).
+
+Since some of these labels may increase the cardinality of metrics, the
+library allows filtering labels using a allow/block list filtering system
+which is global to all metrics.
+
+* If `Config.AllowedLabels` is not nil, then only labels specified in this value will be sent to underlying Sink, otherwise, all labels are sent by default.
+* If `Config.BlockedLabels` is not nil, any label specified in this value will not be sent to underlying Sinks.
+
+By default, both `Config.AllowedLabels` and `Config.BlockedLabels` are nil, meaning that
+no tags are filtered at all, but it allows a user to globally block some tags with high
+cardinality at the application level.
+
+Backwards Compatibility
+-----------------------
+v0.5.0 of the library renamed the Go module from `github.com/armon/go-metrics` to `github.com/hashicorp/go-metrics`.
+While this did not introduce any breaking changes to the API, the change did subtly break backwards compatibility.
+
+In essence, Go treats a renamed module as entirely distinct and will happily compile both modules into the same binary.
+Due to most uses of the go-metrics library involving emitting metrics via the global metrics handler, having two global
+metrics handlers could cause a subset of metrics to be effectively lost. As an example, if your application configures
+go-metrics exporting via the `armon` namespace, then any metrics sent to go-metrics via the `hashicorp` namespaced module
+will never get exported.
+
+Eventually all usage of `armon/go-metrics` should be replaced with usage of `hashicorp/go-metrics`. However, a single
+point-in-time coordinated update across all libraries that an application may depend on isn't always feasible. To facilitate migrations,
+a `github.com/hashicorp/go-metrics/compat` package has been introduced. This package and sub-packages are API compatible with
+`armon/go-metrics`. Libraries should be updated to use this package for emitting metrics via the global handlers. Internally,
+the package will route metrics to either `armon/go-metrics` or `hashicorp/go-metrics`. This is achieved at a global level
+within an application via the use of Go build tags.
+
+**Build Tags**
+* `armonmetrics` - Using this tag will cause metrics to be routed to `armon/go-metrics`
+* `hashicorpmetrics` - Using this tag will cause all metrics to be routed to `hashicorp/go-metrics`
+
+If no build tag is specified, the default behavior is to use `armon/go-metrics`. The overall migration path would be as follows:
+
+1. Upgrade libraries using `armon/go-metrics` to consume `hashicorp/go-metrics/compat` instead.
+2. Update library dependencies of applications that use `armon/go-metrics`.
+ * This doesn't need to be one big atomic update but can be slower due to the default behavior remaining unaltered.
+ * At this point all metrics will still be emitted to `armon/go-metrics`
+3. Update the application to use `hashicorp/go-metrics`
+ * Replace all application imports of `github.com/armon/go-metrics` with `github.com/hashicorp/go-metrics`
+ * Libraries are unaltered at this stage.
+ * Instrument your build system to build with the `hashicorpmetrics` tag.
+
+Your migration is effectively finished and your application is now exclusively using `hashicorp/go-metrics`. A future release of the library
+will change the default behavior to use `hashicorp/go-metrics` instead of `armon/go-metrics`. At that point in time, any application that
+needs more time before performing the migration must instrument their build system to include the `armonmetrics` tag. A subsequent release
+after that will eventually remove the compatibility layer all together. The rough timeline for this will be mid-2025 for changing the default
+behavior and then the end of 2025 for removal of the compatibility layer.
+
+
+Examples
+--------
+
+Here is an example of using the package:
+
+```go
+func SlowMethod() {
+ // Profiling the runtime of a method
+ defer metrics.MeasureSince([]string{"SlowMethod"}, time.Now())
+}
+
+// Configure a statsite sink as the global metrics sink
+sink, _ := metrics.NewStatsiteSink("statsite:8125")
+metrics.NewGlobal(metrics.DefaultConfig("service-name"), sink)
+
+// Emit a Key/Value pair
+metrics.EmitKey([]string{"questions", "meaning of life"}, 42)
+```
+
+Here is an example of setting up a signal handler:
+
+```go
+// Setup the inmem sink and signal handler
+inm := metrics.NewInmemSink(10*time.Second, time.Minute)
+sig := metrics.DefaultInmemSignal(inm)
+metrics.NewGlobal(metrics.DefaultConfig("service-name"), inm)
+
+// Run some code
+inm.SetGauge([]string{"foo"}, 42)
+inm.EmitKey([]string{"bar"}, 30)
+
+inm.IncrCounter([]string{"baz"}, 42)
+inm.IncrCounter([]string{"baz"}, 1)
+inm.IncrCounter([]string{"baz"}, 80)
+
+inm.AddSample([]string{"method", "wow"}, 42)
+inm.AddSample([]string{"method", "wow"}, 100)
+inm.AddSample([]string{"method", "wow"}, 22)
+
+....
+```
+
+When a signal comes in, output like the following will be dumped to stderr:
+
+ [2014-01-28 14:57:33.04 -0800 PST][G] 'foo': 42.000
+ [2014-01-28 14:57:33.04 -0800 PST][P] 'bar': 30.000
+ [2014-01-28 14:57:33.04 -0800 PST][C] 'baz': Count: 3 Min: 1.000 Mean: 41.000 Max: 80.000 Stddev: 39.509
+ [2014-01-28 14:57:33.04 -0800 PST][S] 'method.wow': Count: 3 Min: 22.000 Mean: 54.667 Max: 100.000 Stddev: 40.513
diff --git a/vendor/github.com/hashicorp/go-metrics/compat/armon.go b/vendor/github.com/hashicorp/go-metrics/compat/armon.go
new file mode 100644
index 00000000000..f59d96ced5c
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/compat/armon.go
@@ -0,0 +1,129 @@
+//go:build armonmetrics || ignore || !hashicorpmetrics
+// +build armonmetrics ignore !hashicorpmetrics
+
+package metrics
+
+import (
+ "io"
+ "net/url"
+ "syscall"
+ "time"
+
+ "github.com/armon/go-metrics"
+)
+
+const (
+ // DefaultSignal is used with DefaultInmemSignal
+ DefaultSignal = metrics.DefaultSignal
+)
+
+func AddSample(key []string, val float32) {
+ metrics.AddSample(key, val)
+}
+func AddSampleWithLabels(key []string, val float32, labels []Label) {
+ metrics.AddSampleWithLabels(key, val, labels)
+}
+func EmitKey(key []string, val float32) {
+ metrics.EmitKey(key, val)
+}
+func IncrCounter(key []string, val float32) {
+ metrics.IncrCounter(key, val)
+}
+func IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ metrics.IncrCounterWithLabels(key, val, labels)
+}
+func MeasureSince(key []string, start time.Time) {
+ metrics.MeasureSince(key, start)
+}
+func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
+ metrics.MeasureSinceWithLabels(key, start, labels)
+}
+func SetGauge(key []string, val float32) {
+ metrics.SetGauge(key, val)
+}
+func SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ metrics.SetGaugeWithLabels(key, val, labels)
+}
+func Shutdown() {
+ metrics.Shutdown()
+}
+func UpdateFilter(allow, block []string) {
+ metrics.UpdateFilter(allow, block)
+}
+func UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
+ metrics.UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels)
+}
+
+type AggregateSample = metrics.AggregateSample
+type BlackholeSink = metrics.BlackholeSink
+type Config = metrics.Config
+type Encoder = metrics.Encoder
+type FanoutSink = metrics.FanoutSink
+type GaugeValue = metrics.GaugeValue
+type InmemSignal = metrics.InmemSignal
+type InmemSink = metrics.InmemSink
+type IntervalMetrics = metrics.IntervalMetrics
+type Label = metrics.Label
+type MetricSink = metrics.MetricSink
+type Metrics = metrics.Metrics
+type MetricsSummary = metrics.MetricsSummary
+type PointValue = metrics.PointValue
+type SampledValue = metrics.SampledValue
+type ShutdownSink = metrics.ShutdownSink
+type StatsdSink = metrics.StatsdSink
+type StatsiteSink = metrics.StatsiteSink
+
+func DefaultConfig(serviceName string) *Config {
+ return metrics.DefaultConfig(serviceName)
+}
+
+func DefaultInmemSignal(inmem *InmemSink) *InmemSignal {
+ return metrics.DefaultInmemSignal(inmem)
+}
+func NewInmemSignal(inmem *InmemSink, sig syscall.Signal, w io.Writer) *InmemSignal {
+ return metrics.NewInmemSignal(inmem, sig, w)
+}
+
+func NewInmemSink(interval, retain time.Duration) *InmemSink {
+ return metrics.NewInmemSink(interval, retain)
+}
+
+func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
+ return metrics.NewIntervalMetrics(intv)
+}
+
+func NewInmemSinkFromURL(u *url.URL) (MetricSink, error) {
+ return metrics.NewInmemSinkFromURL(u)
+}
+
+func NewMetricSinkFromURL(urlStr string) (MetricSink, error) {
+ return metrics.NewMetricSinkFromURL(urlStr)
+}
+
+func NewStatsdSinkFromURL(u *url.URL) (MetricSink, error) {
+ return metrics.NewStatsdSinkFromURL(u)
+}
+
+func NewStatsiteSinkFromURL(u *url.URL) (MetricSink, error) {
+ return metrics.NewStatsiteSinkFromURL(u)
+}
+
+func Default() *Metrics {
+ return metrics.Default()
+}
+
+func New(conf *Config, sink MetricSink) (*Metrics, error) {
+ return metrics.New(conf, sink)
+}
+
+func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
+ return metrics.NewGlobal(conf, sink)
+}
+
+func NewStatsdSink(addr string) (*StatsdSink, error) {
+ return metrics.NewStatsdSink(addr)
+}
+
+func NewStatsiteSink(addr string) (*StatsiteSink, error) {
+ return metrics.NewStatsiteSink(addr)
+}
diff --git a/vendor/github.com/hashicorp/go-metrics/compat/hashicorp.go b/vendor/github.com/hashicorp/go-metrics/compat/hashicorp.go
new file mode 100644
index 00000000000..144578f9005
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/compat/hashicorp.go
@@ -0,0 +1,129 @@
+//go:build hashicorpmetrics
+// +build hashicorpmetrics
+
+package metrics
+
+import (
+ "io"
+ "net/url"
+ "syscall"
+ "time"
+
+ "github.com/hashicorp/go-metrics"
+)
+
+const (
+ // DefaultSignal is used with DefaultInmemSignal
+ DefaultSignal = metrics.DefaultSignal
+)
+
+func AddSample(key []string, val float32) {
+ metrics.AddSample(key, val)
+}
+func AddSampleWithLabels(key []string, val float32, labels []Label) {
+ metrics.AddSampleWithLabels(key, val, labels)
+}
+func EmitKey(key []string, val float32) {
+ metrics.EmitKey(key, val)
+}
+func IncrCounter(key []string, val float32) {
+ metrics.IncrCounter(key, val)
+}
+func IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ metrics.IncrCounterWithLabels(key, val, labels)
+}
+func MeasureSince(key []string, start time.Time) {
+ metrics.MeasureSince(key, start)
+}
+func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
+ metrics.MeasureSinceWithLabels(key, start, labels)
+}
+func SetGauge(key []string, val float32) {
+ metrics.SetGauge(key, val)
+}
+func SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ metrics.SetGaugeWithLabels(key, val, labels)
+}
+func Shutdown() {
+ metrics.Shutdown()
+}
+func UpdateFilter(allow, block []string) {
+ metrics.UpdateFilter(allow, block)
+}
+func UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
+ metrics.UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels)
+}
+
+type AggregateSample = metrics.AggregateSample
+type BlackholeSink = metrics.BlackholeSink
+type Config = metrics.Config
+type Encoder = metrics.Encoder
+type FanoutSink = metrics.FanoutSink
+type GaugeValue = metrics.GaugeValue
+type InmemSignal = metrics.InmemSignal
+type InmemSink = metrics.InmemSink
+type IntervalMetrics = metrics.IntervalMetrics
+type Label = metrics.Label
+type MetricSink = metrics.MetricSink
+type Metrics = metrics.Metrics
+type MetricsSummary = metrics.MetricsSummary
+type PointValue = metrics.PointValue
+type SampledValue = metrics.SampledValue
+type ShutdownSink = metrics.ShutdownSink
+type StatsdSink = metrics.StatsdSink
+type StatsiteSink = metrics.StatsiteSink
+
+func DefaultConfig(serviceName string) *Config {
+ return metrics.DefaultConfig(serviceName)
+}
+
+func DefaultInmemSignal(inmem *InmemSink) *InmemSignal {
+ return metrics.DefaultInmemSignal(inmem)
+}
+func NewInmemSignal(inmem *InmemSink, sig syscall.Signal, w io.Writer) *InmemSignal {
+ return metrics.NewInmemSignal(inmem, sig, w)
+}
+
+func NewInmemSink(interval, retain time.Duration) *InmemSink {
+ return metrics.NewInmemSink(interval, retain)
+}
+
+func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
+ return metrics.NewIntervalMetrics(intv)
+}
+
+func NewInmemSinkFromURL(u *url.URL) (MetricSink, error) {
+ return metrics.NewInmemSinkFromURL(u)
+}
+
+func NewMetricSinkFromURL(urlStr string) (MetricSink, error) {
+ return metrics.NewMetricSinkFromURL(urlStr)
+}
+
+func NewStatsdSinkFromURL(u *url.URL) (MetricSink, error) {
+ return metrics.NewStatsdSinkFromURL(u)
+}
+
+func NewStatsiteSinkFromURL(u *url.URL) (MetricSink, error) {
+ return metrics.NewStatsiteSinkFromURL(u)
+}
+
+func Default() *Metrics {
+ return metrics.Default()
+}
+
+func New(conf *Config, sink MetricSink) (*Metrics, error) {
+ return metrics.New(conf, sink)
+}
+
+func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
+ return metrics.NewGlobal(conf, sink)
+}
+
+func NewStatsdSink(addr string) (*StatsdSink, error) {
+ return metrics.NewStatsdSink(addr)
+}
+
+func NewStatsiteSink(addr string) (*StatsiteSink, error) {
+ return metrics.NewStatsiteSink(addr)
+}
diff --git a/vendor/github.com/hashicorp/go-metrics/const_js.go b/vendor/github.com/hashicorp/go-metrics/const_js.go
new file mode 100644
index 00000000000..3fa3f7258c4
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/const_js.go
@@ -0,0 +1,9 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MIT
+
+package metrics
+
+const (
+ // DefaultSignal is used with DefaultInmemSignal
+ DefaultSignal = 0x1e
+)
diff --git a/vendor/github.com/hashicorp/go-metrics/const_unix.go b/vendor/github.com/hashicorp/go-metrics/const_unix.go
new file mode 100644
index 00000000000..6df46d2e2b7
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/const_unix.go
@@ -0,0 +1,16 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MIT
+
+//go:build !windows && !js
+// +build !windows,!js
+
+package metrics
+
+import (
+ "syscall"
+)
+
+const (
+ // DefaultSignal is used with DefaultInmemSignal
+ DefaultSignal = syscall.SIGUSR1
+)
diff --git a/vendor/github.com/hashicorp/go-metrics/const_windows.go b/vendor/github.com/hashicorp/go-metrics/const_windows.go
new file mode 100644
index 00000000000..11cb785fef5
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/const_windows.go
@@ -0,0 +1,16 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MIT
+
+// +build windows
+
+package metrics
+
+import (
+ "syscall"
+)
+
+const (
+ // DefaultSignal is used with DefaultInmemSignal
+ // Windows has no SIGUSR1, use SIGBREAK
+ DefaultSignal = syscall.Signal(21)
+)
diff --git a/vendor/github.com/hashicorp/go-metrics/inmem.go b/vendor/github.com/hashicorp/go-metrics/inmem.go
new file mode 100644
index 00000000000..721a8b9e522
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/inmem.go
@@ -0,0 +1,363 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MIT
+
+package metrics
+
+import (
+ "bytes"
+ "fmt"
+ "math"
+ "net/url"
+ "strings"
+ "sync"
+ "time"
+)
+
+var spaceReplacer = strings.NewReplacer(" ", "_")
+
+// InmemSink provides a MetricSink that does in-memory aggregation
+// without sending metrics over a network. It can be embedded within
+// an application to provide profiling information.
+type InmemSink struct {
+ // How long is each aggregation interval
+ interval time.Duration
+
+ // Retain controls how many metrics interval we keep
+ retain time.Duration
+
+ // maxIntervals is the maximum length of intervals.
+ // It is retain / interval.
+ maxIntervals int
+
+ // intervals is a slice of the retained intervals
+ intervals []*IntervalMetrics
+ intervalLock sync.RWMutex
+
+ rateDenom float64
+}
+
+// IntervalMetrics stores the aggregated metrics
+// for a specific interval
+type IntervalMetrics struct {
+ sync.RWMutex
+
+ // The start time of the interval
+ Interval time.Time
+
+ // Gauges maps the key to the last set value
+ Gauges map[string]GaugeValue
+
+ // PrecisionGauges maps the key to the last set value
+ PrecisionGauges map[string]PrecisionGaugeValue
+
+ // Points maps the string to the list of emitted values
+ // from EmitKey
+ Points map[string][]float32
+
+ // Counters maps the string key to a sum of the counter
+ // values
+ Counters map[string]SampledValue
+
+ // Samples maps the key to an AggregateSample,
+ // which has the rolled up view of a sample
+ Samples map[string]SampledValue
+
+ // done is closed when this interval has ended, and a new IntervalMetrics
+ // has been created to receive any future metrics.
+ done chan struct{}
+}
+
+// NewIntervalMetrics creates a new IntervalMetrics for a given interval
+func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
+ return &IntervalMetrics{
+ Interval: intv,
+ Gauges: make(map[string]GaugeValue),
+ PrecisionGauges: make(map[string]PrecisionGaugeValue),
+ Points: make(map[string][]float32),
+ Counters: make(map[string]SampledValue),
+ Samples: make(map[string]SampledValue),
+ done: make(chan struct{}),
+ }
+}
+
+// AggregateSample is used to hold aggregate metrics
+// about a sample
+type AggregateSample struct {
+ Count int // The count of emitted pairs
+ Rate float64 // The values rate per time unit (usually 1 second)
+ Sum float64 // The sum of values
+ SumSq float64 `json:"-"` // The sum of squared values
+ Min float64 // Minimum value
+ Max float64 // Maximum value
+ LastUpdated time.Time `json:"-"` // When value was last updated
+}
+
+// Computes a Stddev of the values
+func (a *AggregateSample) Stddev() float64 {
+ num := (float64(a.Count) * a.SumSq) - math.Pow(a.Sum, 2)
+ div := float64(a.Count * (a.Count - 1))
+ if div == 0 {
+ return 0
+ }
+ return math.Sqrt(num / div)
+}
+
+// Computes a mean of the values
+func (a *AggregateSample) Mean() float64 {
+ if a.Count == 0 {
+ return 0
+ }
+ return a.Sum / float64(a.Count)
+}
+
+// Ingest is used to update a sample
+func (a *AggregateSample) Ingest(v float64, rateDenom float64) {
+ a.Count++
+ a.Sum += v
+ a.SumSq += (v * v)
+ if v < a.Min || a.Count == 1 {
+ a.Min = v
+ }
+ if v > a.Max || a.Count == 1 {
+ a.Max = v
+ }
+ a.Rate = float64(a.Sum) / rateDenom
+ a.LastUpdated = time.Now()
+}
+
+func (a *AggregateSample) String() string {
+ if a.Count == 0 {
+ return "Count: 0"
+ } else if a.Stddev() == 0 {
+ return fmt.Sprintf("Count: %d Sum: %0.3f LastUpdated: %s", a.Count, a.Sum, a.LastUpdated)
+ } else {
+ return fmt.Sprintf("Count: %d Min: %0.3f Mean: %0.3f Max: %0.3f Stddev: %0.3f Sum: %0.3f LastUpdated: %s",
+ a.Count, a.Min, a.Mean(), a.Max, a.Stddev(), a.Sum, a.LastUpdated)
+ }
+}
+
+// NewInmemSinkFromURL creates an InmemSink from a URL. It is used
+// (and tested) from NewMetricSinkFromURL.
+func NewInmemSinkFromURL(u *url.URL) (MetricSink, error) {
+ params := u.Query()
+
+ interval, err := time.ParseDuration(params.Get("interval"))
+ if err != nil {
+ return nil, fmt.Errorf("Bad 'interval' param: %s", err)
+ }
+
+ retain, err := time.ParseDuration(params.Get("retain"))
+ if err != nil {
+ return nil, fmt.Errorf("Bad 'retain' param: %s", err)
+ }
+
+ return NewInmemSink(interval, retain), nil
+}
+
+// NewInmemSink is used to construct a new in-memory sink.
+// Uses an aggregation interval and maximum retention period.
+func NewInmemSink(interval, retain time.Duration) *InmemSink {
+ rateTimeUnit := time.Second
+ i := &InmemSink{
+ interval: interval,
+ retain: retain,
+ maxIntervals: int(retain / interval),
+ rateDenom: float64(interval.Nanoseconds()) / float64(rateTimeUnit.Nanoseconds()),
+ }
+ i.intervals = make([]*IntervalMetrics, 0, i.maxIntervals)
+ return i
+}
+
+func (i *InmemSink) SetGauge(key []string, val float32) {
+ i.SetGaugeWithLabels(key, val, nil)
+}
+
+func (i *InmemSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ k, name := i.flattenKeyLabels(key, labels)
+ intv := i.getInterval()
+
+ intv.Lock()
+ defer intv.Unlock()
+ intv.Gauges[k] = GaugeValue{Name: name, Value: val, Labels: labels}
+}
+
+func (i *InmemSink) SetPrecisionGauge(key []string, val float64) {
+ i.SetPrecisionGaugeWithLabels(key, val, nil)
+}
+
+func (i *InmemSink) SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label) {
+ k, name := i.flattenKeyLabels(key, labels)
+ intv := i.getInterval()
+
+ intv.Lock()
+ defer intv.Unlock()
+ intv.PrecisionGauges[k] = PrecisionGaugeValue{Name: name, Value: val, Labels: labels}
+}
+
+func (i *InmemSink) EmitKey(key []string, val float32) {
+ k := i.flattenKey(key)
+ intv := i.getInterval()
+
+ intv.Lock()
+ defer intv.Unlock()
+ vals := intv.Points[k]
+ intv.Points[k] = append(vals, val)
+}
+
+func (i *InmemSink) IncrCounter(key []string, val float32) {
+ i.IncrCounterWithLabels(key, val, nil)
+}
+
+func (i *InmemSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ k, name := i.flattenKeyLabels(key, labels)
+ intv := i.getInterval()
+
+ intv.Lock()
+ defer intv.Unlock()
+
+ agg, ok := intv.Counters[k]
+ if !ok {
+ agg = SampledValue{
+ Name: name,
+ AggregateSample: &AggregateSample{},
+ Labels: labels,
+ }
+ intv.Counters[k] = agg
+ }
+ agg.Ingest(float64(val), i.rateDenom)
+}
+
+func (i *InmemSink) AddSample(key []string, val float32) {
+ i.AddSampleWithLabels(key, val, nil)
+}
+
+func (i *InmemSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
+ k, name := i.flattenKeyLabels(key, labels)
+ intv := i.getInterval()
+
+ intv.Lock()
+ defer intv.Unlock()
+
+ agg, ok := intv.Samples[k]
+ if !ok {
+ agg = SampledValue{
+ Name: name,
+ AggregateSample: &AggregateSample{},
+ Labels: labels,
+ }
+ intv.Samples[k] = agg
+ }
+ agg.Ingest(float64(val), i.rateDenom)
+}
+
+// Data is used to retrieve all the aggregated metrics
+// Intervals may be in use, and a read lock should be acquired
+func (i *InmemSink) Data() []*IntervalMetrics {
+ // Get the current interval, forces creation
+ i.getInterval()
+
+ i.intervalLock.RLock()
+ defer i.intervalLock.RUnlock()
+
+ n := len(i.intervals)
+ intervals := make([]*IntervalMetrics, n)
+
+ copy(intervals[:n-1], i.intervals[:n-1])
+ current := i.intervals[n-1]
+
+ // make its own copy for current interval
+ intervals[n-1] = &IntervalMetrics{}
+ copyCurrent := intervals[n-1]
+ current.RLock()
+ *copyCurrent = *current
+ // RWMutex is not safe to copy, so create a new instance on the copy
+ copyCurrent.RWMutex = sync.RWMutex{}
+
+ copyCurrent.Gauges = make(map[string]GaugeValue, len(current.Gauges))
+ for k, v := range current.Gauges {
+ copyCurrent.Gauges[k] = v
+ }
+ copyCurrent.PrecisionGauges = make(map[string]PrecisionGaugeValue, len(current.PrecisionGauges))
+ for k, v := range current.PrecisionGauges {
+ copyCurrent.PrecisionGauges[k] = v
+ }
+ // saved values will be not change, just copy its link
+ copyCurrent.Points = make(map[string][]float32, len(current.Points))
+ for k, v := range current.Points {
+ copyCurrent.Points[k] = v
+ }
+ copyCurrent.Counters = make(map[string]SampledValue, len(current.Counters))
+ for k, v := range current.Counters {
+ copyCurrent.Counters[k] = v.deepCopy()
+ }
+ copyCurrent.Samples = make(map[string]SampledValue, len(current.Samples))
+ for k, v := range current.Samples {
+ copyCurrent.Samples[k] = v.deepCopy()
+ }
+ current.RUnlock()
+
+ return intervals
+}
+
+// getInterval returns the current interval. A new interval is created if no
+// previous interval exists, or if the current time is beyond the window for the
+// current interval.
+func (i *InmemSink) getInterval() *IntervalMetrics {
+ intv := time.Now().Truncate(i.interval)
+
+ // Attempt to return the existing interval first, because it only requires
+ // a read lock.
+ i.intervalLock.RLock()
+ n := len(i.intervals)
+ if n > 0 && i.intervals[n-1].Interval == intv {
+ defer i.intervalLock.RUnlock()
+ return i.intervals[n-1]
+ }
+ i.intervalLock.RUnlock()
+
+ i.intervalLock.Lock()
+ defer i.intervalLock.Unlock()
+
+ // Re-check for an existing interval now that the lock is re-acquired.
+ n = len(i.intervals)
+ if n > 0 && i.intervals[n-1].Interval == intv {
+ return i.intervals[n-1]
+ }
+
+ current := NewIntervalMetrics(intv)
+ i.intervals = append(i.intervals, current)
+ if n > 0 {
+ close(i.intervals[n-1].done)
+ }
+
+ n++
+ // Prune old intervals if the count exceeds the max.
+ if n >= i.maxIntervals {
+ copy(i.intervals[0:], i.intervals[n-i.maxIntervals:])
+ i.intervals = i.intervals[:i.maxIntervals]
+ }
+ return current
+}
+
+// Flattens the key for formatting, removes spaces
+func (i *InmemSink) flattenKey(parts []string) string {
+ buf := &bytes.Buffer{}
+
+ joined := strings.Join(parts, ".")
+
+ spaceReplacer.WriteString(buf, joined)
+
+ return buf.String()
+}
+
+// Flattens the key for formatting along with its labels, removes spaces
+func (i *InmemSink) flattenKeyLabels(parts []string, labels []Label) (string, string) {
+ key := i.flattenKey(parts)
+ buf := bytes.NewBufferString(key)
+
+ for _, label := range labels {
+ spaceReplacer.WriteString(buf, fmt.Sprintf(";%s=%s", label.Name, label.Value))
+ }
+
+ return buf.String(), key
+}
diff --git a/vendor/github.com/hashicorp/go-metrics/inmem_endpoint.go b/vendor/github.com/hashicorp/go-metrics/inmem_endpoint.go
new file mode 100644
index 00000000000..2fc06389e91
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/inmem_endpoint.go
@@ -0,0 +1,190 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MIT
+
+package metrics
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "sort"
+ "time"
+)
+
+// MetricsSummary holds a roll-up of metrics info for a given interval
+type MetricsSummary struct {
+ Timestamp string
+ Gauges []GaugeValue
+ PrecisionGauges []PrecisionGaugeValue
+ Points []PointValue
+ Counters []SampledValue
+ Samples []SampledValue
+}
+
+type GaugeValue struct {
+ Name string
+ Hash string `json:"-"`
+ Value float32
+
+ Labels []Label `json:"-"`
+ DisplayLabels map[string]string `json:"Labels"`
+}
+
+type PrecisionGaugeValue struct {
+ Name string
+ Hash string `json:"-"`
+ Value float64
+
+ Labels []Label `json:"-"`
+ DisplayLabels map[string]string `json:"Labels"`
+}
+
+type PointValue struct {
+ Name string
+ Points []float32
+}
+
+type SampledValue struct {
+ Name string
+ Hash string `json:"-"`
+ *AggregateSample
+ Mean float64
+ Stddev float64
+
+ Labels []Label `json:"-"`
+ DisplayLabels map[string]string `json:"Labels"`
+}
+
+// deepCopy allocates a new instance of AggregateSample
+func (source *SampledValue) deepCopy() SampledValue {
+ dest := *source
+ if source.AggregateSample != nil {
+ dest.AggregateSample = &AggregateSample{}
+ *dest.AggregateSample = *source.AggregateSample
+ }
+ return dest
+}
+
+// DisplayMetrics returns a summary of the metrics from the most recent finished interval.
+func (i *InmemSink) DisplayMetrics(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
+ data := i.Data()
+
+ var interval *IntervalMetrics
+ n := len(data)
+ switch {
+ case n == 0:
+ return nil, fmt.Errorf("no metric intervals have been initialized yet")
+ case n == 1:
+ // Show the current interval if it's all we have
+ interval = data[0]
+ default:
+ // Show the most recent finished interval if we have one
+ interval = data[n-2]
+ }
+
+ return newMetricSummaryFromInterval(interval), nil
+}
+
+func newMetricSummaryFromInterval(interval *IntervalMetrics) MetricsSummary {
+ interval.RLock()
+ defer interval.RUnlock()
+
+ summary := MetricsSummary{
+ Timestamp: interval.Interval.Round(time.Second).UTC().String(),
+ Gauges: make([]GaugeValue, 0, len(interval.Gauges)),
+ PrecisionGauges: make([]PrecisionGaugeValue, 0, len(interval.PrecisionGauges)),
+ Points: make([]PointValue, 0, len(interval.Points)),
+ }
+
+ // Format and sort the output of each metric type, so it gets displayed in a
+ // deterministic order.
+ for name, points := range interval.Points {
+ summary.Points = append(summary.Points, PointValue{name, points})
+ }
+ sort.Slice(summary.Points, func(i, j int) bool {
+ return summary.Points[i].Name < summary.Points[j].Name
+ })
+
+ for hash, value := range interval.Gauges {
+ value.Hash = hash
+ value.DisplayLabels = make(map[string]string)
+ for _, label := range value.Labels {
+ value.DisplayLabels[label.Name] = label.Value
+ }
+ value.Labels = nil
+
+ summary.Gauges = append(summary.Gauges, value)
+ }
+ sort.Slice(summary.Gauges, func(i, j int) bool {
+ return summary.Gauges[i].Hash < summary.Gauges[j].Hash
+ })
+
+ for hash, value := range interval.PrecisionGauges {
+ value.Hash = hash
+ value.DisplayLabels = make(map[string]string)
+ for _, label := range value.Labels {
+ value.DisplayLabels[label.Name] = label.Value
+ }
+ value.Labels = nil
+
+ summary.PrecisionGauges = append(summary.PrecisionGauges, value)
+ }
+ sort.Slice(summary.PrecisionGauges, func(i, j int) bool {
+ return summary.PrecisionGauges[i].Hash < summary.PrecisionGauges[j].Hash
+ })
+
+ summary.Counters = formatSamples(interval.Counters)
+ summary.Samples = formatSamples(interval.Samples)
+
+ return summary
+}
+
+func formatSamples(source map[string]SampledValue) []SampledValue {
+ output := make([]SampledValue, 0, len(source))
+ for hash, sample := range source {
+ displayLabels := make(map[string]string)
+ for _, label := range sample.Labels {
+ displayLabels[label.Name] = label.Value
+ }
+
+ output = append(output, SampledValue{
+ Name: sample.Name,
+ Hash: hash,
+ AggregateSample: sample.AggregateSample,
+ Mean: sample.AggregateSample.Mean(),
+ Stddev: sample.AggregateSample.Stddev(),
+ DisplayLabels: displayLabels,
+ })
+ }
+ sort.Slice(output, func(i, j int) bool {
+ return output[i].Hash < output[j].Hash
+ })
+
+ return output
+}
+
+type Encoder interface {
+ Encode(interface{}) error
+}
+
+// Stream writes metrics using encoder.Encode each time an interval ends. Runs
+// until the request context is cancelled, or the encoder returns an error.
+// The caller is responsible for logging any errors from encoder.
+func (i *InmemSink) Stream(ctx context.Context, encoder Encoder) {
+ interval := i.getInterval()
+
+ for {
+ select {
+ case <-interval.done:
+ summary := newMetricSummaryFromInterval(interval)
+ if err := encoder.Encode(summary); err != nil {
+ return
+ }
+
+ // update interval to the next one
+ interval = i.getInterval()
+ case <-ctx.Done():
+ return
+ }
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-metrics/inmem_signal.go b/vendor/github.com/hashicorp/go-metrics/inmem_signal.go
new file mode 100644
index 00000000000..2711c2586a8
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/inmem_signal.go
@@ -0,0 +1,124 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MIT
+
+package metrics
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "os/signal"
+ "strings"
+ "sync"
+ "syscall"
+)
+
+// InmemSignal is used to listen for a given signal, and when received,
+// to dump the current metrics from the InmemSink to an io.Writer
+type InmemSignal struct {
+ signal syscall.Signal
+ inm *InmemSink
+ w io.Writer
+ sigCh chan os.Signal
+
+ stop bool
+ stopCh chan struct{}
+ stopLock sync.Mutex
+}
+
+// NewInmemSignal creates a new InmemSignal which listens for a given signal,
+// and dumps the current metrics out to a writer
+func NewInmemSignal(inmem *InmemSink, sig syscall.Signal, w io.Writer) *InmemSignal {
+ i := &InmemSignal{
+ signal: sig,
+ inm: inmem,
+ w: w,
+ sigCh: make(chan os.Signal, 1),
+ stopCh: make(chan struct{}),
+ }
+ signal.Notify(i.sigCh, sig)
+ go i.run()
+ return i
+}
+
+// DefaultInmemSignal returns a new InmemSignal that responds to SIGUSR1
+// and writes output to stderr. Windows uses SIGBREAK
+func DefaultInmemSignal(inmem *InmemSink) *InmemSignal {
+ return NewInmemSignal(inmem, DefaultSignal, os.Stderr)
+}
+
+// Stop is used to stop the InmemSignal from listening
+func (i *InmemSignal) Stop() {
+ i.stopLock.Lock()
+ defer i.stopLock.Unlock()
+
+ if i.stop {
+ return
+ }
+ i.stop = true
+ close(i.stopCh)
+ signal.Stop(i.sigCh)
+}
+
+// run is a long running routine that handles signals
+func (i *InmemSignal) run() {
+ for {
+ select {
+ case <-i.sigCh:
+ i.dumpStats()
+ case <-i.stopCh:
+ return
+ }
+ }
+}
+
+// dumpStats is used to dump the data to output writer
+func (i *InmemSignal) dumpStats() {
+ buf := bytes.NewBuffer(nil)
+
+ data := i.inm.Data()
+ // Skip the last period which is still being aggregated
+ for j := 0; j < len(data)-1; j++ {
+ intv := data[j]
+ intv.RLock()
+ for _, val := range intv.Gauges {
+ name := i.flattenLabels(val.Name, val.Labels)
+ fmt.Fprintf(buf, "[%v][G] '%s': %0.3f\n", intv.Interval, name, val.Value)
+ }
+ for _, val := range intv.PrecisionGauges {
+ name := i.flattenLabels(val.Name, val.Labels)
+ fmt.Fprintf(buf, "[%v][G] '%s': %0.3f\n", intv.Interval, name, val.Value)
+ }
+ for name, vals := range intv.Points {
+ for _, val := range vals {
+ fmt.Fprintf(buf, "[%v][P] '%s': %0.3f\n", intv.Interval, name, val)
+ }
+ }
+ for _, agg := range intv.Counters {
+ name := i.flattenLabels(agg.Name, agg.Labels)
+ fmt.Fprintf(buf, "[%v][C] '%s': %s\n", intv.Interval, name, agg.AggregateSample)
+ }
+ for _, agg := range intv.Samples {
+ name := i.flattenLabels(agg.Name, agg.Labels)
+ fmt.Fprintf(buf, "[%v][S] '%s': %s\n", intv.Interval, name, agg.AggregateSample)
+ }
+ intv.RUnlock()
+ }
+
+ // Write out the bytes
+ i.w.Write(buf.Bytes())
+}
+
+// Flattens the key for formatting along with its labels, removes spaces
+func (i *InmemSignal) flattenLabels(name string, labels []Label) string {
+ buf := bytes.NewBufferString(name)
+ replacer := strings.NewReplacer(" ", "_", ":", "_")
+
+ for _, label := range labels {
+ replacer.WriteString(buf, ".")
+ replacer.WriteString(buf, label.Value)
+ }
+
+ return buf.String()
+}
diff --git a/vendor/github.com/hashicorp/go-metrics/metrics.go b/vendor/github.com/hashicorp/go-metrics/metrics.go
new file mode 100644
index 00000000000..34478865b3d
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/metrics.go
@@ -0,0 +1,336 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MIT
+
+package metrics
+
+import (
+ "runtime"
+ "strings"
+ "time"
+
+ iradix "github.com/hashicorp/go-immutable-radix"
+)
+
+type Label struct {
+ Name string
+ Value string
+}
+
+func (m *Metrics) SetGauge(key []string, val float32) {
+ m.SetGaugeWithLabels(key, val, nil)
+}
+
+func (m *Metrics) SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ if m.HostName != "" {
+ if m.EnableHostnameLabel {
+ labels = append(labels, Label{"host", m.HostName})
+ } else if m.EnableHostname {
+ key = insert(0, m.HostName, key)
+ }
+ }
+ if m.EnableTypePrefix {
+ key = insert(0, "gauge", key)
+ }
+ if m.ServiceName != "" {
+ if m.EnableServiceLabel {
+ labels = append(labels, Label{"service", m.ServiceName})
+ } else {
+ key = insert(0, m.ServiceName, key)
+ }
+ }
+ allowed, labelsFiltered := m.allowMetric(key, labels)
+ if !allowed {
+ return
+ }
+ m.sink.SetGaugeWithLabels(key, val, labelsFiltered)
+}
+
+func (m *Metrics) SetPrecisionGauge(key []string, val float64) {
+ m.SetPrecisionGaugeWithLabels(key, val, nil)
+}
+
+func (m *Metrics) SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label) {
+ if m.HostName != "" {
+ if m.EnableHostnameLabel {
+ labels = append(labels, Label{"host", m.HostName})
+ } else if m.EnableHostname {
+ key = insert(0, m.HostName, key)
+ }
+ }
+ if m.EnableTypePrefix {
+ key = insert(0, "gauge", key)
+ }
+ if m.ServiceName != "" {
+ if m.EnableServiceLabel {
+ labels = append(labels, Label{"service", m.ServiceName})
+ } else {
+ key = insert(0, m.ServiceName, key)
+ }
+ }
+ allowed, labelsFiltered := m.allowMetric(key, labels)
+ if !allowed {
+ return
+ }
+ sink, ok := m.sink.(PrecisionGaugeMetricSink)
+ if !ok {
+ // Sink does not implement PrecisionGaugeMetricSink.
+ } else {
+ sink.SetPrecisionGaugeWithLabels(key, val, labelsFiltered)
+ }
+}
+
+func (m *Metrics) EmitKey(key []string, val float32) {
+ if m.EnableTypePrefix {
+ key = insert(0, "kv", key)
+ }
+ if m.ServiceName != "" {
+ key = insert(0, m.ServiceName, key)
+ }
+ allowed, _ := m.allowMetric(key, nil)
+ if !allowed {
+ return
+ }
+ m.sink.EmitKey(key, val)
+}
+
+func (m *Metrics) IncrCounter(key []string, val float32) {
+ m.IncrCounterWithLabels(key, val, nil)
+}
+
+func (m *Metrics) IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ if m.HostName != "" && m.EnableHostnameLabel {
+ labels = append(labels, Label{"host", m.HostName})
+ }
+ if m.EnableTypePrefix {
+ key = insert(0, "counter", key)
+ }
+ if m.ServiceName != "" {
+ if m.EnableServiceLabel {
+ labels = append(labels, Label{"service", m.ServiceName})
+ } else {
+ key = insert(0, m.ServiceName, key)
+ }
+ }
+ allowed, labelsFiltered := m.allowMetric(key, labels)
+ if !allowed {
+ return
+ }
+ m.sink.IncrCounterWithLabels(key, val, labelsFiltered)
+}
+
+func (m *Metrics) AddSample(key []string, val float32) {
+ m.AddSampleWithLabels(key, val, nil)
+}
+
+func (m *Metrics) AddSampleWithLabels(key []string, val float32, labels []Label) {
+ if m.HostName != "" && m.EnableHostnameLabel {
+ labels = append(labels, Label{"host", m.HostName})
+ }
+ if m.EnableTypePrefix {
+ key = insert(0, "sample", key)
+ }
+ if m.ServiceName != "" {
+ if m.EnableServiceLabel {
+ labels = append(labels, Label{"service", m.ServiceName})
+ } else {
+ key = insert(0, m.ServiceName, key)
+ }
+ }
+ allowed, labelsFiltered := m.allowMetric(key, labels)
+ if !allowed {
+ return
+ }
+ m.sink.AddSampleWithLabels(key, val, labelsFiltered)
+}
+
+func (m *Metrics) MeasureSince(key []string, start time.Time) {
+ m.MeasureSinceWithLabels(key, start, nil)
+}
+
+func (m *Metrics) MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
+ if m.HostName != "" && m.EnableHostnameLabel {
+ labels = append(labels, Label{"host", m.HostName})
+ }
+ if m.EnableTypePrefix {
+ key = insert(0, "timer", key)
+ }
+ if m.ServiceName != "" {
+ if m.EnableServiceLabel {
+ labels = append(labels, Label{"service", m.ServiceName})
+ } else {
+ key = insert(0, m.ServiceName, key)
+ }
+ }
+ allowed, labelsFiltered := m.allowMetric(key, labels)
+ if !allowed {
+ return
+ }
+ now := time.Now()
+ elapsed := now.Sub(start)
+ msec := float32(elapsed.Nanoseconds()) / float32(m.TimerGranularity)
+ m.sink.AddSampleWithLabels(key, msec, labelsFiltered)
+}
+
+// UpdateFilter overwrites the existing filter with the given rules.
+func (m *Metrics) UpdateFilter(allow, block []string) {
+ m.UpdateFilterAndLabels(allow, block, m.AllowedLabels, m.BlockedLabels)
+}
+
+// UpdateFilterAndLabels overwrites the existing filter with the given rules.
+func (m *Metrics) UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
+ m.filterLock.Lock()
+ defer m.filterLock.Unlock()
+
+ m.AllowedPrefixes = allow
+ m.BlockedPrefixes = block
+
+ if allowedLabels == nil {
+ // Having a white list means we take only elements from it
+ m.allowedLabels = nil
+ } else {
+ m.allowedLabels = make(map[string]bool)
+ for _, v := range allowedLabels {
+ m.allowedLabels[v] = true
+ }
+ }
+ m.blockedLabels = make(map[string]bool)
+ for _, v := range blockedLabels {
+ m.blockedLabels[v] = true
+ }
+ m.AllowedLabels = allowedLabels
+ m.BlockedLabels = blockedLabels
+
+ m.filter = iradix.New()
+ for _, prefix := range m.AllowedPrefixes {
+ m.filter, _, _ = m.filter.Insert([]byte(prefix), true)
+ }
+ for _, prefix := range m.BlockedPrefixes {
+ m.filter, _, _ = m.filter.Insert([]byte(prefix), false)
+ }
+}
+
+func (m *Metrics) Shutdown() {
+ if ss, ok := m.sink.(ShutdownSink); ok {
+ ss.Shutdown()
+ }
+}
+
+// labelIsAllowed return true if a should be included in metric
+// the caller should lock m.filterLock while calling this method
+func (m *Metrics) labelIsAllowed(label *Label) bool {
+ labelName := (*label).Name
+ if m.blockedLabels != nil {
+ _, ok := m.blockedLabels[labelName]
+ if ok {
+ // If present, let's remove this label
+ return false
+ }
+ }
+ if m.allowedLabels != nil {
+ _, ok := m.allowedLabels[labelName]
+ return ok
+ }
+ // Allow by default
+ return true
+}
+
+// filterLabels return only allowed labels
+// the caller should lock m.filterLock while calling this method
+func (m *Metrics) filterLabels(labels []Label) []Label {
+ if labels == nil {
+ return nil
+ }
+ toReturn := []Label{}
+ for _, label := range labels {
+ if m.labelIsAllowed(&label) {
+ toReturn = append(toReturn, label)
+ }
+ }
+ return toReturn
+}
+
+// Returns whether the metric should be allowed based on configured prefix filters
+// Also return the applicable labels
+func (m *Metrics) allowMetric(key []string, labels []Label) (bool, []Label) {
+ m.filterLock.RLock()
+ defer m.filterLock.RUnlock()
+
+ if m.filter == nil || m.filter.Len() == 0 {
+ return m.Config.FilterDefault, m.filterLabels(labels)
+ }
+
+ _, allowed, ok := m.filter.Root().LongestPrefix([]byte(strings.Join(key, ".")))
+ if !ok {
+ return m.Config.FilterDefault, m.filterLabels(labels)
+ }
+
+ return allowed.(bool), m.filterLabels(labels)
+}
+
+// Periodically collects runtime stats to publish
+func (m *Metrics) collectStats() {
+ for {
+ time.Sleep(m.ProfileInterval)
+ m.EmitRuntimeStats()
+ }
+}
+
+// Emits various runtime statsitics
+func (m *Metrics) EmitRuntimeStats() {
+ // Export number of Goroutines
+ numRoutines := runtime.NumGoroutine()
+ m.SetGauge([]string{"runtime", "num_goroutines"}, float32(numRoutines))
+
+ // Export memory stats
+ var stats runtime.MemStats
+ runtime.ReadMemStats(&stats)
+ m.SetGauge([]string{"runtime", "alloc_bytes"}, float32(stats.Alloc))
+ m.SetGauge([]string{"runtime", "sys_bytes"}, float32(stats.Sys))
+ m.SetGauge([]string{"runtime", "malloc_count"}, float32(stats.Mallocs))
+ m.SetGauge([]string{"runtime", "free_count"}, float32(stats.Frees))
+ m.SetGauge([]string{"runtime", "heap_objects"}, float32(stats.HeapObjects))
+ m.SetGauge([]string{"runtime", "total_gc_pause_ns"}, float32(stats.PauseTotalNs))
+ m.SetGauge([]string{"runtime", "total_gc_runs"}, float32(stats.NumGC))
+
+ // Export info about the last few GC runs
+ num := stats.NumGC
+
+ // Handle wrap around
+ if num < m.lastNumGC {
+ m.lastNumGC = 0
+ }
+
+ // Ensure we don't scan more than 256
+ if num-m.lastNumGC >= 256 {
+ m.lastNumGC = num - 255
+ }
+
+ for i := m.lastNumGC; i < num; i++ {
+ pause := stats.PauseNs[i%256]
+ m.AddSample([]string{"runtime", "gc_pause_ns"}, float32(pause))
+ }
+ m.lastNumGC = num
+}
+
+// Creates a new slice with the provided string value as the first element
+// and the provided slice values as the remaining values.
+// Ordering of the values in the provided input slice is kept in tact in the output slice.
+func insert(i int, v string, s []string) []string {
+ // Allocate new slice to avoid modifying the input slice
+ newS := make([]string, len(s)+1)
+
+ // Copy s[0, i-1] into newS
+ for j := 0; j < i; j++ {
+ newS[j] = s[j]
+ }
+
+ // Insert provided element at index i
+ newS[i] = v
+
+ // Copy s[i, len(s)-1] into newS starting at newS[i+1]
+ for j := i; j < len(s); j++ {
+ newS[j+1] = s[j]
+ }
+
+ return newS
+}
diff --git a/vendor/github.com/hashicorp/go-metrics/sink.go b/vendor/github.com/hashicorp/go-metrics/sink.go
new file mode 100644
index 00000000000..c9e520ffe3c
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/sink.go
@@ -0,0 +1,156 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MIT
+
+package metrics
+
+import (
+ "fmt"
+ "net/url"
+)
+
+// The MetricSink interface is used to transmit metrics information
+// to an external system
+type MetricSink interface {
+ // A Gauge should retain the last value it is set to
+ SetGauge(key []string, val float32)
+ SetGaugeWithLabels(key []string, val float32, labels []Label)
+
+ // Should emit a Key/Value pair for each call
+ EmitKey(key []string, val float32)
+
+ // Counters should accumulate values
+ IncrCounter(key []string, val float32)
+ IncrCounterWithLabels(key []string, val float32, labels []Label)
+
+ // Samples are for timing information, where quantiles are used
+ AddSample(key []string, val float32)
+ AddSampleWithLabels(key []string, val float32, labels []Label)
+}
+
+// PrecisionGaugeMetricSink interfae is used to support 64 bit precisions for Sinks, if needed.
+type PrecisionGaugeMetricSink interface {
+ SetPrecisionGauge(key []string, val float64)
+ SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label)
+}
+
+type ShutdownSink interface {
+ MetricSink
+
+ // Shutdown the metric sink, flush metrics to storage, and cleanup resources.
+ // Called immediately prior to application exit. Implementations must block
+ // until metrics are flushed to storage.
+ Shutdown()
+}
+
+// BlackholeSink is used to just blackhole messages
+type BlackholeSink struct{}
+
+func (*BlackholeSink) SetGauge(key []string, val float32) {}
+func (*BlackholeSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {}
+func (*BlackholeSink) SetPrecisionGauge(key []string, val float64) {}
+func (*BlackholeSink) SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label) {}
+func (*BlackholeSink) EmitKey(key []string, val float32) {}
+func (*BlackholeSink) IncrCounter(key []string, val float32) {}
+func (*BlackholeSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {}
+func (*BlackholeSink) AddSample(key []string, val float32) {}
+func (*BlackholeSink) AddSampleWithLabels(key []string, val float32, labels []Label) {}
+
+// FanoutSink is used to sink to fanout values to multiple sinks
+type FanoutSink []MetricSink
+
+func (fh FanoutSink) SetGauge(key []string, val float32) {
+ fh.SetGaugeWithLabels(key, val, nil)
+}
+
+func (fh FanoutSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ for _, s := range fh {
+ s.SetGaugeWithLabels(key, val, labels)
+ }
+}
+
+func (fh FanoutSink) SetPrecisionGauge(key []string, val float64) {
+ fh.SetPrecisionGaugeWithLabels(key, val, nil)
+}
+
+func (fh FanoutSink) SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label) {
+ for _, s := range fh {
+ // The Sink needs to implement PrecisionGaugeMetricSink, in case it doesn't, the metric value won't be set and ingored instead
+ if s64, ok := s.(PrecisionGaugeMetricSink); ok {
+ s64.SetPrecisionGaugeWithLabels(key, val, labels)
+ }
+ }
+}
+
+func (fh FanoutSink) EmitKey(key []string, val float32) {
+ for _, s := range fh {
+ s.EmitKey(key, val)
+ }
+}
+
+func (fh FanoutSink) IncrCounter(key []string, val float32) {
+ fh.IncrCounterWithLabels(key, val, nil)
+}
+
+func (fh FanoutSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ for _, s := range fh {
+ s.IncrCounterWithLabels(key, val, labels)
+ }
+}
+
+func (fh FanoutSink) AddSample(key []string, val float32) {
+ fh.AddSampleWithLabels(key, val, nil)
+}
+
+func (fh FanoutSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
+ for _, s := range fh {
+ s.AddSampleWithLabels(key, val, labels)
+ }
+}
+
+func (fh FanoutSink) Shutdown() {
+ for _, s := range fh {
+ if ss, ok := s.(ShutdownSink); ok {
+ ss.Shutdown()
+ }
+ }
+}
+
+// sinkURLFactoryFunc is an generic interface around the *SinkFromURL() function provided
+// by each sink type
+type sinkURLFactoryFunc func(*url.URL) (MetricSink, error)
+
+// sinkRegistry supports the generic NewMetricSink function by mapping URL
+// schemes to metric sink factory functions
+var sinkRegistry = map[string]sinkURLFactoryFunc{
+ "statsd": NewStatsdSinkFromURL,
+ "statsite": NewStatsiteSinkFromURL,
+ "inmem": NewInmemSinkFromURL,
+}
+
+// NewMetricSinkFromURL allows a generic URL input to configure any of the
+// supported sinks. The scheme of the URL identifies the type of the sink, the
+// and query parameters are used to set options.
+//
+// "statsd://" - Initializes a StatsdSink. The host and port are passed through
+// as the "addr" of the sink
+//
+// "statsite://" - Initializes a StatsiteSink. The host and port become the
+// "addr" of the sink
+//
+// "inmem://" - Initializes an InmemSink. The host and port are ignored. The
+// "interval" and "duration" query parameters must be specified with valid
+// durations, see NewInmemSink for details.
+func NewMetricSinkFromURL(urlStr string) (MetricSink, error) {
+ u, err := url.Parse(urlStr)
+ if err != nil {
+ return nil, err
+ }
+
+ sinkURLFactoryFunc := sinkRegistry[u.Scheme]
+ if sinkURLFactoryFunc == nil {
+ return nil, fmt.Errorf(
+ "cannot create metric sink, unrecognized sink name: %q", u.Scheme)
+ }
+
+ return sinkURLFactoryFunc(u)
+}
diff --git a/vendor/github.com/hashicorp/go-metrics/start.go b/vendor/github.com/hashicorp/go-metrics/start.go
new file mode 100644
index 00000000000..0862fe7f48e
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/start.go
@@ -0,0 +1,176 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MIT
+
+package metrics
+
+import (
+ "os"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ iradix "github.com/hashicorp/go-immutable-radix"
+)
+
+// Config is used to configure metrics settings
+type Config struct {
+ ServiceName string // Prefixed with keys to separate services
+ HostName string // Hostname to use. If not provided and EnableHostname, it will be os.Hostname
+ EnableHostname bool // Enable prefixing gauge values with hostname
+ EnableHostnameLabel bool // Enable adding hostname to labels
+ EnableServiceLabel bool // Enable adding service to labels
+ EnableRuntimeMetrics bool // Enables profiling of runtime metrics (GC, Goroutines, Memory)
+ EnableTypePrefix bool // Prefixes key with a type ("counter", "gauge", "timer")
+ TimerGranularity time.Duration // Granularity of timers.
+ ProfileInterval time.Duration // Interval to profile runtime metrics
+
+ AllowedPrefixes []string // A list of metric prefixes to allow, with '.' as the separator
+ BlockedPrefixes []string // A list of metric prefixes to block, with '.' as the separator
+ AllowedLabels []string // A list of metric labels to allow, with '.' as the separator
+ BlockedLabels []string // A list of metric labels to block, with '.' as the separator
+ FilterDefault bool // Whether to allow metrics by default
+}
+
+// Metrics represents an instance of a metrics sink that can
+// be used to emit
+type Metrics struct {
+ Config
+ lastNumGC uint32
+ sink MetricSink
+ filter *iradix.Tree
+ allowedLabels map[string]bool
+ blockedLabels map[string]bool
+ filterLock sync.RWMutex // Lock filters and allowedLabels/blockedLabels access
+}
+
+// Shared global metrics instance
+var globalMetrics atomic.Value // *Metrics
+
+func init() {
+ // Initialize to a blackhole sink to avoid errors
+ globalMetrics.Store(&Metrics{sink: &BlackholeSink{}})
+}
+
+// Default returns the shared global metrics instance.
+func Default() *Metrics {
+ return globalMetrics.Load().(*Metrics)
+}
+
+// DefaultConfig provides a sane default configuration
+func DefaultConfig(serviceName string) *Config {
+ c := &Config{
+ ServiceName: serviceName, // Use client provided service
+ HostName: "",
+ EnableHostname: true, // Enable hostname prefix
+ EnableRuntimeMetrics: true, // Enable runtime profiling
+ EnableTypePrefix: false, // Disable type prefix
+ TimerGranularity: time.Millisecond, // Timers are in milliseconds
+ ProfileInterval: time.Second, // Poll runtime every second
+ FilterDefault: true, // Don't filter metrics by default
+ }
+
+ // Try to get the hostname
+ name, _ := os.Hostname()
+ c.HostName = name
+ return c
+}
+
+// New is used to create a new instance of Metrics
+func New(conf *Config, sink MetricSink) (*Metrics, error) {
+ met := &Metrics{}
+ met.Config = *conf
+ met.sink = sink
+ met.UpdateFilterAndLabels(conf.AllowedPrefixes, conf.BlockedPrefixes, conf.AllowedLabels, conf.BlockedLabels)
+
+ // Start the runtime collector
+ if conf.EnableRuntimeMetrics {
+ go met.collectStats()
+ }
+ return met, nil
+}
+
+// NewGlobal is the same as New, but it assigns the metrics object to be
+// used globally as well as returning it.
+func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
+ metrics, err := New(conf, sink)
+ if err == nil {
+ globalMetrics.Store(metrics)
+ }
+ return metrics, err
+}
+
+// Proxy all the methods to the globalMetrics instance
+
+// Set gauge key and value with 32 bit precision
+func SetGauge(key []string, val float32) {
+ globalMetrics.Load().(*Metrics).SetGauge(key, val)
+}
+
+// Set gauge key and value with 32 bit precision
+func SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ globalMetrics.Load().(*Metrics).SetGaugeWithLabels(key, val, labels)
+}
+
+// Set gauge key and value with 64 bit precision
+// The Sink needs to implement PrecisionGaugeMetricSink, in case it doesn't, the metric value won't be set and ingored instead
+func SetPrecisionGauge(key []string, val float64) {
+ globalMetrics.Load().(*Metrics).SetPrecisionGauge(key, val)
+}
+
+// Set gauge key, value with 64 bit precision, and labels
+// The Sink needs to implement PrecisionGaugeMetricSink, in case it doesn't, the metric value won't be set and ingored instead
+func SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label) {
+ globalMetrics.Load().(*Metrics).SetPrecisionGaugeWithLabels(key, val, labels)
+}
+
+func EmitKey(key []string, val float32) {
+ globalMetrics.Load().(*Metrics).EmitKey(key, val)
+}
+
+func IncrCounter(key []string, val float32) {
+ globalMetrics.Load().(*Metrics).IncrCounter(key, val)
+}
+
+func IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ globalMetrics.Load().(*Metrics).IncrCounterWithLabels(key, val, labels)
+}
+
+func AddSample(key []string, val float32) {
+ globalMetrics.Load().(*Metrics).AddSample(key, val)
+}
+
+func AddSampleWithLabels(key []string, val float32, labels []Label) {
+ globalMetrics.Load().(*Metrics).AddSampleWithLabels(key, val, labels)
+}
+
+func MeasureSince(key []string, start time.Time) {
+ globalMetrics.Load().(*Metrics).MeasureSince(key, start)
+}
+
+func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
+ globalMetrics.Load().(*Metrics).MeasureSinceWithLabels(key, start, labels)
+}
+
+func UpdateFilter(allow, block []string) {
+ globalMetrics.Load().(*Metrics).UpdateFilter(allow, block)
+}
+
+// UpdateFilterAndLabels set allow/block prefixes of metrics while allowedLabels
+// and blockedLabels - when not nil - allow filtering of labels in order to
+// block/allow globally labels (especially useful when having large number of
+// values for a given label). See README.md for more information about usage.
+func UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
+ globalMetrics.Load().(*Metrics).UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels)
+}
+
+// Shutdown disables metric collection, then blocks while attempting to flush metrics to storage.
+// WARNING: Not all MetricSink backends support this functionality, and calling this will cause them to leak resources.
+// This is intended for use immediately prior to application exit.
+func Shutdown() {
+ m := globalMetrics.Load().(*Metrics)
+ // Swap whatever MetricSink is currently active with a BlackholeSink. Callers must not have a
+ // reason to expect that calls to the library will successfully collect metrics after Shutdown
+ // has been called.
+ globalMetrics.Store(&Metrics{sink: &BlackholeSink{}})
+ m.Shutdown()
+}
diff --git a/vendor/github.com/hashicorp/go-metrics/statsd.go b/vendor/github.com/hashicorp/go-metrics/statsd.go
new file mode 100644
index 00000000000..91abe1f8121
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/statsd.go
@@ -0,0 +1,197 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MIT
+
+package metrics
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "net"
+ "net/url"
+ "strings"
+ "time"
+)
+
+const (
+ // statsdMaxLen is the maximum size of a packet
+ // to send to statsd
+ statsdMaxLen = 1400
+)
+
+// StatsdSink provides a MetricSink that can be used
+// with a statsite or statsd metrics server. It uses
+// only UDP packets, while StatsiteSink uses TCP.
+type StatsdSink struct {
+ addr string
+ metricQueue chan string
+}
+
+// NewStatsdSinkFromURL creates an StatsdSink from a URL. It is used
+// (and tested) from NewMetricSinkFromURL.
+func NewStatsdSinkFromURL(u *url.URL) (MetricSink, error) {
+ return NewStatsdSink(u.Host)
+}
+
+// NewStatsdSink is used to create a new StatsdSink
+func NewStatsdSink(addr string) (*StatsdSink, error) {
+ s := &StatsdSink{
+ addr: addr,
+ metricQueue: make(chan string, 4096),
+ }
+ go s.flushMetrics()
+ return s, nil
+}
+
+// Close is used to stop flushing to statsd
+func (s *StatsdSink) Shutdown() {
+ close(s.metricQueue)
+}
+
+func (s *StatsdSink) SetGauge(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsdSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsdSink) SetPrecisionGauge(key []string, val float64) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsdSink) SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsdSink) EmitKey(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|kv\n", flatKey, val))
+}
+
+func (s *StatsdSink) IncrCounter(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
+}
+
+func (s *StatsdSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
+}
+
+func (s *StatsdSink) AddSample(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
+}
+
+func (s *StatsdSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
+}
+
+// Flattens the key for formatting, removes spaces
+func (s *StatsdSink) flattenKey(parts []string) string {
+ joined := strings.Join(parts, ".")
+ return strings.Map(func(r rune) rune {
+ switch r {
+ case ':':
+ fallthrough
+ case ' ':
+ return '_'
+ default:
+ return r
+ }
+ }, joined)
+}
+
+// Flattens the key along with labels for formatting, removes spaces
+func (s *StatsdSink) flattenKeyLabels(parts []string, labels []Label) string {
+ for _, label := range labels {
+ parts = append(parts, label.Value)
+ }
+ return s.flattenKey(parts)
+}
+
+// Does a non-blocking push to the metrics queue
+func (s *StatsdSink) pushMetric(m string) {
+ select {
+ case s.metricQueue <- m:
+ default:
+ }
+}
+
+// Flushes metrics
+func (s *StatsdSink) flushMetrics() {
+ var sock net.Conn
+ var err error
+ var wait <-chan time.Time
+ ticker := time.NewTicker(flushInterval)
+ defer ticker.Stop()
+
+CONNECT:
+ // Create a buffer
+ buf := bytes.NewBuffer(nil)
+
+ // Attempt to connect
+ sock, err = net.Dial("udp", s.addr)
+ if err != nil {
+ log.Printf("[ERR] Error connecting to statsd! Err: %s", err)
+ goto WAIT
+ }
+
+ for {
+ select {
+ case metric, ok := <-s.metricQueue:
+ // Get a metric from the queue
+ if !ok {
+ goto QUIT
+ }
+
+ // Check if this would overflow the packet size
+ if len(metric)+buf.Len() > statsdMaxLen {
+ _, err := sock.Write(buf.Bytes())
+ buf.Reset()
+ if err != nil {
+ log.Printf("[ERR] Error writing to statsd! Err: %s", err)
+ goto WAIT
+ }
+ }
+
+ // Append to the buffer
+ buf.WriteString(metric)
+
+ case <-ticker.C:
+ if buf.Len() == 0 {
+ continue
+ }
+
+ _, err := sock.Write(buf.Bytes())
+ buf.Reset()
+ if err != nil {
+ log.Printf("[ERR] Error flushing to statsd! Err: %s", err)
+ goto WAIT
+ }
+ }
+ }
+
+WAIT:
+ // Wait for a while
+ wait = time.After(time.Duration(5) * time.Second)
+ for {
+ select {
+ // Dequeue the messages to avoid backlog
+ case _, ok := <-s.metricQueue:
+ if !ok {
+ goto QUIT
+ }
+ case <-wait:
+ goto CONNECT
+ }
+ }
+QUIT:
+ s.metricQueue = nil
+}
diff --git a/vendor/github.com/hashicorp/go-metrics/statsite.go b/vendor/github.com/hashicorp/go-metrics/statsite.go
new file mode 100644
index 00000000000..13f18ed4c0f
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-metrics/statsite.go
@@ -0,0 +1,185 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MIT
+
+package metrics
+
+import (
+ "bufio"
+ "fmt"
+ "log"
+ "net"
+ "net/url"
+ "strings"
+ "time"
+)
+
+const (
+ // We force flush the statsite metrics after this period of
+ // inactivity. Prevents stats from getting stuck in a buffer
+ // forever.
+ flushInterval = 100 * time.Millisecond
+)
+
+// NewStatsiteSinkFromURL creates an StatsiteSink from a URL. It is used
+// (and tested) from NewMetricSinkFromURL.
+func NewStatsiteSinkFromURL(u *url.URL) (MetricSink, error) {
+ return NewStatsiteSink(u.Host)
+}
+
+// StatsiteSink provides a MetricSink that can be used with a
+// statsite metrics server
+type StatsiteSink struct {
+ addr string
+ metricQueue chan string
+}
+
+// NewStatsiteSink is used to create a new StatsiteSink
+func NewStatsiteSink(addr string) (*StatsiteSink, error) {
+ s := &StatsiteSink{
+ addr: addr,
+ metricQueue: make(chan string, 4096),
+ }
+ go s.flushMetrics()
+ return s, nil
+}
+
+// Close is used to stop flushing to statsite
+func (s *StatsiteSink) Shutdown() {
+ close(s.metricQueue)
+}
+
+func (s *StatsiteSink) SetGauge(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsiteSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsiteSink) SetPrecisionGauge(key []string, val float64) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsiteSink) SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsiteSink) EmitKey(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|kv\n", flatKey, val))
+}
+
+func (s *StatsiteSink) IncrCounter(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
+}
+
+func (s *StatsiteSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
+}
+
+func (s *StatsiteSink) AddSample(key []string, val float32) {
+ flatKey := s.flattenKey(key)
+ s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
+}
+
+func (s *StatsiteSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
+ flatKey := s.flattenKeyLabels(key, labels)
+ s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
+}
+
+// Flattens the key for formatting, removes spaces
+func (s *StatsiteSink) flattenKey(parts []string) string {
+ joined := strings.Join(parts, ".")
+ return strings.Map(func(r rune) rune {
+ switch r {
+ case ':':
+ fallthrough
+ case ' ':
+ return '_'
+ default:
+ return r
+ }
+ }, joined)
+}
+
+// Flattens the key along with labels for formatting, removes spaces
+func (s *StatsiteSink) flattenKeyLabels(parts []string, labels []Label) string {
+ for _, label := range labels {
+ parts = append(parts, label.Value)
+ }
+ return s.flattenKey(parts)
+}
+
+// Does a non-blocking push to the metrics queue
+func (s *StatsiteSink) pushMetric(m string) {
+ select {
+ case s.metricQueue <- m:
+ default:
+ }
+}
+
+// Flushes metrics
+func (s *StatsiteSink) flushMetrics() {
+ var sock net.Conn
+ var err error
+ var wait <-chan time.Time
+ var buffered *bufio.Writer
+ ticker := time.NewTicker(flushInterval)
+ defer ticker.Stop()
+
+CONNECT:
+ // Attempt to connect
+ sock, err = net.Dial("tcp", s.addr)
+ if err != nil {
+ log.Printf("[ERR] Error connecting to statsite! Err: %s", err)
+ goto WAIT
+ }
+
+ // Create a buffered writer
+ buffered = bufio.NewWriter(sock)
+
+ for {
+ select {
+ case metric, ok := <-s.metricQueue:
+ // Get a metric from the queue
+ if !ok {
+ goto QUIT
+ }
+
+ // Try to send to statsite
+ _, err := buffered.Write([]byte(metric))
+ if err != nil {
+ log.Printf("[ERR] Error writing to statsite! Err: %s", err)
+ goto WAIT
+ }
+ case <-ticker.C:
+ if err := buffered.Flush(); err != nil {
+ log.Printf("[ERR] Error flushing to statsite! Err: %s", err)
+ goto WAIT
+ }
+ }
+ }
+
+WAIT:
+ // Wait for a while
+ wait = time.After(time.Duration(5) * time.Second)
+ for {
+ select {
+ // Dequeue the messages to avoid backlog
+ case _, ok := <-s.metricQueue:
+ if !ok {
+ goto QUIT
+ }
+ case <-wait:
+ goto CONNECT
+ }
+ }
+QUIT:
+ s.metricQueue = nil
+}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/LICENSE b/vendor/github.com/hashicorp/go-msgpack/v2/LICENSE
new file mode 100644
index 00000000000..95a0f0541cd
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2012-2015 Ugorji Nwoke.
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/build.sh b/vendor/github.com/hashicorp/go-msgpack/v2/codec/build.sh
new file mode 100644
index 00000000000..831bd864422
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/build.sh
@@ -0,0 +1,263 @@
+#!/bin/bash
+
+# Run all the different permutations of all the tests and other things
+# This helps ensure that nothing gets broken.
+
+_tests() {
+ local gover=$( go version | cut -f 3 -d ' ' )
+ local a=( "" "codecgen" )
+ for i in "${a[@]}"
+ do
+ echo ">>>> TAGS: $i"
+ local i2=${i:-default}
+ case $gover in
+ go1.[0-6]*) go vet -printfuncs "errorf" "$@" &&
+ go test ${zargs[*]} -vet off -tags "$i" "$@" ;;
+ *) go vet -printfuncs "errorf" "$@" &&
+ go test ${zargs[*]} -vet off -tags "alltests $i" -run "Suite" -coverprofile "${i2// /-}.cov.out" "$@" ;;
+ esac
+ if [[ "$?" != 0 ]]; then return 1; fi
+ done
+ echo "++++++++ TEST SUITES ALL PASSED ++++++++"
+}
+
+
+# is a generation needed?
+_ng() {
+ local a="$1"
+ if [[ ! -e "$a" ]]; then echo 1; return; fi
+ for i in `ls -1 *.go.tmpl gen.go values_test.go`
+ do
+ if [[ "$a" -ot "$i" ]]; then echo 1; return; fi
+ done
+}
+
+_prependbt() {
+ cat > ${2} <> ${2}
+ rm -f ${1}
+}
+
+# _build generates gen-helper.go.
+_build() {
+ if ! [[ "${zforce}" || $(_ng "gen-helper.generated.go") || $(_ng "gen.generated.go") ]]; then return 0; fi
+
+ if [ "${zbak}" ]; then
+ _zts=`date '+%m%d%Y_%H%M%S'`
+ _gg=".generated.go"
+ [ -e "gen-helper${_gg}" ] && mv gen-helper${_gg} gen-helper${_gg}__${_zts}.bak
+ [ -e "gen${_gg}" ] && mv gen${_gg} gen${_gg}__${_zts}.bak
+ fi
+ rm -f gen-helper.generated.go gen.generated.go \
+ *_generated_test.go *.generated_ffjson_expose.go
+
+ cat > gen.generated.go <> gen.generated.go < gen-dec-map.go.tmpl
+ cat >> gen.generated.go <> gen.generated.go < gen-dec-array.go.tmpl
+ cat >> gen.generated.go <> gen.generated.go < gen-enc-chan.go.tmpl
+ cat >> gen.generated.go < gen-from-tmpl.codec.generated.go < gen-from-tmpl.generated.go < " + fnameOut + " ______")
+fin, err := os.Open(fnameIn)
+if err != nil { panic(err) }
+defer fin.Close()
+fout, err := os.Create(fnameOut)
+if err != nil { panic(err) }
+defer fout.Close()
+err = codec.GenInternalGoFile(fin, fout)
+if err != nil { panic(err) }
+}
+
+func main() {
+run("gen-helper.go.tmpl", "gen-helper.generated.go")
+run("mammoth-test.go.tmpl", "mammoth_generated_test.go")
+run("mammoth2-test.go.tmpl", "mammoth2_generated_test.go")
+}
+EOF
+
+ sed -e 's+// __DO_NOT_REMOVE__NEEDED_FOR_REPLACING__IMPORT_PATH__FOR_CODEC_BENCH__+import . "github.com/hashicorp/go-msgpack/v2/codec"+' \
+ shared_test.go > bench/shared_test.go
+
+ # explicitly return 0 if this passes, else return 1
+ go run -tags "codecgen.exec" gen-from-tmpl.generated.go &&
+ rm -f gen-from-tmpl.*generated.go &&
+ return 0
+ return 1
+}
+
+_codegenerators() {
+ local c5="_generated_test.go"
+ local c7="$PWD/codecgen"
+ local c8="$c7/__codecgen"
+ local c9="codecgen-scratch.go"
+
+ if ! [[ $zforce || $(_ng "values_codecgen${c5}") ]]; then return 0; fi
+
+ # Note: ensure you run the codecgen for this codebase/directory i.e. ./codecgen/codecgen
+ true &&
+ echo "codecgen ... " &&
+ if [[ $zforce || ! -f "$c8" || "$c7/gen.go" -nt "$c8" ]]; then
+ echo "rebuilding codecgen ... " && ( cd codecgen && go build -o $c8 ${zargs[*]} . )
+ fi &&
+ $c8 -rt codecgen -t 'codecgen generated' -o values_codecgen${c5} -d 19780 $zfin $zfin2 &&
+ cp mammoth2_generated_test.go $c9 &&
+ $c8 -o mammoth2_codecgen${c5} -d 19781 mammoth2_generated_test.go &&
+ rm -f $c9 &&
+ echo "generators done!"
+}
+
+_prebuild() {
+ echo "prebuild: zforce: $zforce"
+ local d="$PWD"
+ zfin="test_values.generated.go"
+ zfin2="test_values_flex.generated.go"
+ zpkg="github.com/hashicorp/go-msgpack/v2/codec"
+ # zpkg=${d##*/src/}
+ # zgobase=${d%%/src/*}
+ # rm -f *_generated_test.go
+ rm -f codecgen-*.go &&
+ _build &&
+ cp $d/values_test.go $d/$zfin &&
+ cp $d/values_flex_test.go $d/$zfin2 &&
+ _codegenerators &&
+ if [[ "$(type -t _codegenerators_external )" = "function" ]]; then _codegenerators_external ; fi &&
+ if [[ $zforce ]]; then go install ${zargs[*]} .; fi &&
+ echo "prebuild done successfully"
+ rm -f $d/$zfin $d/$zfin2
+ unset zfin zfin2 zpkg
+}
+
+_make() {
+ zforce=1
+ (cd codecgen && go install ${zargs[*]} .) && _prebuild && go install ${zargs[*]} .
+ unset zforce
+}
+
+_clean() {
+ rm -f gen-from-tmpl.*generated.go \
+ codecgen-*.go \
+ test_values.generated.go test_values_flex.generated.go
+}
+
+_release() {
+ local reply
+ read -p "Pre-release validation takes a few minutes and MUST be run from within GOPATH/src. Confirm y/n? " -n 1 -r reply
+ echo
+ if [[ ! $reply =~ ^[Yy]$ ]]; then return 1; fi
+
+ # expects GOROOT, GOROOT_BOOTSTRAP to have been set.
+ if [[ -z "${GOROOT// }" || -z "${GOROOT_BOOTSTRAP// }" ]]; then return 1; fi
+ # (cd $GOROOT && git checkout -f master && git pull && git reset --hard)
+ (cd $GOROOT && git pull)
+ local f=`pwd`/make.release.out
+ cat > $f <>$f
+ if [[ "$i" != "master" ]]; then i="release-branch.go$i"; fi
+ (false ||
+ (echo "===== BUILDING GO SDK for branch: $i ... =====" &&
+ cd $GOROOT &&
+ git checkout -f $i && git reset --hard && git clean -f . &&
+ cd src && ./make.bash >>$f 2>&1 && sleep 1 ) ) &&
+ echo "===== GO SDK BUILD DONE =====" &&
+ _prebuild &&
+ echo "===== PREBUILD DONE with exit: $? =====" &&
+ _tests "$@"
+ if [[ "$?" != 0 ]]; then return 1; fi
+ done
+ unset zforce
+ echo "++++++++ RELEASE TEST SUITES ALL PASSED ++++++++"
+}
+
+_usage() {
+ cat < [tests, make, prebuild (force) (external), inlining diagnostics, mid-stack inlining, race detector]
+ -v -> verbose
+EOF
+ if [[ "$(type -t _usage_run)" = "function" ]]; then _usage_run ; fi
+}
+
+_main() {
+ if [[ -z "$1" ]]; then _usage; return 1; fi
+ local x
+ unset zforce
+ zargs=()
+ zbenchflags=""
+ OPTIND=1
+ while getopts ":ctmnrgpfvlzdb:" flag
+ do
+ case "x$flag" in
+ 'xf') zforce=1 ;;
+ 'xv') zverbose=1 ;;
+ 'xl') zargs+=("-gcflags"); zargs+=("-l=4") ;;
+ 'xn') zargs+=("-gcflags"); zargs+=("-m=2") ;;
+ 'xd') zargs+=("-race") ;;
+ 'xb') x='b'; zbenchflags=${OPTARG} ;;
+ x\?) _usage; return 1 ;;
+ *) x=$flag ;;
+ esac
+ done
+ shift $((OPTIND-1))
+ # echo ">>>> _main: extra args: $@"
+ case "x$x" in
+ 'xt') _tests "$@" ;;
+ 'xm') _make "$@" ;;
+ 'xr') _release "$@" ;;
+ 'xg') _go ;;
+ 'xp') _prebuild "$@" ;;
+ 'xc') _clean "$@" ;;
+ 'xz') _analyze "$@" ;;
+ 'xb') _bench "$@" ;;
+ esac
+ unset zforce zargs zbenchflags
+}
+
+[ "." = `dirname $0` ] && _main "$@"
\ No newline at end of file
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/codecgen.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/codecgen.go
new file mode 100644
index 00000000000..28fa810593d
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/codecgen.go
@@ -0,0 +1,14 @@
+//go:build codecgen || generated
+// +build codecgen generated
+
+package codec
+
+// this file is here, to set the codecgen variable to true
+// when the build tag codecgen is set.
+//
+// this allows us do specific things e.g. skip missing fields tests,
+// when running in codecgen mode.
+
+func init() {
+ codecgen = true
+}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/decode.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/decode.go
new file mode 100644
index 00000000000..0e09863e645
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/decode.go
@@ -0,0 +1,3111 @@
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+package codec
+
+import (
+ "encoding"
+ "errors"
+ "fmt"
+ "io"
+ "reflect"
+ "runtime"
+ "strconv"
+ "time"
+)
+
+// Some tagging information for error messages.
+const (
+ msgBadDesc = "unrecognized descriptor byte"
+ // msgDecCannotExpandArr = "cannot expand go array from %v to stream length: %v"
+)
+
+const (
+ decDefMaxDepth = 1024 // maximum depth
+ decDefSliceCap = 8
+ decDefChanCap = 64 // should be large, as cap cannot be expanded
+ decScratchByteArrayLen = cacheLineSize // + (8 * 2) // - (8 * 1)
+)
+
+var (
+ errstrOnlyMapOrArrayCanDecodeIntoStruct = "only encoded map or array can be decoded into a struct"
+ errstrCannotDecodeIntoNil = "cannot decode into nil"
+
+ errmsgExpandSliceOverflow = "expand slice: slice overflow"
+ errmsgExpandSliceCannotChange = "expand slice: cannot change"
+
+ errDecoderNotInitialized = errors.New("Decoder not initialized")
+
+ errDecUnreadByteNothingToRead = errors.New("cannot unread - nothing has been read")
+ errDecUnreadByteLastByteNotRead = errors.New("cannot unread - last byte has not been read")
+ errDecUnreadByteUnknown = errors.New("cannot unread - reason unknown")
+ errMaxDepthExceeded = errors.New("maximum decoding depth exceeded")
+)
+
+/*
+
+// decReader abstracts the reading source, allowing implementations that can
+// read from an io.Reader or directly off a byte slice with zero-copying.
+//
+// Deprecated: Use decReaderSwitch instead.
+type decReader interface {
+ unreadn1()
+ // readx will use the implementation scratch buffer if possible i.e. n < len(scratchbuf), OR
+ // just return a view of the []byte being decoded from.
+ // Ensure you call detachZeroCopyBytes later if this needs to be sent outside codec control.
+ readx(n int) []byte
+ readb([]byte)
+ readn1() uint8
+ numread() uint // number of bytes read
+ track()
+ stopTrack() []byte
+
+ // skip will skip any byte that matches, and return the first non-matching byte
+ skip(accept *bitset256) (token byte)
+ // readTo will read any byte that matches, stopping once no-longer matching.
+ readTo(in []byte, accept *bitset256) (out []byte)
+ // readUntil will read, only stopping once it matches the 'stop' byte.
+ readUntil(in []byte, stop byte) (out []byte)
+}
+
+*/
+
+type decDriver interface {
+ // this will check if the next token is a break.
+ CheckBreak() bool
+ // TryDecodeAsNil tries to decode as nil.
+ // Note: TryDecodeAsNil should be careful not to share any temporary []byte with
+ // the rest of the decDriver. This is because sometimes, we optimize by holding onto
+ // a transient []byte, and ensuring the only other call we make to the decDriver
+ // during that time is maybe a TryDecodeAsNil() call.
+ TryDecodeAsNil() bool
+ // ContainerType returns one of: Bytes, String, Nil, Slice or Map. Return unSet if not known.
+ ContainerType() (vt valueType)
+ // IsBuiltinType(rt uintptr) bool
+
+ // DecodeNaked will decode primitives (number, bool, string, []byte) and RawExt.
+ // For maps and arrays, it will not do the decoding in-band, but will signal
+ // the decoder, so that is done later, by setting the decNaked.valueType field.
+ //
+ // Note: Numbers are decoded as int64, uint64, float64 only (no smaller sized number types).
+ // for extensions, DecodeNaked must read the tag and the []byte if it exists.
+ // if the []byte is not read, then kInterfaceNaked will treat it as a Handle
+ // that stores the subsequent value in-band, and complete reading the RawExt.
+ //
+ // extensions should also use readx to decode them, for efficiency.
+ // kInterface will extract the detached byte slice if it has to pass it outside its realm.
+ DecodeNaked()
+
+ // Deprecated: use DecodeInt64 and DecodeUint64 instead
+ // DecodeInt(bitsize uint8) (i int64)
+ // DecodeUint(bitsize uint8) (ui uint64)
+
+ DecodeInt64() (i int64)
+ DecodeUint64() (ui uint64)
+
+ DecodeFloat64() (f float64)
+ DecodeBool() (b bool)
+ // DecodeString can also decode symbols.
+ // It looks redundant as DecodeBytes is available.
+ // However, some codecs (e.g. binc) support symbols and can
+ // return a pre-stored string value, meaning that it can bypass
+ // the cost of []byte->string conversion.
+ DecodeString() (s string)
+ DecodeStringAsBytes() (v []byte)
+
+ // DecodeBytes may be called directly, without going through reflection.
+ // Consequently, it must be designed to handle possible nil.
+ DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte)
+ // DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte)
+
+ // decodeExt will decode into a *RawExt or into an extension.
+ DecodeExt(v interface{}, xtag uint64, ext Ext) (realxtag uint64)
+ // decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte)
+
+ DecodeTime() (t time.Time)
+
+ ReadArrayStart() int
+ ReadArrayElem()
+ ReadArrayEnd()
+ ReadMapStart() int
+ ReadMapElemKey()
+ ReadMapElemValue()
+ ReadMapEnd()
+
+ reset()
+ uncacheRead()
+}
+
+type decodeError struct {
+ codecError
+ pos int
+}
+
+func (d decodeError) Error() string {
+ return fmt.Sprintf("%s decode error [pos %d]: %v", d.name, d.pos, d.err)
+}
+
+type decDriverNoopContainerReader struct{}
+
+func (x decDriverNoopContainerReader) ReadArrayStart() (v int) { return }
+func (x decDriverNoopContainerReader) ReadArrayElem() {}
+func (x decDriverNoopContainerReader) ReadArrayEnd() {}
+func (x decDriverNoopContainerReader) ReadMapStart() (v int) { return }
+func (x decDriverNoopContainerReader) ReadMapElemKey() {}
+func (x decDriverNoopContainerReader) ReadMapElemValue() {}
+func (x decDriverNoopContainerReader) ReadMapEnd() {}
+func (x decDriverNoopContainerReader) CheckBreak() (v bool) { return }
+
+// func (x decNoSeparator) uncacheRead() {}
+
+// DecodeOptions captures configuration options during decode.
+type DecodeOptions struct {
+ // MapType specifies type to use during schema-less decoding of a map in the stream.
+ // If nil (unset), we default to map[string]interface{} iff json handle and MapStringAsKey=true,
+ // else map[interface{}]interface{}.
+ MapType reflect.Type
+
+ // SliceType specifies type to use during schema-less decoding of an array in the stream.
+ // If nil (unset), we default to []interface{} for all formats.
+ SliceType reflect.Type
+
+ // MaxInitLen defines the maxinum initial length that we "make" a collection
+ // (string, slice, map, chan). If 0 or negative, we default to a sensible value
+ // based on the size of an element in the collection.
+ //
+ // For example, when decoding, a stream may say that it has 2^64 elements.
+ // We should not auto-matically provision a slice of that size, to prevent Out-Of-Memory crash.
+ // Instead, we provision up to MaxInitLen, fill that up, and start appending after that.
+ MaxInitLen int
+
+ // ReaderBufferSize is the size of the buffer used when reading.
+ //
+ // if > 0, we use a smart buffer internally for performance purposes.
+ ReaderBufferSize int
+
+ // MaxDepth defines the maximum depth when decoding nested
+ // maps and slices. If 0 or negative, we default to a suitably large number (currently 1024).
+ MaxDepth int16
+
+ // If ErrorIfNoField, return an error when decoding a map
+ // from a codec stream into a struct, and no matching struct field is found.
+ ErrorIfNoField bool
+
+ // If ErrorIfNoArrayExpand, return an error when decoding a slice/array that cannot be expanded.
+ // For example, the stream contains an array of 8 items, but you are decoding into a [4]T array,
+ // or you are decoding into a slice of length 4 which is non-addressable (and so cannot be set).
+ ErrorIfNoArrayExpand bool
+
+ // If SignedInteger, use the int64 during schema-less decoding of unsigned values (not uint64).
+ SignedInteger bool
+
+ // MapValueReset controls how we decode into a map value.
+ //
+ // By default, we MAY retrieve the mapping for a key, and then decode into that.
+ // However, especially with big maps, that retrieval may be expensive and unnecessary
+ // if the stream already contains all that is necessary to recreate the value.
+ //
+ // If true, we will never retrieve the previous mapping,
+ // but rather decode into a new value and set that in the map.
+ //
+ // If false, we will retrieve the previous mapping if necessary e.g.
+ // the previous mapping is a pointer, or is a struct or array with pre-set state,
+ // or is an interface.
+ MapValueReset bool
+
+ // SliceElementReset: on decoding a slice, reset the element to a zero value first.
+ //
+ // concern: if the slice already contained some garbage, we will decode into that garbage.
+ SliceElementReset bool
+
+ // InterfaceReset controls how we decode into an interface.
+ //
+ // By default, when we see a field that is an interface{...},
+ // or a map with interface{...} value, we will attempt decoding into the
+ // "contained" value.
+ //
+ // However, this prevents us from reading a string into an interface{}
+ // that formerly contained a number.
+ //
+ // If true, we will decode into a new "blank" value, and set that in the interface.
+ // If false, we will decode into whatever is contained in the interface.
+ InterfaceReset bool
+
+ // InternString controls interning of strings during decoding.
+ //
+ // Some handles, e.g. json, typically will read map keys as strings.
+ // If the set of keys are finite, it may help reduce allocation to
+ // look them up from a map (than to allocate them afresh).
+ //
+ // Note: Handles will be smart when using the intern functionality.
+ // Every string should not be interned.
+ // An excellent use-case for interning is struct field names,
+ // or map keys where key type is string.
+ InternString bool
+
+ // PreferArrayOverSlice controls whether to decode to an array or a slice.
+ //
+ // This only impacts decoding into a nil interface{}.
+ // Consequently, it has no effect on codecgen.
+ //
+ // *Note*: This only applies if using go1.5 and above,
+ // as it requires reflect.ArrayOf support which was absent before go1.5.
+ PreferArrayOverSlice bool
+
+ // DeleteOnNilMapValue controls how to decode a nil value in the stream.
+ //
+ // If true, we will delete the mapping of the key.
+ // Else, just set the mapping to the zero value of the type.
+ DeleteOnNilMapValue bool
+
+ // RawToString controls how raw bytes in a stream are decoded into a nil interface{}.
+ // By default, they are decoded as []byte, but can be decoded as string (if configured).
+ RawToString bool
+}
+
+// ------------------------------------------------
+
+type unreadByteStatus uint8
+
+// unreadByteStatus goes from
+// undefined (when initialized) -- (read) --> canUnread -- (unread) --> canRead ...
+const (
+ unreadByteUndefined unreadByteStatus = iota
+ unreadByteCanRead
+ unreadByteCanUnread
+)
+
+type ioDecReaderCommon struct {
+ r io.Reader // the reader passed in
+
+ n uint // num read
+
+ l byte // last byte
+ ls unreadByteStatus // last byte status
+ trb bool // tracking bytes turned on
+ _ bool
+ b [4]byte // tiny buffer for reading single bytes
+
+ tr []byte // tracking bytes read
+}
+
+func (z *ioDecReaderCommon) reset(r io.Reader) {
+ z.r = r
+ z.ls = unreadByteUndefined
+ z.l, z.n = 0, 0
+ z.trb = false
+ if z.tr != nil {
+ z.tr = z.tr[:0]
+ }
+}
+
+func (z *ioDecReaderCommon) numread() uint {
+ return z.n
+}
+
+func (z *ioDecReaderCommon) track() {
+ if z.tr != nil {
+ z.tr = z.tr[:0]
+ }
+ z.trb = true
+}
+
+func (z *ioDecReaderCommon) stopTrack() (bs []byte) {
+ z.trb = false
+ return z.tr
+}
+
+// ------------------------------------------
+
+// ioDecReader is a decReader that reads off an io.Reader.
+//
+// It also has a fallback implementation of ByteScanner if needed.
+type ioDecReader struct {
+ ioDecReaderCommon
+
+ rr io.Reader
+ br io.ByteScanner
+
+ x [scratchByteArrayLen]byte // for: get struct field name, swallow valueTypeBytes, etc
+ _ [1]uint64 // padding
+}
+
+func (z *ioDecReader) reset(r io.Reader) {
+ z.ioDecReaderCommon.reset(r)
+
+ var ok bool
+ z.rr = r
+ z.br, ok = r.(io.ByteScanner)
+ if !ok {
+ z.br = z
+ z.rr = z
+ }
+}
+
+func (z *ioDecReader) Read(p []byte) (n int, err error) {
+ if len(p) == 0 {
+ return
+ }
+ var firstByte bool
+ if z.ls == unreadByteCanRead {
+ z.ls = unreadByteCanUnread
+ p[0] = z.l
+ if len(p) == 1 {
+ n = 1
+ return
+ }
+ firstByte = true
+ p = p[1:]
+ }
+ n, err = z.r.Read(p)
+ if n > 0 {
+ if err == io.EOF && n == len(p) {
+ err = nil // read was successful, so postpone EOF (till next time)
+ }
+ z.l = p[n-1]
+ z.ls = unreadByteCanUnread
+ }
+ if firstByte {
+ n++
+ }
+ return
+}
+
+func (z *ioDecReader) ReadByte() (c byte, err error) {
+ n, err := z.Read(z.b[:1])
+ if n == 1 {
+ c = z.b[0]
+ if err == io.EOF {
+ err = nil // read was successful, so postpone EOF (till next time)
+ }
+ }
+ return
+}
+
+func (z *ioDecReader) UnreadByte() (err error) {
+ switch z.ls {
+ case unreadByteCanUnread:
+ z.ls = unreadByteCanRead
+ case unreadByteCanRead:
+ err = errDecUnreadByteLastByteNotRead
+ case unreadByteUndefined:
+ err = errDecUnreadByteNothingToRead
+ default:
+ err = errDecUnreadByteUnknown
+ }
+ return
+}
+
+func (z *ioDecReader) readx(n uint) (bs []byte) {
+ if n == 0 {
+ return
+ }
+ if n < uint(len(z.x)) {
+ bs = z.x[:n]
+ } else {
+ bs = make([]byte, n)
+ }
+ if _, err := decReadFull(z.rr, bs); err != nil {
+ panic(err)
+ }
+ z.n += uint(len(bs))
+ if z.trb {
+ z.tr = append(z.tr, bs...)
+ }
+ return
+}
+
+func (z *ioDecReader) readb(bs []byte) {
+ if len(bs) == 0 {
+ return
+ }
+ if _, err := decReadFull(z.rr, bs); err != nil {
+ panic(err)
+ }
+ z.n += uint(len(bs))
+ if z.trb {
+ z.tr = append(z.tr, bs...)
+ }
+}
+
+func (z *ioDecReader) readn1eof() (b uint8, eof bool) {
+ b, err := z.br.ReadByte()
+ if err == nil {
+ z.n++
+ if z.trb {
+ z.tr = append(z.tr, b)
+ }
+ } else if err == io.EOF {
+ eof = true
+ } else {
+ panic(err)
+ }
+ return
+}
+
+func (z *ioDecReader) readn1() (b uint8) {
+ b, err := z.br.ReadByte()
+ if err == nil {
+ z.n++
+ if z.trb {
+ z.tr = append(z.tr, b)
+ }
+ return
+ }
+ panic(err)
+}
+
+func (z *ioDecReader) skip(accept *bitset256) (token byte) {
+ var eof bool
+ // for {
+ // token, eof = z.readn1eof()
+ // if eof {
+ // return
+ // }
+ // if accept.isset(token) {
+ // continue
+ // }
+ // return
+ // }
+LOOP:
+ token, eof = z.readn1eof()
+ if eof {
+ return
+ }
+ if accept.isset(token) {
+ goto LOOP
+ }
+ return
+}
+
+func (z *ioDecReader) readTo(in []byte, accept *bitset256) []byte {
+ // out = in
+
+ // for {
+ // token, eof := z.readn1eof()
+ // if eof {
+ // return
+ // }
+ // if accept.isset(token) {
+ // out = append(out, token)
+ // } else {
+ // z.unreadn1()
+ // return
+ // }
+ // }
+LOOP:
+ token, eof := z.readn1eof()
+ if eof {
+ return in
+ }
+ if accept.isset(token) {
+ // out = append(out, token)
+ in = append(in, token)
+ goto LOOP
+ }
+ z.unreadn1()
+ return in
+}
+
+func (z *ioDecReader) readUntil(in []byte, stop byte) (out []byte) {
+ out = in
+ // for {
+ // token, eof := z.readn1eof()
+ // if eof {
+ // panic(io.EOF)
+ // }
+ // out = append(out, token)
+ // if token == stop {
+ // return
+ // }
+ // }
+LOOP:
+ token, eof := z.readn1eof()
+ if eof {
+ panic(io.EOF)
+ }
+ out = append(out, token)
+ if token == stop {
+ return
+ }
+ goto LOOP
+}
+
+//go:noinline
+func (z *ioDecReader) unreadn1() {
+ err := z.br.UnreadByte()
+ if err != nil {
+ panic(err)
+ }
+ z.n--
+ if z.trb {
+ if l := len(z.tr) - 1; l >= 0 {
+ z.tr = z.tr[:l]
+ }
+ }
+}
+
+// ------------------------------------
+
+type bufioDecReader struct {
+ ioDecReaderCommon
+
+ c uint // cursor
+ buf []byte
+
+ bytesBufPooler
+
+ // err error
+
+ // Extensions can call Decode() within a current Decode() call.
+ // We need to know when the top level Decode() call returns,
+ // so we can decide whether to Release() or not.
+ calls uint16 // what depth in mustDecode are we in now.
+
+ _ [6]uint8 // padding
+
+ _ [1]uint64 // padding
+}
+
+func (z *bufioDecReader) reset(r io.Reader, bufsize int) {
+ z.ioDecReaderCommon.reset(r)
+ z.c = 0
+ z.calls = 0
+ if cap(z.buf) >= bufsize {
+ z.buf = z.buf[:0]
+ } else {
+ z.buf = z.bytesBufPooler.get(bufsize)[:0]
+ // z.buf = make([]byte, 0, bufsize)
+ }
+}
+
+func (z *bufioDecReader) release() {
+ z.buf = nil
+ z.bytesBufPooler.end()
+}
+
+func (z *bufioDecReader) readb(p []byte) {
+ var n = uint(copy(p, z.buf[z.c:]))
+ z.n += n
+ z.c += n
+ if len(p) == int(n) {
+ if z.trb {
+ z.tr = append(z.tr, p...) // cost=9
+ }
+ } else {
+ z.readbFill(p, n)
+ }
+}
+
+//go:noinline - fallback when z.buf is consumed
+func (z *bufioDecReader) readbFill(p0 []byte, n uint) {
+ // at this point, there's nothing in z.buf to read (z.buf is fully consumed)
+ p := p0[n:]
+ var n2 uint
+ var err error
+ if len(p) > cap(z.buf) {
+ n2, err = decReadFull(z.r, p)
+ if err != nil {
+ panic(err)
+ }
+ n += n2
+ z.n += n2
+ // always keep last byte in z.buf
+ z.buf = z.buf[:1]
+ z.buf[0] = p[len(p)-1]
+ z.c = 1
+ if z.trb {
+ z.tr = append(z.tr, p0[:n]...)
+ }
+ return
+ }
+ // z.c is now 0, and len(p) <= cap(z.buf)
+LOOP:
+ // for len(p) > 0 && z.err == nil {
+ if len(p) > 0 {
+ z.buf = z.buf[0:cap(z.buf)]
+ var n1 int
+ n1, err = z.r.Read(z.buf)
+ n2 = uint(n1)
+ if n2 == 0 && err != nil {
+ panic(err)
+ }
+ z.buf = z.buf[:n2]
+ n2 = uint(copy(p, z.buf))
+ z.c = n2
+ n += n2
+ z.n += n2
+ p = p[n2:]
+ goto LOOP
+ }
+ if z.c == 0 {
+ z.buf = z.buf[:1]
+ z.buf[0] = p[len(p)-1]
+ z.c = 1
+ }
+ if z.trb {
+ z.tr = append(z.tr, p0[:n]...)
+ }
+}
+
+func (z *bufioDecReader) readn1() (b byte) {
+ // fast-path, so we elide calling into Read() most of the time
+ if z.c < uint(len(z.buf)) {
+ b = z.buf[z.c]
+ z.c++
+ z.n++
+ if z.trb {
+ z.tr = append(z.tr, b)
+ }
+ } else { // meaning z.c == len(z.buf) or greater ... so need to fill
+ z.readbFill(z.b[:1], 0)
+ b = z.b[0]
+ }
+ return
+}
+
+func (z *bufioDecReader) unreadn1() {
+ if z.c == 0 {
+ panic(errDecUnreadByteNothingToRead)
+ }
+ z.c--
+ z.n--
+ if z.trb {
+ z.tr = z.tr[:len(z.tr)-1]
+ }
+}
+
+func (z *bufioDecReader) readx(n uint) (bs []byte) {
+ if n == 0 {
+ // return
+ } else if z.c+n <= uint(len(z.buf)) {
+ bs = z.buf[z.c : z.c+n]
+ z.n += n
+ z.c += n
+ if z.trb {
+ z.tr = append(z.tr, bs...)
+ }
+ } else {
+ bs = make([]byte, n)
+ // n no longer used - can reuse
+ n = uint(copy(bs, z.buf[z.c:]))
+ z.n += n
+ z.c += n
+ z.readbFill(bs, n)
+ }
+ return
+}
+
+//go:noinline - track called by Decoder.nextValueBytes() (called by jsonUnmarshal,rawBytes)
+func (z *bufioDecReader) doTrack(y uint) {
+ z.tr = append(z.tr, z.buf[z.c:y]...) // cost=14???
+}
+
+func (z *bufioDecReader) skipLoopFn(i uint) {
+ z.n += (i - z.c) - 1
+ i++
+ if z.trb {
+ // z.tr = append(z.tr, z.buf[z.c:i]...)
+ z.doTrack(i)
+ }
+ z.c = i
+}
+
+func (z *bufioDecReader) skip(accept *bitset256) (token byte) {
+ // token, _ = z.search(nil, accept, 0, 1); return
+
+ // for i := z.c; i < len(z.buf); i++ {
+ // if token = z.buf[i]; !accept.isset(token) {
+ // z.skipLoopFn(i)
+ // return
+ // }
+ // }
+
+ i := z.c
+LOOP:
+ if i < uint(len(z.buf)) {
+ // inline z.skipLoopFn(i) and refactor, so cost is within inline budget
+ token = z.buf[i]
+ i++
+ if accept.isset(token) {
+ goto LOOP
+ }
+ z.n += i - 2 - z.c
+ if z.trb {
+ z.doTrack(i)
+ }
+ z.c = i
+ return
+ }
+ return z.skipFill(accept)
+}
+
+func (z *bufioDecReader) skipFill(accept *bitset256) (token byte) {
+ z.n += uint(len(z.buf)) - z.c
+ if z.trb {
+ z.tr = append(z.tr, z.buf[z.c:]...)
+ }
+ var n2 int
+ var err error
+ for {
+ z.c = 0
+ z.buf = z.buf[0:cap(z.buf)]
+ n2, err = z.r.Read(z.buf)
+ if n2 == 0 && err != nil {
+ panic(err)
+ }
+ z.buf = z.buf[:n2]
+ var i int
+ for i, token = range z.buf {
+ if !accept.isset(token) {
+ z.skipLoopFn(uint(i))
+ return
+ }
+ }
+ // for i := 0; i < n2; i++ {
+ // if token = z.buf[i]; !accept.isset(token) {
+ // z.skipLoopFn(i)
+ // return
+ // }
+ // }
+ z.n += uint(n2)
+ if z.trb {
+ z.tr = append(z.tr, z.buf...)
+ }
+ }
+}
+
+func (z *bufioDecReader) readToLoopFn(i uint, out0 []byte) (out []byte) {
+ // out0 is never nil
+ z.n += (i - z.c) - 1
+ out = append(out0, z.buf[z.c:i]...)
+ if z.trb {
+ z.doTrack(i)
+ }
+ z.c = i
+ return
+}
+
+func (z *bufioDecReader) readTo(in []byte, accept *bitset256) (out []byte) {
+ // _, out = z.search(in, accept, 0, 2); return
+
+ // for i := z.c; i < len(z.buf); i++ {
+ // if !accept.isset(z.buf[i]) {
+ // return z.readToLoopFn(i, nil)
+ // }
+ // }
+
+ i := z.c
+LOOP:
+ if i < uint(len(z.buf)) {
+ if !accept.isset(z.buf[i]) {
+ // return z.readToLoopFn(i, nil)
+ // inline readToLoopFn here (for performance)
+ z.n += (i - z.c) - 1
+ out = z.buf[z.c:i]
+ if z.trb {
+ z.doTrack(i)
+ }
+ z.c = i
+ return
+ }
+ i++
+ goto LOOP
+ }
+ return z.readToFill(in, accept)
+}
+
+func (z *bufioDecReader) readToFill(in []byte, accept *bitset256) (out []byte) {
+ z.n += uint(len(z.buf)) - z.c
+ out = append(in, z.buf[z.c:]...)
+ if z.trb {
+ z.tr = append(z.tr, z.buf[z.c:]...)
+ }
+ var n2 int
+ var err error
+ for {
+ z.c = 0
+ z.buf = z.buf[0:cap(z.buf)]
+ n2, err = z.r.Read(z.buf)
+ if n2 == 0 && err != nil {
+ if err == io.EOF {
+ return // readTo should read until it matches or end is reached
+ }
+ panic(err)
+ }
+ z.buf = z.buf[:n2]
+ for i, token := range z.buf {
+ if !accept.isset(token) {
+ return z.readToLoopFn(uint(i), out)
+ }
+ }
+ // for i := 0; i < n2; i++ {
+ // if !accept.isset(z.buf[i]) {
+ // return z.readToLoopFn(i, out)
+ // }
+ // }
+ out = append(out, z.buf...)
+ z.n += uint(n2)
+ if z.trb {
+ z.tr = append(z.tr, z.buf...)
+ }
+ }
+}
+
+func (z *bufioDecReader) readUntilLoopFn(i uint, out0 []byte) (out []byte) {
+ z.n += (i - z.c) - 1
+ i++
+ out = append(out0, z.buf[z.c:i]...)
+ if z.trb {
+ // z.tr = append(z.tr, z.buf[z.c:i]...)
+ z.doTrack(i)
+ }
+ z.c = i
+ return
+}
+
+func (z *bufioDecReader) readUntil(in []byte, stop byte) (out []byte) {
+ // _, out = z.search(in, nil, stop, 4); return
+
+ // for i := z.c; i < len(z.buf); i++ {
+ // if z.buf[i] == stop {
+ // return z.readUntilLoopFn(i, nil)
+ // }
+ // }
+
+ i := z.c
+LOOP:
+ if i < uint(len(z.buf)) {
+ if z.buf[i] == stop {
+ // inline readUntilLoopFn
+ // return z.readUntilLoopFn(i, nil)
+ z.n += (i - z.c) - 1
+ i++
+ out = z.buf[z.c:i]
+ if z.trb {
+ z.doTrack(i)
+ }
+ z.c = i
+ return
+ }
+ i++
+ goto LOOP
+ }
+ return z.readUntilFill(in, stop)
+}
+
+func (z *bufioDecReader) readUntilFill(in []byte, stop byte) (out []byte) {
+ z.n += uint(len(z.buf)) - z.c
+ out = append(in, z.buf[z.c:]...)
+ if z.trb {
+ z.tr = append(z.tr, z.buf[z.c:]...)
+ }
+ var n1 int
+ var n2 uint
+ var err error
+ for {
+ z.c = 0
+ z.buf = z.buf[0:cap(z.buf)]
+ n1, err = z.r.Read(z.buf)
+ n2 = uint(n1)
+ if n2 == 0 && err != nil {
+ panic(err)
+ }
+ z.buf = z.buf[:n2]
+ for i, token := range z.buf {
+ if token == stop {
+ return z.readUntilLoopFn(uint(i), out)
+ }
+ }
+ // for i := 0; i < n2; i++ {
+ // if z.buf[i] == stop {
+ // return z.readUntilLoopFn(i, out)
+ // }
+ // }
+ out = append(out, z.buf...)
+ z.n += n2
+ if z.trb {
+ z.tr = append(z.tr, z.buf...)
+ }
+ }
+}
+
+// ------------------------------------
+
+var errBytesDecReaderCannotUnread = errors.New("cannot unread last byte read")
+
+// bytesDecReader is a decReader that reads off a byte slice with zero copying
+type bytesDecReader struct {
+ b []byte // data
+ c uint // cursor
+ t uint // track start
+ // a int // available
+}
+
+func (z *bytesDecReader) reset(in []byte) {
+ z.b = in
+ // z.a = len(in)
+ z.c = 0
+ z.t = 0
+}
+
+func (z *bytesDecReader) numread() uint {
+ return z.c
+}
+
+func (z *bytesDecReader) unreadn1() {
+ if z.c == 0 || len(z.b) == 0 {
+ panic(errBytesDecReaderCannotUnread)
+ }
+ z.c--
+ // z.a++
+}
+
+func (z *bytesDecReader) readx(n uint) (bs []byte) {
+ // slicing from a non-constant start position is more expensive,
+ // as more computation is required to decipher the pointer start position.
+ // However, we do it only once, and it's better than reslicing both z.b and return value.
+
+ // if n <= 0 {
+ // } else if z.a == 0 {
+ // panic(io.EOF)
+ // } else if n > z.a {
+ // panic(io.ErrUnexpectedEOF)
+ // } else {
+ // c0 := z.c
+ // z.c = c0 + n
+ // z.a = z.a - n
+ // bs = z.b[c0:z.c]
+ // }
+ // return
+
+ if n != 0 {
+ z.c += n
+ if z.c > uint(len(z.b)) {
+ z.c = uint(len(z.b))
+ panic(io.EOF)
+ }
+ bs = z.b[z.c-n : z.c]
+ }
+ return
+
+ // if n == 0 {
+ // } else if z.c+n > uint(len(z.b)) {
+ // z.c = uint(len(z.b))
+ // panic(io.EOF)
+ // } else {
+ // z.c += n
+ // bs = z.b[z.c-n : z.c]
+ // }
+ // return
+
+ // if n == 0 {
+ // return
+ // }
+ // if z.c == uint(len(z.b)) {
+ // panic(io.EOF)
+ // }
+ // if z.c+n > uint(len(z.b)) {
+ // panic(io.ErrUnexpectedEOF)
+ // }
+ // // z.a -= n
+ // z.c += n
+ // return z.b[z.c-n : z.c]
+}
+
+func (z *bytesDecReader) readb(bs []byte) {
+ copy(bs, z.readx(uint(len(bs))))
+}
+
+func (z *bytesDecReader) readn1() (v uint8) {
+ if z.c == uint(len(z.b)) {
+ panic(io.EOF)
+ }
+ v = z.b[z.c]
+ z.c++
+ // z.a--
+ return
+}
+
+// func (z *bytesDecReader) readn1eof() (v uint8, eof bool) {
+// if z.a == 0 {
+// eof = true
+// return
+// }
+// v = z.b[z.c]
+// z.c++
+// z.a--
+// return
+// }
+
+func (z *bytesDecReader) skip(accept *bitset256) (token byte) {
+ i := z.c
+ // if i == len(z.b) {
+ // goto END
+ // // panic(io.EOF)
+ // }
+
+ // Replace loop with goto construct, so that this can be inlined
+ // for i := z.c; i < blen; i++ {
+ // if !accept.isset(z.b[i]) {
+ // token = z.b[i]
+ // i++
+ // z.a -= (i - z.c)
+ // z.c = i
+ // return
+ // }
+ // }
+
+ // i := z.c
+LOOP:
+ if i < uint(len(z.b)) {
+ token = z.b[i]
+ i++
+ if accept.isset(token) {
+ goto LOOP
+ }
+ // z.a -= (i - z.c)
+ z.c = i
+ return
+ }
+ // END:
+ panic(io.EOF)
+ // // z.a = 0
+ // z.c = blen
+ // return
+}
+
+func (z *bytesDecReader) readTo(_ []byte, accept *bitset256) (out []byte) {
+ return z.readToNoInput(accept)
+}
+
+func (z *bytesDecReader) readToNoInput(accept *bitset256) (out []byte) {
+ i := z.c
+ if i == uint(len(z.b)) {
+ panic(io.EOF)
+ }
+
+ // Replace loop with goto construct, so that this can be inlined
+ // for i := z.c; i < blen; i++ {
+ // if !accept.isset(z.b[i]) {
+ // out = z.b[z.c:i]
+ // z.a -= (i - z.c)
+ // z.c = i
+ // return
+ // }
+ // }
+ // out = z.b[z.c:]
+ // z.a, z.c = 0, blen
+ // return
+
+ // i := z.c
+ // LOOP:
+ // if i < blen {
+ // if accept.isset(z.b[i]) {
+ // i++
+ // goto LOOP
+ // }
+ // out = z.b[z.c:i]
+ // z.a -= (i - z.c)
+ // z.c = i
+ // return
+ // }
+ // out = z.b[z.c:]
+ // // z.a, z.c = 0, blen
+ // z.a = 0
+ // z.c = blen
+ // return
+
+ // c := i
+LOOP:
+ if i < uint(len(z.b)) {
+ if accept.isset(z.b[i]) {
+ i++
+ goto LOOP
+ }
+ }
+
+ out = z.b[z.c:i]
+ // z.a -= (i - z.c)
+ z.c = i
+ return // z.b[c:i]
+ // z.c, i = i, z.c
+ // return z.b[i:z.c]
+}
+
+func (z *bytesDecReader) readUntil(_ []byte, stop byte) (out []byte) {
+ return z.readUntilNoInput(stop)
+}
+
+func (z *bytesDecReader) readUntilNoInput(stop byte) (out []byte) {
+ i := z.c
+ // if i == len(z.b) {
+ // panic(io.EOF)
+ // }
+
+ // Replace loop with goto construct, so that this can be inlined
+ // for i := z.c; i < blen; i++ {
+ // if z.b[i] == stop {
+ // i++
+ // out = z.b[z.c:i]
+ // z.a -= (i - z.c)
+ // z.c = i
+ // return
+ // }
+ // }
+LOOP:
+ if i < uint(len(z.b)) {
+ if z.b[i] == stop {
+ i++
+ out = z.b[z.c:i]
+ // z.a -= (i - z.c)
+ z.c = i
+ return
+ }
+ i++
+ goto LOOP
+ }
+ // z.a = 0
+ // z.c = blen
+ panic(io.EOF)
+}
+
+func (z *bytesDecReader) track() {
+ z.t = z.c
+}
+
+func (z *bytesDecReader) stopTrack() (bs []byte) {
+ return z.b[z.t:z.c]
+}
+
+// ----------------------------------------
+
+// func (d *Decoder) builtin(f *codecFnInfo, rv reflect.Value) {
+// d.d.DecodeBuiltin(f.ti.rtid, rv2i(rv))
+// }
+
+func (d *Decoder) rawExt(f *codecFnInfo, rv reflect.Value) {
+ d.d.DecodeExt(rv2i(rv), 0, nil)
+}
+
+func (d *Decoder) ext(f *codecFnInfo, rv reflect.Value) {
+ d.d.DecodeExt(rv2i(rv), f.xfTag, f.xfFn)
+}
+
+func (d *Decoder) selferUnmarshal(f *codecFnInfo, rv reflect.Value) {
+ rv2i(rv).(Selfer).CodecDecodeSelf(d)
+}
+
+func (d *Decoder) binaryUnmarshal(f *codecFnInfo, rv reflect.Value) {
+ bm := rv2i(rv).(encoding.BinaryUnmarshaler)
+ xbs := d.d.DecodeBytes(nil, true)
+ if fnerr := bm.UnmarshalBinary(xbs); fnerr != nil {
+ panic(fnerr)
+ }
+}
+
+func (d *Decoder) textUnmarshal(f *codecFnInfo, rv reflect.Value) {
+ tm := rv2i(rv).(encoding.TextUnmarshaler)
+ fnerr := tm.UnmarshalText(d.d.DecodeStringAsBytes())
+ if fnerr != nil {
+ panic(fnerr)
+ }
+}
+
+func (d *Decoder) jsonUnmarshal(f *codecFnInfo, rv reflect.Value) {
+ tm := rv2i(rv).(jsonUnmarshaler)
+ // bs := d.d.DecodeBytes(d.b[:], true, true)
+ // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself.
+ fnerr := tm.UnmarshalJSON(d.nextValueBytes())
+ if fnerr != nil {
+ panic(fnerr)
+ }
+}
+
+func (d *Decoder) kErr(f *codecFnInfo, rv reflect.Value) {
+ d.errorf("no decoding function defined for kind %v", rv.Kind())
+}
+
+// var kIntfCtr uint64
+
+func (d *Decoder) kInterfaceNaked(f *codecFnInfo) (rvn reflect.Value) {
+ // nil interface:
+ // use some hieristics to decode it appropriately
+ // based on the detected next value in the stream.
+ n := d.naked()
+ d.d.DecodeNaked()
+ if n.v == valueTypeNil {
+ return
+ }
+ // We cannot decode non-nil stream value into nil interface with methods (e.g. io.Reader).
+ if f.ti.numMeth > 0 {
+ d.errorf("cannot decode non-nil codec value into nil %v (%v methods)", f.ti.rt, f.ti.numMeth)
+ return
+ }
+ // var useRvn bool
+ switch n.v {
+ case valueTypeMap:
+ // if json, default to a map type with string keys
+ mtid := d.mtid
+ if mtid == 0 {
+ if d.jsms {
+ mtid = mapStrIntfTypId
+ } else {
+ mtid = mapIntfIntfTypId
+ }
+ }
+ if mtid == mapIntfIntfTypId {
+ var v2 map[interface{}]interface{}
+ d.decode(&v2)
+ rvn = reflect.ValueOf(&v2).Elem()
+ } else if mtid == mapStrIntfTypId { // for json performance
+ var v2 map[string]interface{}
+ d.decode(&v2)
+ rvn = reflect.ValueOf(&v2).Elem()
+ } else {
+ if d.mtr {
+ rvn = reflect.New(d.h.MapType)
+ d.decode(rv2i(rvn))
+ rvn = rvn.Elem()
+ } else {
+ rvn = reflect.New(d.h.MapType).Elem()
+ d.decodeValue(rvn, nil, true)
+ }
+ }
+ case valueTypeArray:
+ if d.stid == 0 || d.stid == intfSliceTypId {
+ var v2 []interface{}
+ d.decode(&v2)
+ rvn = reflect.ValueOf(&v2).Elem()
+ if d.stid == 0 && d.h.PreferArrayOverSlice {
+ rvn2 := reflect.New(reflect.ArrayOf(rvn.Len(), intfTyp)).Elem()
+ reflect.Copy(rvn2, rvn)
+ rvn = rvn2
+ }
+ } else {
+ if d.str {
+ rvn = reflect.New(d.h.SliceType)
+ d.decode(rv2i(rvn))
+ rvn = rvn.Elem()
+ } else {
+ rvn = reflect.New(d.h.SliceType).Elem()
+ d.decodeValue(rvn, nil, true)
+ }
+ }
+ case valueTypeExt:
+ var v interface{}
+ tag, bytes := n.u, n.l // calling decode below might taint the values
+ if bytes == nil {
+ d.decode(&v)
+ }
+ bfn := d.h.getExtForTag(tag)
+ if bfn == nil {
+ var re RawExt
+ re.Tag = tag
+ re.Data = detachZeroCopyBytes(d.bytes, nil, bytes)
+ re.Value = v
+ rvn = reflect.ValueOf(&re).Elem()
+ } else {
+ rvnA := reflect.New(bfn.rt)
+ if bytes != nil {
+ bfn.ext.ReadExt(rv2i(rvnA), bytes)
+ } else {
+ bfn.ext.UpdateExt(rv2i(rvnA), v)
+ }
+ rvn = rvnA.Elem()
+ }
+ case valueTypeNil:
+ // no-op
+ case valueTypeInt:
+ rvn = n.ri()
+ case valueTypeUint:
+ rvn = n.ru()
+ case valueTypeFloat:
+ rvn = n.rf()
+ case valueTypeBool:
+ rvn = n.rb()
+ case valueTypeString, valueTypeSymbol:
+ rvn = n.rs()
+ case valueTypeBytes:
+ rvn = n.rl()
+ case valueTypeTime:
+ rvn = n.rt()
+ default:
+ panicv.errorf("kInterfaceNaked: unexpected valueType: %d", n.v)
+ }
+ return
+}
+
+func (d *Decoder) kInterface(f *codecFnInfo, rv reflect.Value) {
+ // Note:
+ // A consequence of how kInterface works, is that
+ // if an interface already contains something, we try
+ // to decode into what was there before.
+ // We do not replace with a generic value (as got from decodeNaked).
+
+ // every interface passed here MUST be settable.
+ var rvn reflect.Value
+ if rv.IsNil() || d.h.InterfaceReset {
+ // check if mapping to a type: if so, initialize it and move on
+ rvn = d.h.intf2impl(f.ti.rtid)
+ if rvn.IsValid() {
+ rv.Set(rvn)
+ } else {
+ rvn = d.kInterfaceNaked(f)
+ if rvn.IsValid() {
+ rv.Set(rvn)
+ } else if d.h.InterfaceReset {
+ // reset to zero value based on current type in there.
+ rv.Set(reflect.Zero(rv.Elem().Type()))
+ }
+ return
+ }
+ } else {
+ // now we have a non-nil interface value, meaning it contains a type
+ rvn = rv.Elem()
+ }
+ if d.d.TryDecodeAsNil() {
+ rv.Set(reflect.Zero(rvn.Type()))
+ return
+ }
+
+ // Note: interface{} is settable, but underlying type may not be.
+ // Consequently, we MAY have to create a decodable value out of the underlying value,
+ // decode into it, and reset the interface itself.
+ // fmt.Printf(">>>> kInterface: rvn type: %v, rv type: %v\n", rvn.Type(), rv.Type())
+
+ rvn2, canDecode := isDecodeable(rvn)
+ if canDecode {
+ d.decodeValue(rvn2, nil, true)
+ return
+ }
+
+ rvn2 = reflect.New(rvn.Type()).Elem()
+ rvn2.Set(rvn)
+ d.decodeValue(rvn2, nil, true)
+ rv.Set(rvn2)
+}
+
+func decStructFieldKey(dd decDriver, keyType valueType, b *[decScratchByteArrayLen]byte) (rvkencname []byte) {
+ // use if-else-if, not switch (which compiles to binary-search)
+ // since keyType is typically valueTypeString, branch prediction is pretty good.
+
+ if keyType == valueTypeString {
+ rvkencname = dd.DecodeStringAsBytes()
+ } else if keyType == valueTypeInt {
+ rvkencname = strconv.AppendInt(b[:0], dd.DecodeInt64(), 10)
+ } else if keyType == valueTypeUint {
+ rvkencname = strconv.AppendUint(b[:0], dd.DecodeUint64(), 10)
+ } else if keyType == valueTypeFloat {
+ rvkencname = strconv.AppendFloat(b[:0], dd.DecodeFloat64(), 'f', -1, 64)
+ } else {
+ rvkencname = dd.DecodeStringAsBytes()
+ }
+ return rvkencname
+}
+
+func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
+ fti := f.ti
+ dd := d.d
+ elemsep := d.esep
+ sfn := structFieldNode{v: rv, update: true}
+ ctyp := dd.ContainerType()
+ var mf MissingFielder
+ if fti.mf {
+ mf = rv2i(rv).(MissingFielder)
+ } else if fti.mfp {
+ mf = rv2i(rv.Addr()).(MissingFielder)
+ }
+ if ctyp == valueTypeMap {
+ containerLen := dd.ReadMapStart()
+ if containerLen == 0 {
+ dd.ReadMapEnd()
+ return
+ }
+ d.depthIncr()
+ tisfi := fti.sfiSort
+ hasLen := containerLen >= 0
+
+ var rvkencname []byte
+ for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ {
+ if elemsep {
+ dd.ReadMapElemKey()
+ }
+ rvkencname = decStructFieldKey(dd, fti.keyType, &d.b)
+ if elemsep {
+ dd.ReadMapElemValue()
+ }
+ if k := fti.indexForEncName(rvkencname); k > -1 {
+ si := tisfi[k]
+ if dd.TryDecodeAsNil() {
+ si.setToZeroValue(rv)
+ } else {
+ d.decodeValue(sfn.field(si), nil, true)
+ }
+ } else if mf != nil {
+ // store rvkencname in new []byte, as it previously shares Decoder.b, which is used in decode
+ name2 := rvkencname
+ rvkencname = make([]byte, len(rvkencname))
+ copy(rvkencname, name2)
+
+ var f interface{}
+ // xdebugf("kStruct: mf != nil: before decode: rvkencname: %s", rvkencname)
+ d.decode(&f)
+ // xdebugf("kStruct: mf != nil: after decode: rvkencname: %s", rvkencname)
+ if !mf.CodecMissingField(rvkencname, f) && d.h.ErrorIfNoField {
+ d.errorf("no matching struct field found when decoding stream map with key: %s ",
+ stringView(rvkencname))
+ }
+ } else {
+ d.structFieldNotFound(-1, stringView(rvkencname))
+ }
+ // keepAlive4StringView(rvkencnameB) // not needed, as reference is outside loop
+ }
+ dd.ReadMapEnd()
+ d.depthDecr()
+ } else if ctyp == valueTypeArray {
+ containerLen := dd.ReadArrayStart()
+ if containerLen == 0 {
+ dd.ReadArrayEnd()
+ return
+ }
+ d.depthIncr()
+ // Not much gain from doing it two ways for array.
+ // Arrays are not used as much for structs.
+ hasLen := containerLen >= 0
+ var checkbreak bool
+ for j, si := range fti.sfiSrc {
+ if hasLen && j == containerLen {
+ break
+ }
+ if !hasLen && dd.CheckBreak() {
+ checkbreak = true
+ break
+ }
+ if elemsep {
+ dd.ReadArrayElem()
+ }
+ if dd.TryDecodeAsNil() {
+ si.setToZeroValue(rv)
+ } else {
+ d.decodeValue(sfn.field(si), nil, true)
+ }
+ }
+ if (hasLen && containerLen > len(fti.sfiSrc)) || (!hasLen && !checkbreak) {
+ // read remaining values and throw away
+ for j := len(fti.sfiSrc); ; j++ {
+ if (hasLen && j == containerLen) || (!hasLen && dd.CheckBreak()) {
+ break
+ }
+ if elemsep {
+ dd.ReadArrayElem()
+ }
+ d.structFieldNotFound(j, "")
+ }
+ }
+ dd.ReadArrayEnd()
+ d.depthDecr()
+ } else {
+ d.errorstr(errstrOnlyMapOrArrayCanDecodeIntoStruct)
+ return
+ }
+}
+
+func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
+ // A slice can be set from a map or array in stream.
+ // This way, the order can be kept (as order is lost with map).
+ ti := f.ti
+ if f.seq == seqTypeChan && ti.chandir&uint8(reflect.SendDir) == 0 {
+ d.errorf("receive-only channel cannot be decoded")
+ }
+ dd := d.d
+ rtelem0 := ti.elem
+ ctyp := dd.ContainerType()
+ if ctyp == valueTypeBytes || ctyp == valueTypeString {
+ // you can only decode bytes or string in the stream into a slice or array of bytes
+ if !(ti.rtid == uint8SliceTypId || rtelem0.Kind() == reflect.Uint8) {
+ d.errorf("bytes/string in stream must decode into slice/array of bytes, not %v", ti.rt)
+ }
+ if f.seq == seqTypeChan {
+ bs2 := dd.DecodeBytes(nil, true)
+ irv := rv2i(rv)
+ ch, ok := irv.(chan<- byte)
+ if !ok {
+ ch = irv.(chan byte)
+ }
+ for _, b := range bs2 {
+ ch <- b
+ }
+ } else {
+ rvbs := rv.Bytes()
+ bs2 := dd.DecodeBytes(rvbs, false)
+ // if rvbs == nil && bs2 != nil || rvbs != nil && bs2 == nil || len(bs2) != len(rvbs) {
+ if !(len(bs2) > 0 && len(bs2) == len(rvbs) && &bs2[0] == &rvbs[0]) {
+ if rv.CanSet() {
+ rv.SetBytes(bs2)
+ } else if len(rvbs) > 0 && len(bs2) > 0 {
+ copy(rvbs, bs2)
+ }
+ }
+ }
+ return
+ }
+
+ // array := f.seq == seqTypeChan
+
+ slh, containerLenS := d.decSliceHelperStart() // only expects valueType(Array|Map)
+
+ // an array can never return a nil slice. so no need to check f.array here.
+ if containerLenS == 0 {
+ if rv.CanSet() {
+ if f.seq == seqTypeSlice {
+ if rv.IsNil() {
+ rv.Set(reflect.MakeSlice(ti.rt, 0, 0))
+ } else {
+ rv.SetLen(0)
+ }
+ } else if f.seq == seqTypeChan {
+ if rv.IsNil() {
+ rv.Set(reflect.MakeChan(ti.rt, 0))
+ }
+ }
+ }
+ slh.End()
+ return
+ }
+
+ d.depthIncr()
+
+ rtelem0Size := int(rtelem0.Size())
+ rtElem0Kind := rtelem0.Kind()
+ rtelem0Mut := !isImmutableKind(rtElem0Kind)
+ rtelem := rtelem0
+ rtelemkind := rtelem.Kind()
+ for rtelemkind == reflect.Ptr {
+ rtelem = rtelem.Elem()
+ rtelemkind = rtelem.Kind()
+ }
+
+ var fn *codecFn
+
+ var rvCanset = rv.CanSet()
+ var rvChanged bool
+ var rv0 = rv
+ var rv9 reflect.Value
+
+ rvlen := rv.Len()
+ rvcap := rv.Cap()
+ hasLen := containerLenS > 0
+ if hasLen && f.seq == seqTypeSlice {
+ if containerLenS > rvcap {
+ oldRvlenGtZero := rvlen > 0
+ rvlen = decInferLen(containerLenS, d.h.MaxInitLen, int(rtelem0.Size()))
+ if rvlen <= rvcap {
+ if rvCanset {
+ rv.SetLen(rvlen)
+ }
+ } else if rvCanset {
+ rv = reflect.MakeSlice(ti.rt, rvlen, rvlen)
+ rvcap = rvlen
+ rvChanged = true
+ } else {
+ d.errorf("cannot decode into non-settable slice")
+ }
+ if rvChanged && oldRvlenGtZero && !isImmutableKind(rtelem0.Kind()) {
+ reflect.Copy(rv, rv0) // only copy up to length NOT cap i.e. rv0.Slice(0, rvcap)
+ }
+ } else if containerLenS != rvlen {
+ rvlen = containerLenS
+ if rvCanset {
+ rv.SetLen(rvlen)
+ }
+ // else {
+ // rv = rv.Slice(0, rvlen)
+ // rvChanged = true
+ // d.errorf("cannot decode into non-settable slice")
+ // }
+ }
+ }
+
+ // consider creating new element once, and just decoding into it.
+ var rtelem0Zero reflect.Value
+ var rtelem0ZeroValid bool
+ var decodeAsNil bool
+ var j int
+
+ for ; (hasLen && j < containerLenS) || !(hasLen || dd.CheckBreak()); j++ {
+ if j == 0 && (f.seq == seqTypeSlice || f.seq == seqTypeChan) && rv.IsNil() {
+ if hasLen {
+ rvlen = decInferLen(containerLenS, d.h.MaxInitLen, rtelem0Size)
+ } else if f.seq == seqTypeSlice {
+ rvlen = decDefSliceCap
+ } else {
+ rvlen = decDefChanCap
+ }
+ if rvCanset {
+ if f.seq == seqTypeSlice {
+ rv = reflect.MakeSlice(ti.rt, rvlen, rvlen)
+ rvChanged = true
+ } else { // chan
+ rv = reflect.MakeChan(ti.rt, rvlen)
+ rvChanged = true
+ }
+ } else {
+ d.errorf("cannot decode into non-settable slice")
+ }
+ }
+ slh.ElemContainerState(j)
+ decodeAsNil = dd.TryDecodeAsNil()
+ if f.seq == seqTypeChan {
+ if decodeAsNil {
+ rv.Send(reflect.Zero(rtelem0))
+ continue
+ }
+ if rtelem0Mut || !rv9.IsValid() { // || (rtElem0Kind == reflect.Ptr && rv9.IsNil()) {
+ rv9 = reflect.New(rtelem0).Elem()
+ }
+ if fn == nil {
+ fn = d.h.fn(rtelem, true, true)
+ }
+ d.decodeValue(rv9, fn, true)
+ rv.Send(rv9)
+ } else {
+ // if indefinite, etc, then expand the slice if necessary
+ var decodeIntoBlank bool
+ if j >= rvlen {
+ if f.seq == seqTypeArray {
+ d.arrayCannotExpand(rvlen, j+1)
+ decodeIntoBlank = true
+ } else { // if f.seq == seqTypeSlice
+ // rv = reflect.Append(rv, reflect.Zero(rtelem0)) // append logic + varargs
+ var rvcap2 int
+ var rvErrmsg2 string
+ rv9, rvcap2, rvChanged, rvErrmsg2 =
+ expandSliceRV(rv, ti.rt, rvCanset, rtelem0Size, 1, rvlen, rvcap)
+ if rvErrmsg2 != "" {
+ d.errorf("%s", rvErrmsg2)
+ }
+ rvlen++
+ if rvChanged {
+ rv = rv9
+ rvcap = rvcap2
+ }
+ }
+ }
+ if decodeIntoBlank {
+ if !decodeAsNil {
+ d.swallow()
+ }
+ } else {
+ rv9 = rv.Index(j)
+ if d.h.SliceElementReset || decodeAsNil {
+ if !rtelem0ZeroValid {
+ rtelem0ZeroValid = true
+ rtelem0Zero = reflect.Zero(rtelem0)
+ }
+ rv9.Set(rtelem0Zero)
+ if decodeAsNil {
+ continue
+ }
+ }
+
+ if fn == nil {
+ fn = d.h.fn(rtelem, true, true)
+ }
+ d.decodeValue(rv9, fn, true)
+ }
+ }
+ }
+ if f.seq == seqTypeSlice {
+ if j < rvlen {
+ if rv.CanSet() {
+ rv.SetLen(j)
+ } else if rvCanset {
+ rv = rv.Slice(0, j)
+ rvChanged = true
+ } // else { d.errorf("kSlice: cannot change non-settable slice") }
+ rvlen = j
+ } else if j == 0 && rv.IsNil() {
+ if rvCanset {
+ rv = reflect.MakeSlice(ti.rt, 0, 0)
+ rvChanged = true
+ } // else { d.errorf("kSlice: cannot change non-settable slice") }
+ }
+ }
+ slh.End()
+
+ if rvChanged { // infers rvCanset=true, so it can be reset
+ rv0.Set(rv)
+ }
+
+ d.depthDecr()
+}
+
+// func (d *Decoder) kArray(f *codecFnInfo, rv reflect.Value) {
+// // d.decodeValueFn(rv.Slice(0, rv.Len()))
+// f.kSlice(rv.Slice(0, rv.Len()))
+// }
+
+func (d *Decoder) kMap(f *codecFnInfo, rv reflect.Value) {
+ dd := d.d
+ containerLen := dd.ReadMapStart()
+ elemsep := d.esep
+ ti := f.ti
+ if rv.IsNil() {
+ rvlen := decInferLen(containerLen, d.h.MaxInitLen, int(ti.key.Size()+ti.elem.Size()))
+ rv.Set(makeMapReflect(ti.rt, rvlen))
+ }
+
+ if containerLen == 0 {
+ dd.ReadMapEnd()
+ return
+ }
+
+ d.depthIncr()
+
+ ktype, vtype := ti.key, ti.elem
+ ktypeId := rt2id(ktype)
+ vtypeKind := vtype.Kind()
+
+ var keyFn, valFn *codecFn
+ var ktypeLo, vtypeLo reflect.Type
+
+ for ktypeLo = ktype; ktypeLo.Kind() == reflect.Ptr; ktypeLo = ktypeLo.Elem() {
+ }
+
+ for vtypeLo = vtype; vtypeLo.Kind() == reflect.Ptr; vtypeLo = vtypeLo.Elem() {
+ }
+
+ var mapGet, mapSet bool
+ rvvImmut := isImmutableKind(vtypeKind)
+ if !d.h.MapValueReset {
+ // if pointer, mapGet = true
+ // if interface, mapGet = true if !DecodeNakedAlways (else false)
+ // if builtin, mapGet = false
+ // else mapGet = true
+ if vtypeKind == reflect.Ptr {
+ mapGet = true
+ } else if vtypeKind == reflect.Interface {
+ if !d.h.InterfaceReset {
+ mapGet = true
+ }
+ } else if !rvvImmut {
+ mapGet = true
+ }
+ }
+
+ var rvk, rvkp, rvv, rvz reflect.Value
+ rvkMut := !isImmutableKind(ktype.Kind()) // if ktype is immutable, then re-use the same rvk.
+ ktypeIsString := ktypeId == stringTypId
+ ktypeIsIntf := ktypeId == intfTypId
+ hasLen := containerLen > 0
+ var kstrbs []byte
+
+ for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ {
+ if rvkMut || !rvkp.IsValid() {
+ rvkp = reflect.New(ktype)
+ rvk = rvkp.Elem()
+ }
+ if elemsep {
+ dd.ReadMapElemKey()
+ }
+ // if false && dd.TryDecodeAsNil() { // nil cannot be a map key, so disregard this block
+ // // Previously, if a nil key, we just ignored the mapped value and continued.
+ // // However, that makes the result of encoding and then decoding map[intf]intf{nil:nil}
+ // // to be an empty map.
+ // // Instead, we treat a nil key as the zero value of the type.
+ // rvk.Set(reflect.Zero(ktype))
+ // } else if ktypeIsString {
+ if ktypeIsString {
+ kstrbs = dd.DecodeStringAsBytes()
+ rvk.SetString(stringView(kstrbs))
+ // NOTE: if doing an insert, you MUST use a real string (not stringview)
+ } else {
+ if keyFn == nil {
+ keyFn = d.h.fn(ktypeLo, true, true)
+ }
+ d.decodeValue(rvk, keyFn, true)
+ }
+ // special case if a byte array.
+ if ktypeIsIntf {
+ if rvk2 := rvk.Elem(); rvk2.IsValid() {
+ if rvk2.Type() == uint8SliceTyp {
+ rvk = reflect.ValueOf(d.string(rvk2.Bytes()))
+ } else {
+ rvk = rvk2
+ }
+ }
+ }
+
+ if elemsep {
+ dd.ReadMapElemValue()
+ }
+
+ // Brittle, but OK per TryDecodeAsNil() contract.
+ // i.e. TryDecodeAsNil never shares slices with other decDriver procedures
+ if dd.TryDecodeAsNil() {
+ if ktypeIsString {
+ rvk.SetString(d.string(kstrbs))
+ }
+ if d.h.DeleteOnNilMapValue {
+ rv.SetMapIndex(rvk, reflect.Value{})
+ } else {
+ rv.SetMapIndex(rvk, reflect.Zero(vtype))
+ }
+ continue
+ }
+
+ mapSet = true // set to false if u do a get, and its a non-nil pointer
+ if mapGet {
+ // mapGet true only in case where kind=Ptr|Interface or kind is otherwise mutable.
+ rvv = rv.MapIndex(rvk)
+ if !rvv.IsValid() {
+ rvv = reflect.New(vtype).Elem()
+ } else if vtypeKind == reflect.Ptr {
+ if rvv.IsNil() {
+ rvv = reflect.New(vtype).Elem()
+ } else {
+ mapSet = false
+ }
+ } else if vtypeKind == reflect.Interface {
+ // not addressable, and thus not settable.
+ // e MUST create a settable/addressable variant
+ rvv2 := reflect.New(rvv.Type()).Elem()
+ if !rvv.IsNil() {
+ rvv2.Set(rvv)
+ }
+ rvv = rvv2
+ }
+ // else it is ~mutable, and we can just decode into it directly
+ } else if rvvImmut {
+ if !rvz.IsValid() {
+ rvz = reflect.New(vtype).Elem()
+ }
+ rvv = rvz
+ } else {
+ rvv = reflect.New(vtype).Elem()
+ }
+
+ // We MUST be done with the stringview of the key, before decoding the value
+ // so that we don't bastardize the reused byte array.
+ if mapSet && ktypeIsString {
+ rvk.SetString(d.string(kstrbs))
+ }
+ if valFn == nil {
+ valFn = d.h.fn(vtypeLo, true, true)
+ }
+ d.decodeValue(rvv, valFn, true)
+ // d.decodeValueFn(rvv, valFn)
+ if mapSet {
+ rv.SetMapIndex(rvk, rvv)
+ }
+ // if ktypeIsString {
+ // // keepAlive4StringView(kstrbs) // not needed, as reference is outside loop
+ // }
+ }
+
+ dd.ReadMapEnd()
+
+ d.depthDecr()
+}
+
+// decNaked is used to keep track of the primitives decoded.
+// Without it, we would have to decode each primitive and wrap it
+// in an interface{}, causing an allocation.
+// In this model, the primitives are decoded in a "pseudo-atomic" fashion,
+// so we can rest assured that no other decoding happens while these
+// primitives are being decoded.
+//
+// maps and arrays are not handled by this mechanism.
+// However, RawExt is, and we accommodate for extensions that decode
+// RawExt from DecodeNaked, but need to decode the value subsequently.
+// kInterfaceNaked and swallow, which call DecodeNaked, handle this caveat.
+//
+// However, decNaked also keeps some arrays of default maps and slices
+// used in DecodeNaked. This way, we can get a pointer to it
+// without causing a new heap allocation.
+//
+// kInterfaceNaked will ensure that there is no allocation for the common
+// uses.
+
+type decNaked struct {
+ // r RawExt // used for RawExt, uint, []byte.
+
+ // primitives below
+ u uint64
+ i int64
+ f float64
+ l []byte
+ s string
+
+ // ---- cpu cache line boundary?
+ t time.Time
+ b bool
+
+ // state
+ v valueType
+ _ [6]bool // padding
+
+ // ru, ri, rf, rl, rs, rb, rt reflect.Value // mapping to the primitives above
+ //
+ // _ [3]uint64 // padding
+}
+
+// func (n *decNaked) init() {
+// n.ru = reflect.ValueOf(&n.u).Elem()
+// n.ri = reflect.ValueOf(&n.i).Elem()
+// n.rf = reflect.ValueOf(&n.f).Elem()
+// n.rl = reflect.ValueOf(&n.l).Elem()
+// n.rs = reflect.ValueOf(&n.s).Elem()
+// n.rt = reflect.ValueOf(&n.t).Elem()
+// n.rb = reflect.ValueOf(&n.b).Elem()
+// // n.rr[] = reflect.ValueOf(&n.)
+// }
+
+// type decNakedPooler struct {
+// n *decNaked
+// nsp *sync.Pool
+// }
+
+// // naked must be called before each call to .DecodeNaked, as they will use it.
+// func (d *decNakedPooler) naked() *decNaked {
+// if d.n == nil {
+// // consider one of:
+// // - get from sync.Pool (if GC is frequent, there's no value here)
+// // - new alloc (safest. only init'ed if it a naked decode will be done)
+// // - field in Decoder (makes the Decoder struct very big)
+// // To support using a decoder where a DecodeNaked is not needed,
+// // we prefer #1 or #2.
+// // d.n = new(decNaked) // &d.nv // new(decNaked) // grab from a sync.Pool
+// // d.n.init()
+// var v interface{}
+// d.nsp, v = pool.decNaked()
+// d.n = v.(*decNaked)
+// }
+// return d.n
+// }
+
+// func (d *decNakedPooler) end() {
+// if d.n != nil {
+// // if n != nil, then nsp != nil (they are always set together)
+// d.nsp.Put(d.n)
+// d.n, d.nsp = nil, nil
+// }
+// }
+
+// type rtid2rv struct {
+// rtid uintptr
+// rv reflect.Value
+// }
+
+// --------------
+
+type decReaderSwitch struct {
+ rb bytesDecReader
+ // ---- cpu cache line boundary?
+ ri *ioDecReader
+ bi *bufioDecReader
+
+ mtr, str bool // whether maptype or slicetype are known types
+
+ be bool // is binary encoding
+ js bool // is json handle
+ jsms bool // is json handle, and MapKeyAsString
+ esep bool // has elem separators
+
+ // typ entryType
+ bytes bool // is bytes reader
+ bufio bool // is this a bufioDecReader?
+}
+
+// numread, track and stopTrack are always inlined, as they just check int fields, etc.
+
+/*
+func (z *decReaderSwitch) numread() int {
+ switch z.typ {
+ case entryTypeBytes:
+ return z.rb.numread()
+ case entryTypeIo:
+ return z.ri.numread()
+ default:
+ return z.bi.numread()
+ }
+}
+func (z *decReaderSwitch) track() {
+ switch z.typ {
+ case entryTypeBytes:
+ z.rb.track()
+ case entryTypeIo:
+ z.ri.track()
+ default:
+ z.bi.track()
+ }
+}
+func (z *decReaderSwitch) stopTrack() []byte {
+ switch z.typ {
+ case entryTypeBytes:
+ return z.rb.stopTrack()
+ case entryTypeIo:
+ return z.ri.stopTrack()
+ default:
+ return z.bi.stopTrack()
+ }
+}
+
+func (z *decReaderSwitch) unreadn1() {
+ switch z.typ {
+ case entryTypeBytes:
+ z.rb.unreadn1()
+ case entryTypeIo:
+ z.ri.unreadn1()
+ default:
+ z.bi.unreadn1()
+ }
+}
+func (z *decReaderSwitch) readx(n int) []byte {
+ switch z.typ {
+ case entryTypeBytes:
+ return z.rb.readx(n)
+ case entryTypeIo:
+ return z.ri.readx(n)
+ default:
+ return z.bi.readx(n)
+ }
+}
+func (z *decReaderSwitch) readb(s []byte) {
+ switch z.typ {
+ case entryTypeBytes:
+ z.rb.readb(s)
+ case entryTypeIo:
+ z.ri.readb(s)
+ default:
+ z.bi.readb(s)
+ }
+}
+func (z *decReaderSwitch) readn1() uint8 {
+ switch z.typ {
+ case entryTypeBytes:
+ return z.rb.readn1()
+ case entryTypeIo:
+ return z.ri.readn1()
+ default:
+ return z.bi.readn1()
+ }
+}
+func (z *decReaderSwitch) skip(accept *bitset256) (token byte) {
+ switch z.typ {
+ case entryTypeBytes:
+ return z.rb.skip(accept)
+ case entryTypeIo:
+ return z.ri.skip(accept)
+ default:
+ return z.bi.skip(accept)
+ }
+}
+func (z *decReaderSwitch) readTo(in []byte, accept *bitset256) (out []byte) {
+ switch z.typ {
+ case entryTypeBytes:
+ return z.rb.readTo(in, accept)
+ case entryTypeIo:
+ return z.ri.readTo(in, accept)
+ default:
+ return z.bi.readTo(in, accept)
+ }
+}
+func (z *decReaderSwitch) readUntil(in []byte, stop byte) (out []byte) {
+ switch z.typ {
+ case entryTypeBytes:
+ return z.rb.readUntil(in, stop)
+ case entryTypeIo:
+ return z.ri.readUntil(in, stop)
+ default:
+ return z.bi.readUntil(in, stop)
+ }
+}
+
+*/
+
+// the if/else-if/else block is expensive to inline.
+// Each node of this construct costs a lot and dominates the budget.
+// Best to only do an if fast-path else block (so fast-path is inlined).
+// This is irrespective of inlineExtraCallCost set in $GOROOT/src/cmd/compile/internal/gc/inl.go
+//
+// In decReaderSwitch methods below, we delegate all IO functions into their own methods.
+// This allows for the inlining of the common path when z.bytes=true.
+// Go 1.12+ supports inlining methods with up to 1 inlined function (or 2 if no other constructs).
+
+func (z *decReaderSwitch) numread() uint {
+ if z.bytes {
+ return z.rb.numread()
+ } else if z.bufio {
+ return z.bi.numread()
+ } else {
+ return z.ri.numread()
+ }
+}
+func (z *decReaderSwitch) track() {
+ if z.bytes {
+ z.rb.track()
+ } else if z.bufio {
+ z.bi.track()
+ } else {
+ z.ri.track()
+ }
+}
+func (z *decReaderSwitch) stopTrack() []byte {
+ if z.bytes {
+ return z.rb.stopTrack()
+ } else if z.bufio {
+ return z.bi.stopTrack()
+ } else {
+ return z.ri.stopTrack()
+ }
+}
+
+// func (z *decReaderSwitch) unreadn1() {
+// if z.bytes {
+// z.rb.unreadn1()
+// } else {
+// z.unreadn1IO()
+// }
+// }
+// func (z *decReaderSwitch) unreadn1IO() {
+// if z.bufio {
+// z.bi.unreadn1()
+// } else {
+// z.ri.unreadn1()
+// }
+// }
+
+func (z *decReaderSwitch) unreadn1() {
+ if z.bytes {
+ z.rb.unreadn1()
+ } else if z.bufio {
+ z.bi.unreadn1()
+ } else {
+ z.ri.unreadn1() // not inlined
+ }
+}
+
+func (z *decReaderSwitch) readx(n uint) []byte {
+ if z.bytes {
+ return z.rb.readx(n)
+ }
+ return z.readxIO(n)
+}
+func (z *decReaderSwitch) readxIO(n uint) []byte {
+ if z.bufio {
+ return z.bi.readx(n)
+ }
+ return z.ri.readx(n)
+}
+
+func (z *decReaderSwitch) readb(s []byte) {
+ if z.bytes {
+ z.rb.readb(s)
+ } else {
+ z.readbIO(s)
+ }
+}
+
+//go:noinline - fallback for io, ensures z.bytes path is inlined
+func (z *decReaderSwitch) readbIO(s []byte) {
+ if z.bufio {
+ z.bi.readb(s)
+ } else {
+ z.ri.readb(s)
+ }
+}
+
+func (z *decReaderSwitch) readn1() uint8 {
+ if z.bytes {
+ return z.rb.readn1()
+ }
+ return z.readn1IO()
+}
+func (z *decReaderSwitch) readn1IO() uint8 {
+ if z.bufio {
+ return z.bi.readn1()
+ }
+ return z.ri.readn1()
+}
+
+func (z *decReaderSwitch) skip(accept *bitset256) (token byte) {
+ if z.bytes {
+ return z.rb.skip(accept)
+ }
+ return z.skipIO(accept)
+}
+func (z *decReaderSwitch) skipIO(accept *bitset256) (token byte) {
+ if z.bufio {
+ return z.bi.skip(accept)
+ }
+ return z.ri.skip(accept)
+}
+
+func (z *decReaderSwitch) readTo(in []byte, accept *bitset256) (out []byte) {
+ if z.bytes {
+ return z.rb.readToNoInput(accept) // z.rb.readTo(in, accept)
+ }
+ return z.readToIO(in, accept)
+}
+
+//go:noinline - fallback for io, ensures z.bytes path is inlined
+func (z *decReaderSwitch) readToIO(in []byte, accept *bitset256) (out []byte) {
+ if z.bufio {
+ return z.bi.readTo(in, accept)
+ }
+ return z.ri.readTo(in, accept)
+}
+func (z *decReaderSwitch) readUntil(in []byte, stop byte) (out []byte) {
+ if z.bytes {
+ return z.rb.readUntilNoInput(stop)
+ }
+ return z.readUntilIO(in, stop)
+}
+
+func (z *decReaderSwitch) readUntilIO(in []byte, stop byte) (out []byte) {
+ if z.bufio {
+ return z.bi.readUntil(in, stop)
+ }
+ return z.ri.readUntil(in, stop)
+}
+
+// Decoder reads and decodes an object from an input stream in a supported format.
+//
+// Decoder is NOT safe for concurrent use i.e. a Decoder cannot be used
+// concurrently in multiple goroutines.
+//
+// However, as Decoder could be allocation heavy to initialize, a Reset method is provided
+// so its state can be reused to decode new input streams repeatedly.
+// This is the idiomatic way to use.
+type Decoder struct {
+ panicHdl
+ // hopefully, reduce derefencing cost by laying the decReader inside the Decoder.
+ // Try to put things that go together to fit within a cache line (8 words).
+
+ d decDriver
+
+ // NOTE: Decoder shouldn't call it's read methods,
+ // as the handler MAY need to do some coordination.
+ r *decReaderSwitch
+
+ // bi *bufioDecReader
+ // cache the mapTypeId and sliceTypeId for faster comparisons
+ mtid uintptr
+ stid uintptr
+
+ hh Handle
+ h *BasicHandle
+
+ // ---- cpu cache line boundary?
+ decReaderSwitch
+
+ // ---- cpu cache line boundary?
+ n decNaked
+
+ // cr containerStateRecv
+ err error
+
+ depth int16
+ maxdepth int16
+
+ _ [4]uint8 // padding
+
+ is map[string]string // used for interning strings
+
+ // ---- cpu cache line boundary?
+ b [decScratchByteArrayLen]byte // scratch buffer, used by Decoder and xxxEncDrivers
+
+ // padding - false sharing help // modify 232 if Decoder struct changes.
+ // _ [cacheLineSize - 232%cacheLineSize]byte
+}
+
+// NewDecoder returns a Decoder for decoding a stream of bytes from an io.Reader.
+//
+// For efficiency, Users are encouraged to configure ReaderBufferSize on the handle
+// OR pass in a memory buffered reader (eg bufio.Reader, bytes.Buffer).
+func NewDecoder(r io.Reader, h Handle) *Decoder {
+ d := newDecoder(h)
+ d.Reset(r)
+ return d
+}
+
+// NewDecoderBytes returns a Decoder which efficiently decodes directly
+// from a byte slice with zero copying.
+func NewDecoderBytes(in []byte, h Handle) *Decoder {
+ d := newDecoder(h)
+ d.ResetBytes(in)
+ return d
+}
+
+// var defaultDecNaked decNaked
+
+func newDecoder(h Handle) *Decoder {
+ d := &Decoder{h: basicHandle(h), err: errDecoderNotInitialized}
+ d.bytes = true
+ if useFinalizers {
+ runtime.SetFinalizer(d, (*Decoder).finalize)
+ // xdebugf(">>>> new(Decoder) with finalizer")
+ }
+ d.r = &d.decReaderSwitch
+ d.hh = h
+ d.be = h.isBinary()
+ // NOTE: do not initialize d.n here. It is lazily initialized in d.naked()
+ var jh *JsonHandle
+ jh, d.js = h.(*JsonHandle)
+ if d.js {
+ d.jsms = jh.MapKeyAsString
+ }
+ d.esep = d.hh.hasElemSeparators()
+ if d.h.InternString {
+ d.is = make(map[string]string, 32)
+ }
+ d.d = h.newDecDriver(d)
+ // d.cr, _ = d.d.(containerStateRecv)
+ return d
+}
+
+func (d *Decoder) resetCommon() {
+ // d.r = &d.decReaderSwitch
+ d.d.reset()
+ d.err = nil
+ d.depth = 0
+ d.maxdepth = d.h.MaxDepth
+ if d.maxdepth <= 0 {
+ d.maxdepth = decDefMaxDepth
+ }
+ // reset all things which were cached from the Handle, but could change
+ d.mtid, d.stid = 0, 0
+ d.mtr, d.str = false, false
+ if d.h.MapType != nil {
+ d.mtid = rt2id(d.h.MapType)
+ d.mtr = fastpathAV.index(d.mtid) != -1
+ }
+ if d.h.SliceType != nil {
+ d.stid = rt2id(d.h.SliceType)
+ d.str = fastpathAV.index(d.stid) != -1
+ }
+}
+
+// Reset the Decoder with a new Reader to decode from,
+// clearing all state from last run(s).
+func (d *Decoder) Reset(r io.Reader) {
+ if r == nil {
+ return
+ }
+ d.bytes = false
+ // d.typ = entryTypeUnset
+ if d.h.ReaderBufferSize > 0 {
+ if d.bi == nil {
+ d.bi = new(bufioDecReader)
+ }
+ d.bi.reset(r, d.h.ReaderBufferSize)
+ // d.r = d.bi
+ // d.typ = entryTypeBufio
+ d.bufio = true
+ } else {
+ // d.ri.x = &d.b
+ // d.s = d.sa[:0]
+ if d.ri == nil {
+ d.ri = new(ioDecReader)
+ }
+ d.ri.reset(r)
+ // d.r = d.ri
+ // d.typ = entryTypeIo
+ d.bufio = false
+ }
+ d.resetCommon()
+}
+
+// ResetBytes resets the Decoder with a new []byte to decode from,
+// clearing all state from last run(s).
+func (d *Decoder) ResetBytes(in []byte) {
+ if in == nil {
+ return
+ }
+ d.bytes = true
+ d.bufio = false
+ // d.typ = entryTypeBytes
+ d.rb.reset(in)
+ // d.r = &d.rb
+ d.resetCommon()
+}
+
+func (d *Decoder) naked() *decNaked {
+ return &d.n
+}
+
+// Decode decodes the stream from reader and stores the result in the
+// value pointed to by v. v cannot be a nil pointer. v can also be
+// a reflect.Value of a pointer.
+//
+// Note that a pointer to a nil interface is not a nil pointer.
+// If you do not know what type of stream it is, pass in a pointer to a nil interface.
+// We will decode and store a value in that nil interface.
+//
+// Sample usages:
+//
+// // Decoding into a non-nil typed value
+// var f float32
+// err = codec.NewDecoder(r, handle).Decode(&f)
+//
+// // Decoding into nil interface
+// var v interface{}
+// dec := codec.NewDecoder(r, handle)
+// err = dec.Decode(&v)
+//
+// When decoding into a nil interface{}, we will decode into an appropriate value based
+// on the contents of the stream:
+// - Numbers are decoded as float64, int64 or uint64.
+// - Other values are decoded appropriately depending on the type:
+// bool, string, []byte, time.Time, etc
+// - Extensions are decoded as RawExt (if no ext function registered for the tag)
+//
+// Configurations exist on the Handle to override defaults
+// (e.g. for MapType, SliceType and how to decode raw bytes).
+//
+// When decoding into a non-nil interface{} value, the mode of encoding is based on the
+// type of the value. When a value is seen:
+// - If an extension is registered for it, call that extension function
+// - If it implements BinaryUnmarshaler, call its UnmarshalBinary(data []byte) error
+// - Else decode it based on its reflect.Kind
+//
+// There are some special rules when decoding into containers (slice/array/map/struct).
+// Decode will typically use the stream contents to UPDATE the container i.e. the values
+// in these containers will not be zero'ed before decoding.
+// - A map can be decoded from a stream map, by updating matching keys.
+// - A slice can be decoded from a stream array,
+// by updating the first n elements, where n is length of the stream.
+// - A slice can be decoded from a stream map, by decoding as if
+// it contains a sequence of key-value pairs.
+// - A struct can be decoded from a stream map, by updating matching fields.
+// - A struct can be decoded from a stream array,
+// by updating fields as they occur in the struct (by index).
+//
+// This in-place update maintains consistency in the decoding philosophy (i.e. we ALWAYS update
+// in place by default). However, the consequence of this is that values in slices or maps
+// which are not zero'ed before hand, will have part of the prior values in place after decode
+// if the stream doesn't contain an update for those parts.
+//
+// This in-place update can be disabled by configuring the MapValueReset and SliceElementReset
+// decode options available on every handle.
+//
+// Furthermore, when decoding a stream map or array with length of 0 into a nil map or slice,
+// we reset the destination map or slice to a zero-length value.
+//
+// However, when decoding a stream nil, we reset the destination container
+// to its "zero" value (e.g. nil for slice/map, etc).
+//
+// Note: we allow nil values in the stream anywhere except for map keys.
+// A nil value in the encoded stream where a map key is expected is treated as an error.
+func (d *Decoder) Decode(v interface{}) (err error) {
+ // tried to use closure, as runtime optimizes defer with no params.
+ // This seemed to be causing weird issues (like circular reference found, unexpected panic, etc).
+ // Also, see https://github.com/golang/go/issues/14939#issuecomment-417836139
+ // defer func() { d.deferred(&err) }()
+ // { x, y := d, &err; defer func() { x.deferred(y) }() }
+ if d.err != nil {
+ return d.err
+ }
+ if recoverPanicToErr {
+ defer func() {
+ if x := recover(); x != nil {
+ panicValToErr(d, x, &d.err)
+ err = d.err
+ }
+ }()
+ }
+
+ // defer d.deferred(&err)
+ d.mustDecode(v)
+ return
+}
+
+// MustDecode is like Decode, but panics if unable to Decode.
+// This provides insight to the code location that triggered the error.
+func (d *Decoder) MustDecode(v interface{}) {
+ if d.err != nil {
+ panic(d.err)
+ }
+ d.mustDecode(v)
+}
+
+// MustDecode is like Decode, but panics if unable to Decode.
+// This provides insight to the code location that triggered the error.
+func (d *Decoder) mustDecode(v interface{}) {
+ // TODO: Top-level: ensure that v is a pointer and not nil.
+ if d.d.TryDecodeAsNil() {
+ setZero(v)
+ return
+ }
+ if d.bi == nil {
+ d.decode(v)
+ return
+ }
+
+ d.bi.calls++
+ d.decode(v)
+ // xprintf.(">>>>>>>> >>>>>>>> num decFns: %v\n", d.cf.sn)
+ d.bi.calls--
+ if !d.h.ExplicitRelease && d.bi.calls == 0 {
+ d.bi.release()
+ }
+}
+
+// func (d *Decoder) deferred(err1 *error) {
+// if recoverPanicToErr {
+// if x := recover(); x != nil {
+// panicValToErr(d, x, err1)
+// panicValToErr(d, x, &d.err)
+// }
+// }
+// }
+
+//go:noinline -- as it is run by finalizer
+func (d *Decoder) finalize() {
+ // xdebugf("finalizing Decoder")
+ d.Release()
+}
+
+// Release releases shared (pooled) resources.
+//
+// It is important to call Release() when done with a Decoder, so those resources
+// are released instantly for use by subsequently created Decoders.
+//
+// By default, Release() is automatically called unless the option ExplicitRelease is set.
+func (d *Decoder) Release() {
+ if d.bi != nil {
+ d.bi.release()
+ }
+ // d.decNakedPooler.end()
+}
+
+// // this is not a smart swallow, as it allocates objects and does unnecessary work.
+// func (d *Decoder) swallowViaHammer() {
+// var blank interface{}
+// d.decodeValueNoFn(reflect.ValueOf(&blank).Elem())
+// }
+
+func (d *Decoder) swallow() {
+ // smarter decode that just swallows the content
+ dd := d.d
+ if dd.TryDecodeAsNil() {
+ return
+ }
+ elemsep := d.esep
+ switch dd.ContainerType() {
+ case valueTypeMap:
+ containerLen := dd.ReadMapStart()
+ d.depthIncr()
+ hasLen := containerLen >= 0
+ for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ {
+ // if clenGtEqualZero {if j >= containerLen {break} } else if dd.CheckBreak() {break}
+ if elemsep {
+ dd.ReadMapElemKey()
+ }
+ d.swallow()
+ if elemsep {
+ dd.ReadMapElemValue()
+ }
+ d.swallow()
+ }
+ dd.ReadMapEnd()
+ d.depthDecr()
+ case valueTypeArray:
+ containerLen := dd.ReadArrayStart()
+ d.depthIncr()
+ hasLen := containerLen >= 0
+ for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ {
+ if elemsep {
+ dd.ReadArrayElem()
+ }
+ d.swallow()
+ }
+ dd.ReadArrayEnd()
+ d.depthDecr()
+ case valueTypeBytes:
+ dd.DecodeBytes(d.b[:], true)
+ case valueTypeString:
+ dd.DecodeStringAsBytes()
+ default:
+ // these are all primitives, which we can get from decodeNaked
+ // if RawExt using Value, complete the processing.
+ n := d.naked()
+ dd.DecodeNaked()
+ if n.v == valueTypeExt && n.l == nil {
+ var v2 interface{}
+ d.decode(&v2)
+ }
+ }
+}
+
+func setZero(iv interface{}) {
+ if iv == nil || definitelyNil(iv) {
+ return
+ }
+ var canDecode bool
+ switch v := iv.(type) {
+ case *string:
+ *v = ""
+ case *bool:
+ *v = false
+ case *int:
+ *v = 0
+ case *int8:
+ *v = 0
+ case *int16:
+ *v = 0
+ case *int32:
+ *v = 0
+ case *int64:
+ *v = 0
+ case *uint:
+ *v = 0
+ case *uint8:
+ *v = 0
+ case *uint16:
+ *v = 0
+ case *uint32:
+ *v = 0
+ case *uint64:
+ *v = 0
+ case *float32:
+ *v = 0
+ case *float64:
+ *v = 0
+ case *[]uint8:
+ *v = nil
+ case *Raw:
+ *v = nil
+ case *time.Time:
+ *v = time.Time{}
+ case reflect.Value:
+ if v, canDecode = isDecodeable(v); canDecode && v.CanSet() {
+ v.Set(reflect.Zero(v.Type()))
+ } // TODO: else drain if chan, clear if map, set all to nil if slice???
+ default:
+ if !fastpathDecodeSetZeroTypeSwitch(iv) {
+ v := reflect.ValueOf(iv)
+ if v, canDecode = isDecodeable(v); canDecode && v.CanSet() {
+ v.Set(reflect.Zero(v.Type()))
+ } // TODO: else drain if chan, clear if map, set all to nil if slice???
+ }
+ }
+}
+
+func (d *Decoder) decode(iv interface{}) {
+ // a switch with only concrete types can be optimized.
+ // consequently, we deal with nil and interfaces outside the switch.
+
+ if iv == nil {
+ d.errorstr(errstrCannotDecodeIntoNil)
+ return
+ }
+
+ switch v := iv.(type) {
+ // case nil:
+ // case Selfer:
+ case reflect.Value:
+ v = d.ensureDecodeable(v)
+ d.decodeValue(v, nil, true)
+
+ case *string:
+ *v = d.d.DecodeString()
+ case *bool:
+ *v = d.d.DecodeBool()
+ case *int:
+ *v = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize))
+ case *int8:
+ *v = int8(chkOvf.IntV(d.d.DecodeInt64(), 8))
+ case *int16:
+ *v = int16(chkOvf.IntV(d.d.DecodeInt64(), 16))
+ case *int32:
+ *v = int32(chkOvf.IntV(d.d.DecodeInt64(), 32))
+ case *int64:
+ *v = d.d.DecodeInt64()
+ case *uint:
+ *v = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))
+ case *uint8:
+ *v = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8))
+ case *uint16:
+ *v = uint16(chkOvf.UintV(d.d.DecodeUint64(), 16))
+ case *uint32:
+ *v = uint32(chkOvf.UintV(d.d.DecodeUint64(), 32))
+ case *uint64:
+ *v = d.d.DecodeUint64()
+ case *float32:
+ f64 := d.d.DecodeFloat64()
+ if chkOvf.Float32(f64) {
+ d.errorf("float32 overflow: %v", f64)
+ }
+ *v = float32(f64)
+ case *float64:
+ *v = d.d.DecodeFloat64()
+ case *[]uint8:
+ *v = d.d.DecodeBytes(*v, false)
+ case []uint8:
+ b := d.d.DecodeBytes(v, false)
+ if !(len(b) > 0 && len(b) == len(v) && &b[0] == &v[0]) {
+ copy(v, b)
+ }
+ case *time.Time:
+ *v = d.d.DecodeTime()
+ case *Raw:
+ *v = d.rawBytes()
+
+ case *interface{}:
+ d.decodeValue(reflect.ValueOf(iv).Elem(), nil, true)
+ // d.decodeValueNotNil(reflect.ValueOf(iv).Elem())
+
+ default:
+ if v, ok := iv.(Selfer); ok {
+ v.CodecDecodeSelf(d)
+ } else if !fastpathDecodeTypeSwitch(iv, d) {
+ v := reflect.ValueOf(iv)
+ v = d.ensureDecodeable(v)
+ d.decodeValue(v, nil, false)
+ // d.decodeValueFallback(v)
+ }
+ }
+}
+
+func (d *Decoder) decodeValue(rv reflect.Value, fn *codecFn, chkAll bool) {
+ // If stream is not containing a nil value, then we can deref to the base
+ // non-pointer value, and decode into that.
+ var rvp reflect.Value
+ var rvpValid bool
+ if rv.Kind() == reflect.Ptr {
+ rvpValid = true
+ for {
+ if rv.IsNil() {
+ rv.Set(reflect.New(rv.Type().Elem()))
+ }
+ rvp = rv
+ rv = rv.Elem()
+ if rv.Kind() != reflect.Ptr {
+ break
+ }
+ }
+ }
+
+ if fn == nil {
+ // always pass checkCodecSelfer=true, in case T or ****T is passed, where *T is a Selfer
+ fn = d.h.fn(rv.Type(), chkAll, true) // chkAll, chkAll)
+ }
+ if fn.i.addrD {
+ if rvpValid {
+ fn.fd(d, &fn.i, rvp)
+ } else if rv.CanAddr() {
+ fn.fd(d, &fn.i, rv.Addr())
+ } else if !fn.i.addrF {
+ fn.fd(d, &fn.i, rv)
+ } else {
+ d.errorf("cannot decode into a non-pointer value")
+ }
+ } else {
+ fn.fd(d, &fn.i, rv)
+ }
+ // return rv
+}
+
+func (d *Decoder) structFieldNotFound(index int, rvkencname string) {
+ // NOTE: rvkencname may be a stringView, so don't pass it to another function.
+ if d.h.ErrorIfNoField {
+ if index >= 0 {
+ d.errorf("no matching struct field found when decoding stream array at index %v", index)
+ return
+ } else if rvkencname != "" {
+ d.errorf("no matching struct field found when decoding stream map with key %s", rvkencname)
+ return
+ }
+ }
+ d.swallow()
+}
+
+func (d *Decoder) arrayCannotExpand(sliceLen, streamLen int) {
+ if d.h.ErrorIfNoArrayExpand {
+ d.errorf("cannot expand array len during decode from %v to %v", sliceLen, streamLen)
+ }
+}
+
+func isDecodeable(rv reflect.Value) (rv2 reflect.Value, canDecode bool) {
+ switch rv.Kind() {
+ case reflect.Array:
+ return rv, rv.CanAddr()
+ case reflect.Ptr:
+ if !rv.IsNil() {
+ return rv.Elem(), true
+ }
+ case reflect.Slice, reflect.Chan, reflect.Map:
+ if !rv.IsNil() {
+ return rv, true
+ }
+ }
+ return
+}
+
+func (d *Decoder) ensureDecodeable(rv reflect.Value) (rv2 reflect.Value) {
+ // decode can take any reflect.Value that is a inherently addressable i.e.
+ // - array
+ // - non-nil chan (we will SEND to it)
+ // - non-nil slice (we will set its elements)
+ // - non-nil map (we will put into it)
+ // - non-nil pointer (we can "update" it)
+ rv2, canDecode := isDecodeable(rv)
+ if canDecode {
+ return
+ }
+ if !rv.IsValid() {
+ d.errorstr(errstrCannotDecodeIntoNil)
+ return
+ }
+ if !rv.CanInterface() {
+ d.errorf("cannot decode into a value without an interface: %v", rv)
+ return
+ }
+ rvi := rv2i(rv)
+ rvk := rv.Kind()
+ d.errorf("cannot decode into value of kind: %v, type: %T, %v", rvk, rvi, rvi)
+ return
+}
+
+func (d *Decoder) depthIncr() {
+ d.depth++
+ if d.depth >= d.maxdepth {
+ panic(errMaxDepthExceeded)
+ }
+}
+
+func (d *Decoder) depthDecr() {
+ d.depth--
+}
+
+// Possibly get an interned version of a string
+//
+// This should mostly be used for map keys, where the key type is string.
+// This is because keys of a map/struct are typically reused across many objects.
+func (d *Decoder) string(v []byte) (s string) {
+ if d.is == nil {
+ return string(v) // don't return stringView, as we need a real string here.
+ }
+ s, ok := d.is[string(v)] // no allocation here, per go implementation
+ if !ok {
+ s = string(v) // new allocation here
+ d.is[s] = s
+ }
+ return s
+}
+
+// nextValueBytes returns the next value in the stream as a set of bytes.
+func (d *Decoder) nextValueBytes() (bs []byte) {
+ d.d.uncacheRead()
+ d.r.track()
+ d.swallow()
+ bs = d.r.stopTrack()
+ return
+}
+
+func (d *Decoder) rawBytes() []byte {
+ // ensure that this is not a view into the bytes
+ // i.e. make new copy always.
+ bs := d.nextValueBytes()
+ bs2 := make([]byte, len(bs))
+ copy(bs2, bs)
+ return bs2
+}
+
+func (d *Decoder) wrapErr(v interface{}, err *error) {
+ *err = decodeError{codecError: codecError{name: d.hh.Name(), err: v}, pos: int(d.r.numread())}
+}
+
+// NumBytesRead returns the number of bytes read
+func (d *Decoder) NumBytesRead() int {
+ return int(d.r.numread())
+}
+
+// --------------------------------------------------
+
+// decSliceHelper assists when decoding into a slice, from a map or an array in the stream.
+// A slice can be set from a map or array in stream. This supports the MapBySlice interface.
+type decSliceHelper struct {
+ d *Decoder
+ // ct valueType
+ array bool
+}
+
+func (d *Decoder) decSliceHelperStart() (x decSliceHelper, clen int) {
+ dd := d.d
+ ctyp := dd.ContainerType()
+ switch ctyp {
+ case valueTypeArray:
+ x.array = true
+ clen = dd.ReadArrayStart()
+ case valueTypeMap:
+ clen = dd.ReadMapStart() * 2
+ default:
+ d.errorf("only encoded map or array can be decoded into a slice (%d)", ctyp)
+ }
+ // x.ct = ctyp
+ x.d = d
+ return
+}
+
+func (x decSliceHelper) End() {
+ if x.array {
+ x.d.d.ReadArrayEnd()
+ } else {
+ x.d.d.ReadMapEnd()
+ }
+}
+
+func (x decSliceHelper) ElemContainerState(index int) {
+ if x.array {
+ x.d.d.ReadArrayElem()
+ } else if index%2 == 0 {
+ x.d.d.ReadMapElemKey()
+ } else {
+ x.d.d.ReadMapElemValue()
+ }
+}
+
+func decByteSlice(r *decReaderSwitch, clen, maxInitLen int, bs []byte) (bsOut []byte) {
+ if clen == 0 {
+ return zeroByteSlice
+ }
+ if len(bs) == clen {
+ bsOut = bs
+ r.readb(bsOut)
+ } else if cap(bs) >= clen {
+ bsOut = bs[:clen]
+ r.readb(bsOut)
+ } else {
+ // bsOut = make([]byte, clen)
+ len2 := decInferLen(clen, maxInitLen, 1)
+ bsOut = make([]byte, len2)
+ r.readb(bsOut)
+ for len2 < clen {
+ len3 := decInferLen(clen-len2, maxInitLen, 1)
+ bs3 := bsOut
+ bsOut = make([]byte, len2+len3)
+ copy(bsOut, bs3)
+ r.readb(bsOut[len2:])
+ len2 += len3
+ }
+ }
+ return
+}
+
+// func decByteSliceZeroCopy(r decReader, clen, maxInitLen int, bs []byte) (bsOut []byte) {
+// if _, ok := r.(*bytesDecReader); ok && clen <= maxInitLen {
+// return r.readx(clen)
+// }
+// return decByteSlice(r, clen, maxInitLen, bs)
+// }
+
+func detachZeroCopyBytes(isBytesReader bool, dest []byte, in []byte) (out []byte) {
+ if xlen := len(in); xlen > 0 {
+ if isBytesReader || xlen <= scratchByteArrayLen {
+ if cap(dest) >= xlen {
+ out = dest[:xlen]
+ } else {
+ out = make([]byte, xlen)
+ }
+ copy(out, in)
+ return
+ }
+ }
+ return in
+}
+
+// decInferLen will infer a sensible length, given the following:
+// - clen: length wanted.
+// - maxlen: max length to be returned.
+// if <= 0, it is unset, and we infer it based on the unit size
+// - unit: number of bytes for each element of the collection
+func decInferLen(clen, maxlen, unit int) (rvlen int) {
+ // handle when maxlen is not set i.e. <= 0
+ if clen <= 0 {
+ return
+ }
+ if unit == 0 {
+ return clen
+ }
+ if maxlen <= 0 {
+ // no maxlen defined. Use maximum of 256K memory, with a floor of 4K items.
+ // maxlen = 256 * 1024 / unit
+ // if maxlen < (4 * 1024) {
+ // maxlen = 4 * 1024
+ // }
+ if unit < (256 / 4) {
+ maxlen = 256 * 1024 / unit
+ } else {
+ maxlen = 4 * 1024
+ }
+ }
+ if clen > maxlen {
+ rvlen = maxlen
+ } else {
+ rvlen = clen
+ }
+ return
+}
+
+func expandSliceRV(s reflect.Value, st reflect.Type, canChange bool, stElemSize, num, slen, scap int) (
+ s2 reflect.Value, scap2 int, changed bool, err string) {
+ l1 := slen + num // new slice length
+ if l1 < slen {
+ err = errmsgExpandSliceOverflow
+ return
+ }
+ if l1 <= scap {
+ if s.CanSet() {
+ s.SetLen(l1)
+ } else if canChange {
+ s2 = s.Slice(0, l1)
+ scap2 = scap
+ changed = true
+ } else {
+ err = errmsgExpandSliceCannotChange
+ return
+ }
+ return
+ }
+ if !canChange {
+ err = errmsgExpandSliceCannotChange
+ return
+ }
+ scap2 = growCap(scap, stElemSize, num)
+ s2 = reflect.MakeSlice(st, l1, scap2)
+ changed = true
+ reflect.Copy(s2, s)
+ return
+}
+
+func decReadFull(r io.Reader, bs []byte) (n uint, err error) {
+ var nn int
+ for n < uint(len(bs)) && err == nil {
+ nn, err = r.Read(bs[n:])
+ if nn > 0 {
+ if err == io.EOF {
+ // leave EOF for next time
+ err = nil
+ }
+ n += uint(nn)
+ }
+ }
+ // xdebugf("decReadFull: len(bs): %v, n: %v, err: %v", len(bs), n, err)
+ // do not do this - it serves no purpose
+ // if n != len(bs) && err == io.EOF { err = io.ErrUnexpectedEOF }
+ return
+}
+
+func decNakedReadRawBytes(dr decDriver, d *Decoder, n *decNaked, rawToString bool) {
+ if rawToString {
+ n.v = valueTypeString
+ n.s = string(dr.DecodeBytes(d.b[:], true))
+ } else {
+ n.v = valueTypeBytes
+ n.l = dr.DecodeBytes(nil, false)
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/doc.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/doc.go
new file mode 100644
index 00000000000..325c6e1ed95
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/doc.go
@@ -0,0 +1,239 @@
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+/*
+Package codec provides a High Performance, Feature-Rich Idiomatic
+codec/encoding library for msgpack, json.
+
+Supported Serialization formats are:
+
+ - msgpack: https://github.com/msgpack/msgpack
+ - json: http://json.org http://tools.ietf.org/html/rfc7159
+
+For detailed usage information, read the primer at
+http://ugorji.net/blog/go-codec-primer .
+
+The idiomatic Go support is as seen in other encoding packages in the
+standard library (ie json, xml, gob, etc).
+
+Rich Feature Set includes:
+
+ - Simple but extremely powerful and feature-rich API
+ - Excellent code coverage ( > 90% )
+ - Very High Performance.
+ Our extensive benchmarks show us outperforming Gob, Json, Bson, etc by 2-4X.
+ - Lock-free (sans mutex) concurrency for scaling to 100's of cores
+ - In-place updates during decode, with option to zero value in maps and slices prior to decode
+ - Coerce types where appropriate
+ e.g. decode an int in the stream into a float, decode numbers from formatted strings, etc
+ - Corner Cases:
+ Overflows, nil maps/slices, nil values in streams are handled correctly
+ - Standard field renaming via tags
+ - Support for omitting empty fields during an encoding
+ - Encoding from any value and decoding into pointer to any value
+ (struct, slice, map, primitives, pointers, interface{}, etc)
+ - Extensions to support efficient encoding/decoding of any named types
+ - Support encoding.(Binary|Text)(M|Unm)arshaler interfaces
+ - Support IsZero() bool to determine if a value is a zero value.
+ Analogous to time.Time.IsZero() bool.
+ - Decoding without a schema (into a interface{}).
+ Includes Options to configure what specific map or slice type to use
+ when decoding an encoded list or map into a nil interface{}
+ - Mapping a non-interface type to an interface, so we can decode appropriately
+ into any interface type with a correctly configured non-interface value.
+ - Encode a struct as an array, and decode struct from an array in the data stream
+ - Option to encode struct keys as numbers (instead of strings)
+ (to support structured streams with fields encoded as numeric codes)
+ - Comprehensive support for anonymous fields
+ - Fast (no-reflection) encoding/decoding of common maps and slices
+ - Code-generation for faster performance.
+ - Support binary (e.g. messagepack) and text (e.g. json) formats
+ - Support indefinite-length formats to enable true streaming
+ (for formats which support it e.g. json)
+ - Support canonical encoding, where a value is ALWAYS encoded as same sequence of bytes.
+ This mostly applies to maps, where iteration order is non-deterministic.
+ - NIL in data stream decoded as zero value
+ - Never silently skip data when decoding.
+ User decides whether to return an error or silently skip data when keys or indexes
+ in the data stream do not map to fields in the struct.
+ - Detect and error when encoding a cyclic reference (instead of stack overflow shutdown)
+ - Encode/Decode from/to chan types (for iterative streaming support)
+ - Drop-in replacement for encoding/json. `json:` key in struct tag supported.
+ - Provides a RPC Server and Client Codec for net/rpc communication protocol.
+ - Handle unique idiosyncrasies of codecs e.g.
+ - For messagepack, configure how ambiguities in handling raw bytes are resolved
+ - For messagepack, provide rpc server/client codec to support
+ msgpack-rpc protocol defined at:
+ https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md
+
+## Extension Support
+
+Users can register a function to handle the encoding or decoding of their
+custom types.
+
+There are no restrictions on what the custom type can be. Some examples:
+
+```go
+
+ type BisSet []int
+ type BitSet64 uint64
+ type UUID string
+ type MyStructWithUnexportedFields struct { a int; b bool; c []int; }
+ type GifImage struct { ... }
+
+```
+
+As an illustration, MyStructWithUnexportedFields would normally be encoded
+as an empty map because it has no exported fields, while UUID would be
+encoded as a string. However, with extension support, you can encode any of
+these however you like.
+
+## Custom Encoding and Decoding
+
+This package maintains symmetry in the encoding and decoding halfs. We
+determine how to encode or decode by walking this decision tree
+
+ - is type a codec.Selfer?
+ - is there an extension registered for the type?
+ - is format binary, and is type a encoding.BinaryMarshaler and BinaryUnmarshaler?
+ - is format specifically json, and is type a encoding/json.Marshaler and Unmarshaler?
+ - is format text-based, and type an encoding.TextMarshaler and TextUnmarshaler?
+ - else we use a pair of functions based on the "kind" of the type e.g. map, slice, int64, etc
+
+This symmetry is important to reduce chances of issues happening because the
+encoding and decoding sides are out of sync e.g. decoded via very specific
+encoding.TextUnmarshaler but encoded via kind-specific generalized mode.
+
+Consequently, if a type only defines one-half of the symmetry (e.g. it
+implements UnmarshalJSON() but not MarshalJSON() ), then that type doesn't
+satisfy the check and we will continue walking down the decision tree.
+
+## RPC
+
+RPC Client and Server Codecs are implemented, so the codecs can be used with
+the standard net/rpc package.
+
+## Usage
+
+The Handle is SAFE for concurrent READ, but NOT SAFE for concurrent
+modification.
+
+The Encoder and Decoder are NOT safe for concurrent use.
+
+Consequently, the usage model is basically:
+
+ - Create and initialize the Handle before any use.
+ Once created, DO NOT modify it.
+ - Multiple Encoders or Decoders can now use the Handle concurrently.
+ They only read information off the Handle (never write).
+ - However, each Encoder or Decoder MUST not be used concurrently
+ - To re-use an Encoder/Decoder, call Reset(...) on it first.
+ This allows you use state maintained on the Encoder/Decoder.
+
+Sample usage model:
+
+```go
+
+ // create and configure Handle
+ var (
+ mh codec.MsgpackHandle
+ )
+
+ mh.MapType = reflect.TypeOf(map[string]interface{}(nil))
+
+ // configure extensions
+ // e.g. for msgpack, define functions and enable Time support for tag 1
+ mh.SetExt(reflect.TypeOf(time.Time{}), 1, myExt)
+
+ // create and use decoder/encoder
+ var (
+ r io.Reader
+ w io.Writer
+ b []byte
+ h = &mh
+ )
+
+ dec = codec.NewDecoder(r, h)
+ dec = codec.NewDecoderBytes(b, h)
+ err = dec.Decode(&v)
+
+ enc = codec.NewEncoder(w, h)
+ enc = codec.NewEncoderBytes(&b, h)
+ err = enc.Encode(v)
+
+ //RPC Server
+ go func() {
+ for {
+ conn, err := listener.Accept()
+ rpcCodec := codec.GoRpc.ServerCodec(conn, h)
+ //OR rpcCodec := codec.MsgpackSpecRpc.ServerCodec(conn, h)
+ rpc.ServeCodec(rpcCodec)
+ }
+ }()
+
+ //RPC Communication (client side)
+ conn, err = net.Dial("tcp", "localhost:5555")
+ rpcCodec := codec.GoRpc.ClientCodec(conn, h)
+ //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h)
+ client := rpc.NewClientWithCodec(rpcCodec)
+
+```
+
+## Running Tests
+
+To run tests, use the following:
+
+```
+
+ go test
+
+```
+
+To run the full suite of tests, use the following:
+
+```
+
+ go test -tags alltests -run Suite
+
+```
+
+You can run the tag 'safe' to run tests or build in safe mode. e.g.
+
+```
+
+ go test -tags safe -run Json
+ go test -tags "alltests safe" -run Suite
+
+```
+
+## Running Benchmarks
+
+```
+
+ cd codec/bench
+ ./bench.sh -d
+ ./bench.sh -c
+ ./bench.sh -s
+ go test -bench . -benchmem -benchtime 1s
+
+```
+
+Please see http://github.com/hashicorp/go-codec-bench .
+
+## Caveats
+
+Struct fields matching the following are ignored during encoding and
+decoding
+
+ - struct tag value set to -
+ - func, complex numbers, unsafe pointers
+ - unexported and not embedded
+ - unexported and embedded and not struct kind
+ - unexported and embedded pointers
+
+Every other field in a struct will be encoded/decoded.
+
+Embedded fields are encoded as if they exist in the top-level struct, with
+some caveats. See Encode documentation.
+*/
+package codec
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/encode.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/encode.go
new file mode 100644
index 00000000000..29c723e13e5
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/encode.go
@@ -0,0 +1,1812 @@
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+package codec
+
+import (
+ "encoding"
+ "errors"
+ "fmt"
+ "io"
+ "reflect"
+ "runtime"
+ "sort"
+ "strconv"
+ "time"
+)
+
+// defEncByteBufSize is the default size of []byte used
+// for bufio buffer or []byte (when nil passed)
+const defEncByteBufSize = 1 << 10 // 4:16, 6:64, 8:256, 10:1024
+
+var errEncoderNotInitialized = errors.New("Encoder not initialized")
+
+/*
+
+// encWriter abstracts writing to a byte array or to an io.Writer.
+//
+//
+// Deprecated: Use encWriterSwitch instead.
+type encWriter interface {
+ writeb([]byte)
+ writestr(string)
+ writen1(byte)
+ writen2(byte, byte)
+ end()
+}
+
+*/
+
+// encDriver abstracts the actual codec (binc vs msgpack, etc)
+type encDriver interface {
+ EncodeNil()
+ EncodeInt(i int64)
+ EncodeUint(i uint64)
+ EncodeBool(b bool)
+ EncodeFloat32(f float32)
+ EncodeFloat64(f float64)
+ // encodeExtPreamble(xtag byte, length int)
+ EncodeRawExt(re *RawExt, e *Encoder)
+ EncodeExt(v interface{}, xtag uint64, ext Ext, e *Encoder)
+ // Deprecated: use EncodeStringEnc instead
+ EncodeString(c charEncoding, v string)
+ // Deprecated: use EncodeStringBytesRaw instead
+ EncodeStringBytes(c charEncoding, v []byte)
+ EncodeStringEnc(c charEncoding, v string) // c cannot be cRAW
+ // EncodeSymbol(v string)
+ EncodeStringBytesRaw(v []byte)
+ EncodeTime(time.Time)
+ //encBignum(f *big.Int)
+ //encStringRunes(c charEncoding, v []rune)
+ WriteArrayStart(length int)
+ WriteArrayElem()
+ WriteArrayEnd()
+ WriteMapStart(length int)
+ WriteMapElemKey()
+ WriteMapElemValue()
+ WriteMapEnd()
+
+ reset()
+ atEndOfEncode()
+}
+
+type encDriverAsis interface {
+ EncodeAsis(v []byte)
+}
+
+type encodeError struct {
+ codecError
+}
+
+func (e encodeError) Error() string {
+ return fmt.Sprintf("%s encode error: %v", e.name, e.err)
+}
+
+type encDriverNoopContainerWriter struct{}
+
+func (encDriverNoopContainerWriter) WriteArrayStart(length int) {}
+func (encDriverNoopContainerWriter) WriteArrayElem() {}
+func (encDriverNoopContainerWriter) WriteArrayEnd() {}
+func (encDriverNoopContainerWriter) WriteMapStart(length int) {}
+func (encDriverNoopContainerWriter) WriteMapElemKey() {}
+func (encDriverNoopContainerWriter) WriteMapElemValue() {}
+func (encDriverNoopContainerWriter) WriteMapEnd() {}
+func (encDriverNoopContainerWriter) atEndOfEncode() {}
+
+type encDriverTrackContainerWriter struct {
+ c containerState
+}
+
+func (e *encDriverTrackContainerWriter) WriteArrayStart(length int) { e.c = containerArrayStart }
+func (e *encDriverTrackContainerWriter) WriteArrayElem() { e.c = containerArrayElem }
+func (e *encDriverTrackContainerWriter) WriteArrayEnd() { e.c = containerArrayEnd }
+func (e *encDriverTrackContainerWriter) WriteMapStart(length int) { e.c = containerMapStart }
+func (e *encDriverTrackContainerWriter) WriteMapElemKey() { e.c = containerMapKey }
+func (e *encDriverTrackContainerWriter) WriteMapElemValue() { e.c = containerMapValue }
+func (e *encDriverTrackContainerWriter) WriteMapEnd() { e.c = containerMapEnd }
+func (e *encDriverTrackContainerWriter) atEndOfEncode() {}
+
+// type ioEncWriterWriter interface {
+// WriteByte(c byte) error
+// WriteString(s string) (n int, err error)
+// Write(p []byte) (n int, err error)
+// }
+
+// EncodeOptions captures configuration options during encode.
+type EncodeOptions struct {
+ // WriterBufferSize is the size of the buffer used when writing.
+ //
+ // if > 0, we use a smart buffer internally for performance purposes.
+ WriterBufferSize int
+
+ // ChanRecvTimeout is the timeout used when selecting from a chan.
+ //
+ // Configuring this controls how we receive from a chan during the encoding process.
+ // - If ==0, we only consume the elements currently available in the chan.
+ // - if <0, we consume until the chan is closed.
+ // - If >0, we consume until this timeout.
+ ChanRecvTimeout time.Duration
+
+ // StructToArray specifies to encode a struct as an array, and not as a map
+ StructToArray bool
+
+ // Canonical representation means that encoding a value will always result in the same
+ // sequence of bytes.
+ //
+ // This only affects maps, as the iteration order for maps is random.
+ //
+ // The implementation MAY use the natural sort order for the map keys if possible:
+ //
+ // - If there is a natural sort order (ie for number, bool, string or []byte keys),
+ // then the map keys are first sorted in natural order and then written
+ // with corresponding map values to the strema.
+ // - If there is no natural sort order, then the map keys will first be
+ // encoded into []byte, and then sorted,
+ // before writing the sorted keys and the corresponding map values to the stream.
+ //
+ Canonical bool
+
+ // CheckCircularRef controls whether we check for circular references
+ // and error fast during an encode.
+ //
+ // If enabled, an error is received if a pointer to a struct
+ // references itself either directly or through one of its fields (iteratively).
+ //
+ // This is opt-in, as there may be a performance hit to checking circular references.
+ CheckCircularRef bool
+
+ // RecursiveEmptyCheck controls whether we descend into interfaces, structs and pointers
+ // when checking if a value is empty.
+ //
+ // Note that this may make OmitEmpty more expensive, as it incurs a lot more reflect calls.
+ RecursiveEmptyCheck bool
+
+ // Raw controls whether we encode Raw values.
+ // This is a "dangerous" option and must be explicitly set.
+ // If set, we blindly encode Raw values as-is, without checking
+ // if they are a correct representation of a value in that format.
+ // If unset, we error out.
+ Raw bool
+
+ // StringToRaw controls how strings are encoded.
+ //
+ // As a go string is just an (immutable) sequence of bytes,
+ // it can be encoded either as raw bytes or as a UTF string.
+ //
+ // By default, strings are encoded as UTF-8.
+ // but can be treated as []byte during an encode.
+ //
+ // Note that things which we know (by definition) to be UTF-8
+ // are ALWAYS encoded as UTF-8 strings.
+ // These include encoding.TextMarshaler, time.Format calls, struct field names, etc.
+ StringToRaw bool
+
+ // // AsSymbols defines what should be encoded as symbols.
+ // //
+ // // Encoding as symbols can reduce the encoded size significantly.
+ // //
+ // // However, during decoding, each string to be encoded as a symbol must
+ // // be checked to see if it has been seen before. Consequently, encoding time
+ // // will increase if using symbols, because string comparisons has a clear cost.
+ // //
+ // // Sample values:
+ // // AsSymbolNone
+ // // AsSymbolAll
+ // // AsSymbolMapStringKeys
+ // // AsSymbolMapStringKeysFlag | AsSymbolStructFieldNameFlag
+ // AsSymbols AsSymbolFlag
+}
+
+// ---------------------------------------------
+
+/*
+
+type ioEncStringWriter interface {
+ WriteString(s string) (n int, err error)
+}
+
+// ioEncWriter implements encWriter and can write to an io.Writer implementation
+type ioEncWriter struct {
+ w io.Writer
+ ww io.Writer
+ bw io.ByteWriter
+ sw ioEncStringWriter
+ fw ioFlusher
+ b [8]byte
+}
+
+func (z *ioEncWriter) reset(w io.Writer) {
+ z.w = w
+ var ok bool
+ if z.bw, ok = w.(io.ByteWriter); !ok {
+ z.bw = z
+ }
+ if z.sw, ok = w.(ioEncStringWriter); !ok {
+ z.sw = z
+ }
+ z.fw, _ = w.(ioFlusher)
+ z.ww = w
+}
+
+func (z *ioEncWriter) WriteByte(b byte) (err error) {
+ z.b[0] = b
+ _, err = z.w.Write(z.b[:1])
+ return
+}
+
+func (z *ioEncWriter) WriteString(s string) (n int, err error) {
+ return z.w.Write(bytesView(s))
+}
+
+func (z *ioEncWriter) writeb(bs []byte) {
+ if _, err := z.ww.Write(bs); err != nil {
+ panic(err)
+ }
+}
+
+func (z *ioEncWriter) writestr(s string) {
+ if _, err := z.sw.WriteString(s); err != nil {
+ panic(err)
+ }
+}
+
+func (z *ioEncWriter) writen1(b byte) {
+ if err := z.bw.WriteByte(b); err != nil {
+ panic(err)
+ }
+}
+
+func (z *ioEncWriter) writen2(b1, b2 byte) {
+ var err error
+ if err = z.bw.WriteByte(b1); err == nil {
+ if err = z.bw.WriteByte(b2); err == nil {
+ return
+ }
+ }
+ panic(err)
+}
+
+// func (z *ioEncWriter) writen5(b1, b2, b3, b4, b5 byte) {
+// z.b[0], z.b[1], z.b[2], z.b[3], z.b[4] = b1, b2, b3, b4, b5
+// if _, err := z.ww.Write(z.b[:5]); err != nil {
+// panic(err)
+// }
+// }
+
+//go:noinline - so *encWriterSwitch.XXX has the bytesEncAppender.XXX inlined
+func (z *ioEncWriter) end() {
+ if z.fw != nil {
+ if err := z.fw.Flush(); err != nil {
+ panic(err)
+ }
+ }
+}
+
+*/
+
+// ---------------------------------------------
+
+// bufioEncWriter
+type bufioEncWriter struct {
+ buf []byte
+ w io.Writer
+ n int
+ sz int // buf size
+
+ // Extensions can call Encode() within a current Encode() call.
+ // We need to know when the top level Encode() call returns,
+ // so we can decide whether to Release() or not.
+ calls uint16 // what depth in mustDecode are we in now.
+
+ _ [6]uint8 // padding
+
+ bytesBufPooler
+
+ _ [1]uint64 // padding
+ // a int
+ // b [4]byte
+ // err
+}
+
+func (z *bufioEncWriter) reset(w io.Writer, bufsize int) {
+ z.w = w
+ z.n = 0
+ z.calls = 0
+ if bufsize <= 0 {
+ bufsize = defEncByteBufSize
+ }
+ z.sz = bufsize
+ if cap(z.buf) >= bufsize {
+ z.buf = z.buf[:cap(z.buf)]
+ } else {
+ z.buf = z.bytesBufPooler.get(bufsize)
+ // z.buf = make([]byte, bufsize)
+ }
+}
+
+func (z *bufioEncWriter) release() {
+ z.buf = nil
+ z.bytesBufPooler.end()
+}
+
+//go:noinline - flush only called intermittently
+func (z *bufioEncWriter) flushErr() (err error) {
+ n, err := z.w.Write(z.buf[:z.n])
+ z.n -= n
+ if z.n > 0 && err == nil {
+ err = io.ErrShortWrite
+ }
+ if n > 0 && z.n > 0 {
+ copy(z.buf, z.buf[n:z.n+n])
+ }
+ return err
+}
+
+func (z *bufioEncWriter) flush() {
+ if err := z.flushErr(); err != nil {
+ panic(err)
+ }
+}
+
+func (z *bufioEncWriter) writeb(s []byte) {
+LOOP:
+ a := len(z.buf) - z.n
+ if len(s) > a {
+ z.n += copy(z.buf[z.n:], s[:a])
+ s = s[a:]
+ z.flush()
+ goto LOOP
+ }
+ z.n += copy(z.buf[z.n:], s)
+}
+
+func (z *bufioEncWriter) writestr(s string) {
+ // z.writeb(bytesView(s)) // inlined below
+LOOP:
+ a := len(z.buf) - z.n
+ if len(s) > a {
+ z.n += copy(z.buf[z.n:], s[:a])
+ s = s[a:]
+ z.flush()
+ goto LOOP
+ }
+ z.n += copy(z.buf[z.n:], s)
+}
+
+func (z *bufioEncWriter) writen1(b1 byte) {
+ if 1 > len(z.buf)-z.n {
+ z.flush()
+ }
+ z.buf[z.n] = b1
+ z.n++
+}
+
+func (z *bufioEncWriter) writen2(b1, b2 byte) {
+ if 2 > len(z.buf)-z.n {
+ z.flush()
+ }
+ z.buf[z.n+1] = b2
+ z.buf[z.n] = b1
+ z.n += 2
+}
+
+func (z *bufioEncWriter) endErr() (err error) {
+ if z.n > 0 {
+ err = z.flushErr()
+ }
+ return
+}
+
+// ---------------------------------------------
+
+// bytesEncAppender implements encWriter and can write to an byte slice.
+type bytesEncAppender struct {
+ b []byte
+ out *[]byte
+}
+
+func (z *bytesEncAppender) writeb(s []byte) {
+ z.b = append(z.b, s...)
+}
+func (z *bytesEncAppender) writestr(s string) {
+ z.b = append(z.b, s...)
+}
+func (z *bytesEncAppender) writen1(b1 byte) {
+ z.b = append(z.b, b1)
+}
+func (z *bytesEncAppender) writen2(b1, b2 byte) {
+ z.b = append(z.b, b1, b2)
+}
+func (z *bytesEncAppender) endErr() error {
+ *(z.out) = z.b
+ return nil
+}
+func (z *bytesEncAppender) reset(in []byte, out *[]byte) {
+ z.b = in[:0]
+ z.out = out
+}
+
+// ---------------------------------------------
+
+func (e *Encoder) rawExt(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeRawExt(rv2i(rv).(*RawExt), e)
+}
+
+func (e *Encoder) ext(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeExt(rv2i(rv), f.xfTag, f.xfFn, e)
+}
+
+func (e *Encoder) selferMarshal(f *codecFnInfo, rv reflect.Value) {
+ rv2i(rv).(Selfer).CodecEncodeSelf(e)
+}
+
+func (e *Encoder) binaryMarshal(f *codecFnInfo, rv reflect.Value) {
+ bs, fnerr := rv2i(rv).(encoding.BinaryMarshaler).MarshalBinary()
+ e.marshalRaw(bs, fnerr)
+}
+
+func (e *Encoder) textMarshal(f *codecFnInfo, rv reflect.Value) {
+ bs, fnerr := rv2i(rv).(encoding.TextMarshaler).MarshalText()
+ e.marshalUtf8(bs, fnerr)
+}
+
+func (e *Encoder) jsonMarshal(f *codecFnInfo, rv reflect.Value) {
+ bs, fnerr := rv2i(rv).(jsonMarshaler).MarshalJSON()
+ e.marshalAsis(bs, fnerr)
+}
+
+func (e *Encoder) raw(f *codecFnInfo, rv reflect.Value) {
+ e.rawBytes(rv2i(rv).(Raw))
+}
+
+func (e *Encoder) kInvalid(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeNil()
+}
+
+func (e *Encoder) kErr(f *codecFnInfo, rv reflect.Value) {
+ e.errorf("unsupported kind %s, for %#v", rv.Kind(), rv)
+}
+
+func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) {
+ ti := f.ti
+ ee := e.e
+ // array may be non-addressable, so we have to manage with care
+ // (don't call rv.Bytes, rv.Slice, etc).
+ // E.g. type struct S{B [2]byte};
+ // Encode(S{}) will bomb on "panic: slice of unaddressable array".
+ if f.seq != seqTypeArray {
+ if rv.IsNil() {
+ ee.EncodeNil()
+ return
+ }
+ // If in this method, then there was no extension function defined.
+ // So it's okay to treat as []byte.
+ if ti.rtid == uint8SliceTypId {
+ ee.EncodeStringBytesRaw(rv.Bytes())
+ return
+ }
+ }
+ if f.seq == seqTypeChan && ti.chandir&uint8(reflect.RecvDir) == 0 {
+ e.errorf("send-only channel cannot be encoded")
+ }
+ elemsep := e.esep
+ rtelem := ti.elem
+ rtelemIsByte := uint8TypId == rt2id(rtelem) // NOT rtelem.Kind() == reflect.Uint8
+ var l int
+ // if a slice, array or chan of bytes, treat specially
+ if rtelemIsByte {
+ switch f.seq {
+ case seqTypeSlice:
+ ee.EncodeStringBytesRaw(rv.Bytes())
+ case seqTypeArray:
+ l = rv.Len()
+ if rv.CanAddr() {
+ ee.EncodeStringBytesRaw(rv.Slice(0, l).Bytes())
+ } else {
+ var bs []byte
+ if l <= cap(e.b) {
+ bs = e.b[:l]
+ } else {
+ bs = make([]byte, l)
+ }
+ reflect.Copy(reflect.ValueOf(bs), rv)
+ ee.EncodeStringBytesRaw(bs)
+ }
+ case seqTypeChan:
+ // do not use range, so that the number of elements encoded
+ // does not change, and encoding does not hang waiting on someone to close chan.
+ // for b := range rv2i(rv).(<-chan byte) { bs = append(bs, b) }
+ // ch := rv2i(rv).(<-chan byte) // fix error - that this is a chan byte, not a <-chan byte.
+
+ if rv.IsNil() {
+ ee.EncodeNil()
+ break
+ }
+ bs := e.b[:0]
+ irv := rv2i(rv)
+ ch, ok := irv.(<-chan byte)
+ if !ok {
+ ch = irv.(chan byte)
+ }
+
+ L1:
+ switch timeout := e.h.ChanRecvTimeout; {
+ case timeout == 0: // only consume available
+ for {
+ select {
+ case b := <-ch:
+ bs = append(bs, b)
+ default:
+ break L1
+ }
+ }
+ case timeout > 0: // consume until timeout
+ tt := time.NewTimer(timeout)
+ for {
+ select {
+ case b := <-ch:
+ bs = append(bs, b)
+ case <-tt.C:
+ // close(tt.C)
+ break L1
+ }
+ }
+ default: // consume until close
+ for b := range ch {
+ bs = append(bs, b)
+ }
+ }
+
+ ee.EncodeStringBytesRaw(bs)
+ }
+ return
+ }
+
+ // if chan, consume chan into a slice, and work off that slice.
+ if f.seq == seqTypeChan {
+ rvcs := reflect.Zero(reflect.SliceOf(rtelem))
+ timeout := e.h.ChanRecvTimeout
+ if timeout < 0 { // consume until close
+ for {
+ recv, recvOk := rv.Recv()
+ if !recvOk {
+ break
+ }
+ rvcs = reflect.Append(rvcs, recv)
+ }
+ } else {
+ cases := make([]reflect.SelectCase, 2)
+ cases[0] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: rv}
+ if timeout == 0 {
+ cases[1] = reflect.SelectCase{Dir: reflect.SelectDefault}
+ } else {
+ tt := time.NewTimer(timeout)
+ cases[1] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(tt.C)}
+ }
+ for {
+ chosen, recv, recvOk := reflect.Select(cases)
+ if chosen == 1 || !recvOk {
+ break
+ }
+ rvcs = reflect.Append(rvcs, recv)
+ }
+ }
+ rv = rvcs // TODO: ensure this doesn't mess up anywhere that rv of kind chan is expected
+ }
+
+ l = rv.Len()
+ if ti.mbs {
+ if l%2 == 1 {
+ e.errorf("mapBySlice requires even slice length, but got %v", l)
+ return
+ }
+ ee.WriteMapStart(l / 2)
+ } else {
+ ee.WriteArrayStart(l)
+ }
+
+ if l > 0 {
+ var fn *codecFn
+ for rtelem.Kind() == reflect.Ptr {
+ rtelem = rtelem.Elem()
+ }
+ // if kind is reflect.Interface, do not pre-determine the
+ // encoding type, because preEncodeValue may break it down to
+ // a concrete type and kInterface will bomb.
+ if rtelem.Kind() != reflect.Interface {
+ fn = e.h.fn(rtelem, true, true)
+ }
+ for j := 0; j < l; j++ {
+ if elemsep {
+ if ti.mbs {
+ if j%2 == 0 {
+ ee.WriteMapElemKey()
+ } else {
+ ee.WriteMapElemValue()
+ }
+ } else {
+ ee.WriteArrayElem()
+ }
+ }
+ e.encodeValue(rv.Index(j), fn, true)
+ }
+ }
+
+ if ti.mbs {
+ ee.WriteMapEnd()
+ } else {
+ ee.WriteArrayEnd()
+ }
+}
+
+func (e *Encoder) kStructNoOmitempty(f *codecFnInfo, rv reflect.Value) {
+ fti := f.ti
+ tisfi := fti.sfiSrc
+ toMap := !(fti.toArray || e.h.StructToArray)
+ if toMap {
+ tisfi = fti.sfiSort
+ }
+
+ ee := e.e
+
+ sfn := structFieldNode{v: rv, update: false}
+ if toMap {
+ ee.WriteMapStart(len(tisfi))
+ if e.esep {
+ for _, si := range tisfi {
+ ee.WriteMapElemKey()
+ e.kStructFieldKey(fti.keyType, si.encNameAsciiAlphaNum, si.encName)
+ ee.WriteMapElemValue()
+ e.encodeValue(sfn.field(si), nil, true)
+ }
+ } else {
+ for _, si := range tisfi {
+ e.kStructFieldKey(fti.keyType, si.encNameAsciiAlphaNum, si.encName)
+ e.encodeValue(sfn.field(si), nil, true)
+ }
+ }
+ ee.WriteMapEnd()
+ } else {
+ ee.WriteArrayStart(len(tisfi))
+ if e.esep {
+ for _, si := range tisfi {
+ ee.WriteArrayElem()
+ e.encodeValue(sfn.field(si), nil, true)
+ }
+ } else {
+ for _, si := range tisfi {
+ e.encodeValue(sfn.field(si), nil, true)
+ }
+ }
+ ee.WriteArrayEnd()
+ }
+}
+
+func (e *Encoder) kStructFieldKey(keyType valueType, encNameAsciiAlphaNum bool, encName string) {
+ encStructFieldKey(encName, e.e, e.w, keyType, encNameAsciiAlphaNum, e.js)
+}
+
+func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
+ fti := f.ti
+ elemsep := e.esep
+ tisfi := fti.sfiSrc
+ var newlen int
+ toMap := !(fti.toArray || e.h.StructToArray)
+ var mf map[string]interface{}
+ if f.ti.mf {
+ mf = rv2i(rv).(MissingFielder).CodecMissingFields()
+ toMap = true
+ newlen += len(mf)
+ } else if f.ti.mfp {
+ if rv.CanAddr() {
+ mf = rv2i(rv.Addr()).(MissingFielder).CodecMissingFields()
+ } else {
+ // make a new addressable value of same one, and use it
+ rv2 := reflect.New(rv.Type())
+ rv2.Elem().Set(rv)
+ mf = rv2i(rv2).(MissingFielder).CodecMissingFields()
+ }
+ toMap = true
+ newlen += len(mf)
+ }
+ // if toMap, use the sorted array. If toArray, use unsorted array (to match sequence in struct)
+ if toMap {
+ tisfi = fti.sfiSort
+ }
+ newlen += len(tisfi)
+ ee := e.e
+
+ // Use sync.Pool to reduce allocating slices unnecessarily.
+ // The cost of sync.Pool is less than the cost of new allocation.
+ //
+ // Each element of the array pools one of encStructPool(8|16|32|64).
+ // It allows the re-use of slices up to 64 in length.
+ // A performance cost of encoding structs was collecting
+ // which values were empty and should be omitted.
+ // We needed slices of reflect.Value and string to collect them.
+ // This shared pool reduces the amount of unnecessary creation we do.
+ // The cost is that of locking sometimes, but sync.Pool is efficient
+ // enough to reduce thread contention.
+
+ // fmt.Printf(">>>>>>>>>>>>>> encode.kStruct: newlen: %d\n", newlen)
+ var spool sfiRvPooler
+ var fkvs = spool.get(newlen)
+
+ var kv sfiRv
+ recur := e.h.RecursiveEmptyCheck
+ sfn := structFieldNode{v: rv, update: false}
+ newlen = 0
+ for _, si := range tisfi {
+ // kv.r = si.field(rv, false)
+ kv.r = sfn.field(si)
+ if toMap {
+ if si.omitEmpty() && isEmptyValue(kv.r, e.h.TypeInfos, recur, recur) {
+ continue
+ }
+ kv.v = si // si.encName
+ } else {
+ // use the zero value.
+ // if a reference or struct, set to nil (so you do not output too much)
+ if si.omitEmpty() && isEmptyValue(kv.r, e.h.TypeInfos, recur, recur) {
+ switch kv.r.Kind() {
+ case reflect.Struct, reflect.Interface, reflect.Ptr,
+ reflect.Array, reflect.Map, reflect.Slice:
+ kv.r = reflect.Value{} //encode as nil
+ }
+ }
+ }
+ fkvs[newlen] = kv
+ newlen++
+ }
+ fkvs = fkvs[:newlen]
+
+ var mflen int
+ for k, v := range mf {
+ if k == "" {
+ delete(mf, k)
+ continue
+ }
+ if fti.infoFieldOmitempty && isEmptyValue(reflect.ValueOf(v), e.h.TypeInfos, recur, recur) {
+ delete(mf, k)
+ continue
+ }
+ mflen++
+ }
+
+ var j int
+ if toMap {
+ ee.WriteMapStart(newlen + mflen)
+ if elemsep {
+ for j = 0; j < len(fkvs); j++ {
+ kv = fkvs[j]
+ ee.WriteMapElemKey()
+ e.kStructFieldKey(fti.keyType, kv.v.encNameAsciiAlphaNum, kv.v.encName)
+ ee.WriteMapElemValue()
+ e.encodeValue(kv.r, nil, true)
+ }
+ } else {
+ for j = 0; j < len(fkvs); j++ {
+ kv = fkvs[j]
+ e.kStructFieldKey(fti.keyType, kv.v.encNameAsciiAlphaNum, kv.v.encName)
+ e.encodeValue(kv.r, nil, true)
+ }
+ }
+ // now, add the others
+ for k, v := range mf {
+ ee.WriteMapElemKey()
+ e.kStructFieldKey(fti.keyType, false, k)
+ ee.WriteMapElemValue()
+ e.encode(v)
+ }
+ ee.WriteMapEnd()
+ } else {
+ ee.WriteArrayStart(newlen)
+ if elemsep {
+ for j = 0; j < len(fkvs); j++ {
+ ee.WriteArrayElem()
+ e.encodeValue(fkvs[j].r, nil, true)
+ }
+ } else {
+ for j = 0; j < len(fkvs); j++ {
+ e.encodeValue(fkvs[j].r, nil, true)
+ }
+ }
+ ee.WriteArrayEnd()
+ }
+
+ // do not use defer. Instead, use explicit pool return at end of function.
+ // defer has a cost we are trying to avoid.
+ // If there is a panic and these slices are not returned, it is ok.
+ spool.end()
+}
+
+func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
+ ee := e.e
+ if rv.IsNil() {
+ ee.EncodeNil()
+ return
+ }
+
+ l := rv.Len()
+ ee.WriteMapStart(l)
+ if l == 0 {
+ ee.WriteMapEnd()
+ return
+ }
+ // var asSymbols bool
+ // determine the underlying key and val encFn's for the map.
+ // This eliminates some work which is done for each loop iteration i.e.
+ // rv.Type(), ref.ValueOf(rt).Pointer(), then check map/list for fn.
+ //
+ // However, if kind is reflect.Interface, do not pre-determine the
+ // encoding type, because preEncodeValue may break it down to
+ // a concrete type and kInterface will bomb.
+ var keyFn, valFn *codecFn
+ ti := f.ti
+ rtkey0 := ti.key
+ rtkey := rtkey0
+ rtval0 := ti.elem
+ rtval := rtval0
+ // rtkeyid := rt2id(rtkey0)
+ for rtval.Kind() == reflect.Ptr {
+ rtval = rtval.Elem()
+ }
+ if rtval.Kind() != reflect.Interface {
+ valFn = e.h.fn(rtval, true, true)
+ }
+ mks := rv.MapKeys()
+
+ if e.h.Canonical {
+ e.kMapCanonical(rtkey, rv, mks, valFn)
+ ee.WriteMapEnd()
+ return
+ }
+
+ var keyTypeIsString = stringTypId == rt2id(rtkey0) // rtkeyid
+ if !keyTypeIsString {
+ for rtkey.Kind() == reflect.Ptr {
+ rtkey = rtkey.Elem()
+ }
+ if rtkey.Kind() != reflect.Interface {
+ // rtkeyid = rt2id(rtkey)
+ keyFn = e.h.fn(rtkey, true, true)
+ }
+ }
+
+ // for j, lmks := 0, len(mks); j < lmks; j++ {
+ for j := range mks {
+ if e.esep {
+ ee.WriteMapElemKey()
+ }
+ if keyTypeIsString {
+ if e.h.StringToRaw {
+ ee.EncodeStringBytesRaw(bytesView(mks[j].String()))
+ } else {
+ ee.EncodeStringEnc(cUTF8, mks[j].String())
+ }
+ } else {
+ e.encodeValue(mks[j], keyFn, true)
+ }
+ if e.esep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mks[j]), valFn, true)
+
+ }
+ ee.WriteMapEnd()
+}
+
+func (e *Encoder) kMapCanonical(rtkey reflect.Type, rv reflect.Value, mks []reflect.Value, valFn *codecFn) {
+ ee := e.e
+ elemsep := e.esep
+ // we previously did out-of-band if an extension was registered.
+ // This is not necessary, as the natural kind is sufficient for ordering.
+
+ switch rtkey.Kind() {
+ case reflect.Bool:
+ mksv := make([]boolRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = k.Bool()
+ }
+ sort.Sort(boolRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeBool(mksv[i].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ case reflect.String:
+ mksv := make([]stringRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = k.String()
+ }
+ sort.Sort(stringRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ if e.h.StringToRaw {
+ ee.EncodeStringBytesRaw(bytesView(mksv[i].v))
+ } else {
+ ee.EncodeStringEnc(cUTF8, mksv[i].v)
+ }
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr:
+ mksv := make([]uintRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = k.Uint()
+ }
+ sort.Sort(uintRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeUint(mksv[i].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+ mksv := make([]intRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = k.Int()
+ }
+ sort.Sort(intRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeInt(mksv[i].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ case reflect.Float32:
+ mksv := make([]floatRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = k.Float()
+ }
+ sort.Sort(floatRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeFloat32(float32(mksv[i].v))
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ case reflect.Float64:
+ mksv := make([]floatRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = k.Float()
+ }
+ sort.Sort(floatRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeFloat64(mksv[i].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ case reflect.Struct:
+ if rv.Type() == timeTyp {
+ mksv := make([]timeRv, len(mks))
+ for i, k := range mks {
+ v := &mksv[i]
+ v.r = k
+ v.v = rv2i(k).(time.Time)
+ }
+ sort.Sort(timeRvSlice(mksv))
+ for i := range mksv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ ee.EncodeTime(mksv[i].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true)
+ }
+ break
+ }
+ fallthrough
+ default:
+ // out-of-band
+ // first encode each key to a []byte first, then sort them, then record
+ var mksv []byte = make([]byte, 0, len(mks)*16) // temporary byte slice for the encoding
+ e2 := NewEncoderBytes(&mksv, e.hh)
+ mksbv := make([]bytesRv, len(mks))
+ for i, k := range mks {
+ v := &mksbv[i]
+ l := len(mksv)
+ e2.MustEncode(k)
+ v.r = k
+ v.v = mksv[l:]
+ }
+ sort.Sort(bytesRvSlice(mksbv))
+ for j := range mksbv {
+ if elemsep {
+ ee.WriteMapElemKey()
+ }
+ e.asis(mksbv[j].v)
+ if elemsep {
+ ee.WriteMapElemValue()
+ }
+ e.encodeValue(rv.MapIndex(mksbv[j].r), valFn, true)
+ }
+ }
+}
+
+// // --------------------------------------------------
+
+type encWriterSwitch struct {
+ // wi *ioEncWriter
+ wb bytesEncAppender
+ wf *bufioEncWriter
+ // typ entryType
+ bytes bool // encoding to []byte
+ esep bool // whether it has elem separators
+ isas bool // whether e.as != nil
+ js bool // is json encoder?
+ be bool // is binary encoder?
+ _ [2]byte // padding
+ // _ [2]uint64 // padding
+ // _ uint64 // padding
+}
+
+func (z *encWriterSwitch) writeb(s []byte) {
+ if z.bytes {
+ z.wb.writeb(s)
+ } else {
+ z.wf.writeb(s)
+ }
+}
+func (z *encWriterSwitch) writestr(s string) {
+ if z.bytes {
+ z.wb.writestr(s)
+ } else {
+ z.wf.writestr(s)
+ }
+}
+func (z *encWriterSwitch) writen1(b1 byte) {
+ if z.bytes {
+ z.wb.writen1(b1)
+ } else {
+ z.wf.writen1(b1)
+ }
+}
+func (z *encWriterSwitch) writen2(b1, b2 byte) {
+ if z.bytes {
+ z.wb.writen2(b1, b2)
+ } else {
+ z.wf.writen2(b1, b2)
+ }
+}
+func (z *encWriterSwitch) endErr() error {
+ if z.bytes {
+ return z.wb.endErr()
+ }
+ return z.wf.endErr()
+}
+
+func (z *encWriterSwitch) end() {
+ if err := z.endErr(); err != nil {
+ panic(err)
+ }
+}
+
+/*
+
+// ------------------------------------------
+func (z *encWriterSwitch) writeb(s []byte) {
+ switch z.typ {
+ case entryTypeBytes:
+ z.wb.writeb(s)
+ case entryTypeIo:
+ z.wi.writeb(s)
+ default:
+ z.wf.writeb(s)
+ }
+}
+func (z *encWriterSwitch) writestr(s string) {
+ switch z.typ {
+ case entryTypeBytes:
+ z.wb.writestr(s)
+ case entryTypeIo:
+ z.wi.writestr(s)
+ default:
+ z.wf.writestr(s)
+ }
+}
+func (z *encWriterSwitch) writen1(b1 byte) {
+ switch z.typ {
+ case entryTypeBytes:
+ z.wb.writen1(b1)
+ case entryTypeIo:
+ z.wi.writen1(b1)
+ default:
+ z.wf.writen1(b1)
+ }
+}
+func (z *encWriterSwitch) writen2(b1, b2 byte) {
+ switch z.typ {
+ case entryTypeBytes:
+ z.wb.writen2(b1, b2)
+ case entryTypeIo:
+ z.wi.writen2(b1, b2)
+ default:
+ z.wf.writen2(b1, b2)
+ }
+}
+func (z *encWriterSwitch) end() {
+ switch z.typ {
+ case entryTypeBytes:
+ z.wb.end()
+ case entryTypeIo:
+ z.wi.end()
+ default:
+ z.wf.end()
+ }
+}
+
+// ------------------------------------------
+func (z *encWriterSwitch) writeb(s []byte) {
+ if z.bytes {
+ z.wb.writeb(s)
+ } else {
+ z.wi.writeb(s)
+ }
+}
+func (z *encWriterSwitch) writestr(s string) {
+ if z.bytes {
+ z.wb.writestr(s)
+ } else {
+ z.wi.writestr(s)
+ }
+}
+func (z *encWriterSwitch) writen1(b1 byte) {
+ if z.bytes {
+ z.wb.writen1(b1)
+ } else {
+ z.wi.writen1(b1)
+ }
+}
+func (z *encWriterSwitch) writen2(b1, b2 byte) {
+ if z.bytes {
+ z.wb.writen2(b1, b2)
+ } else {
+ z.wi.writen2(b1, b2)
+ }
+}
+func (z *encWriterSwitch) end() {
+ if z.bytes {
+ z.wb.end()
+ } else {
+ z.wi.end()
+ }
+}
+
+*/
+
+// Encoder writes an object to an output stream in a supported format.
+//
+// Encoder is NOT safe for concurrent use i.e. a Encoder cannot be used
+// concurrently in multiple goroutines.
+//
+// However, as Encoder could be allocation heavy to initialize, a Reset method is provided
+// so its state can be reused to decode new input streams repeatedly.
+// This is the idiomatic way to use.
+type Encoder struct {
+ panicHdl
+ // hopefully, reduce derefencing cost by laying the encWriter inside the Encoder
+ e encDriver
+
+ // NOTE: Encoder shouldn't call it's write methods,
+ // as the handler MAY need to do some coordination.
+ w *encWriterSwitch
+
+ // bw *bufio.Writer
+ as encDriverAsis
+
+ err error
+
+ h *BasicHandle
+ hh Handle
+ // ---- cpu cache line boundary? + 3
+ encWriterSwitch
+
+ ci set
+
+ b [(5 * 8)]byte // for encoding chan or (non-addressable) [N]byte
+
+ // ---- writable fields during execution --- *try* to keep in sep cache line
+
+ // ---- cpu cache line boundary?
+ // b [scratchByteArrayLen]byte
+ // _ [cacheLineSize - scratchByteArrayLen]byte // padding
+ // b [cacheLineSize - (8 * 0)]byte // used for encoding a chan or (non-addressable) array of bytes
+}
+
+// NewEncoder returns an Encoder for encoding into an io.Writer.
+//
+// For efficiency, Users are encouraged to configure WriterBufferSize on the handle
+// OR pass in a memory buffered writer (eg bufio.Writer, bytes.Buffer).
+func NewEncoder(w io.Writer, h Handle) *Encoder {
+ e := newEncoder(h)
+ e.Reset(w)
+ return e
+}
+
+// NewEncoderBytes returns an encoder for encoding directly and efficiently
+// into a byte slice, using zero-copying to temporary slices.
+//
+// It will potentially replace the output byte slice pointed to.
+// After encoding, the out parameter contains the encoded contents.
+func NewEncoderBytes(out *[]byte, h Handle) *Encoder {
+ e := newEncoder(h)
+ e.ResetBytes(out)
+ return e
+}
+
+func newEncoder(h Handle) *Encoder {
+ e := &Encoder{h: basicHandle(h), err: errEncoderNotInitialized}
+ e.bytes = true
+ if useFinalizers {
+ runtime.SetFinalizer(e, (*Encoder).finalize)
+ // xdebugf(">>>> new(Encoder) with finalizer")
+ }
+ e.w = &e.encWriterSwitch
+ e.hh = h
+ e.esep = h.hasElemSeparators()
+
+ return e
+}
+
+func (e *Encoder) resetCommon() {
+ // e.w = &e.encWriterSwitch
+ if e.e == nil || e.hh.recreateEncDriver(e.e) {
+ e.e = e.hh.newEncDriver(e)
+ e.as, e.isas = e.e.(encDriverAsis)
+ // e.cr, _ = e.e.(containerStateRecv)
+ }
+ e.be = e.hh.isBinary()
+ _, e.js = e.hh.(*JsonHandle)
+ e.e.reset()
+ e.err = nil
+}
+
+// Reset resets the Encoder with a new output stream.
+//
+// This accommodates using the state of the Encoder,
+// where it has "cached" information about sub-engines.
+func (e *Encoder) Reset(w io.Writer) {
+ if w == nil {
+ return
+ }
+ // var ok bool
+ e.bytes = false
+ if e.wf == nil {
+ e.wf = new(bufioEncWriter)
+ }
+ // e.typ = entryTypeUnset
+ // if e.h.WriterBufferSize > 0 {
+ // // bw := bufio.NewWriterSize(w, e.h.WriterBufferSize)
+ // // e.wi.bw = bw
+ // // e.wi.sw = bw
+ // // e.wi.fw = bw
+ // // e.wi.ww = bw
+ // if e.wf == nil {
+ // e.wf = new(bufioEncWriter)
+ // }
+ // e.wf.reset(w, e.h.WriterBufferSize)
+ // e.typ = entryTypeBufio
+ // } else {
+ // if e.wi == nil {
+ // e.wi = new(ioEncWriter)
+ // }
+ // e.wi.reset(w)
+ // e.typ = entryTypeIo
+ // }
+ e.wf.reset(w, e.h.WriterBufferSize)
+ // e.typ = entryTypeBufio
+
+ // e.w = e.wi
+ e.resetCommon()
+}
+
+// ResetBytes resets the Encoder with a new destination output []byte.
+func (e *Encoder) ResetBytes(out *[]byte) {
+ if out == nil {
+ return
+ }
+ var in []byte = *out
+ if in == nil {
+ in = make([]byte, defEncByteBufSize)
+ }
+ e.bytes = true
+ // e.typ = entryTypeBytes
+ e.wb.reset(in, out)
+ // e.w = &e.wb
+ e.resetCommon()
+}
+
+// Encode writes an object into a stream.
+//
+// Encoding can be configured via the struct tag for the fields.
+// The key (in the struct tags) that we look at is configurable.
+//
+// By default, we look up the "codec" key in the struct field's tags,
+// and fall bak to the "json" key if "codec" is absent.
+// That key in struct field's tag value is the key name,
+// followed by an optional comma and options.
+//
+// To set an option on all fields (e.g. omitempty on all fields), you
+// can create a field called _struct, and set flags on it. The options
+// which can be set on _struct are:
+// - omitempty: so all fields are omitted if empty
+// - toarray: so struct is encoded as an array
+// - int: so struct key names are encoded as signed integers (instead of strings)
+// - uint: so struct key names are encoded as unsigned integers (instead of strings)
+// - float: so struct key names are encoded as floats (instead of strings)
+//
+// More details on these below.
+//
+// Struct values "usually" encode as maps. Each exported struct field is encoded unless:
+// - the field's tag is "-", OR
+// - the field is empty (empty or the zero value) and its tag specifies the "omitempty" option.
+//
+// When encoding as a map, the first string in the tag (before the comma)
+// is the map key string to use when encoding.
+// ...
+// This key is typically encoded as a string.
+// However, there are instances where the encoded stream has mapping keys encoded as numbers.
+// For example, some cbor streams have keys as integer codes in the stream, but they should map
+// to fields in a structured object. Consequently, a struct is the natural representation in code.
+// For these, configure the struct to encode/decode the keys as numbers (instead of string).
+// This is done with the int,uint or float option on the _struct field (see above).
+//
+// However, struct values may encode as arrays. This happens when:
+// - StructToArray Encode option is set, OR
+// - the tag on the _struct field sets the "toarray" option
+//
+// Note that omitempty is ignored when encoding struct values as arrays,
+// as an entry must be encoded for each field, to maintain its position.
+//
+// Values with types that implement MapBySlice are encoded as stream maps.
+//
+// The empty values (for omitempty option) are false, 0, any nil pointer
+// or interface value, and any array, slice, map, or string of length zero.
+//
+// Anonymous fields are encoded inline except:
+// - the struct tag specifies a replacement name (first value)
+// - the field is of an interface type
+//
+// Examples:
+//
+// // NOTE: 'json:' can be used as struct tag key, in place 'codec:' below.
+// type MyStruct struct {
+// _struct bool `codec:",omitempty"` //set omitempty for every field
+// Field1 string `codec:"-"` //skip this field
+// Field2 int `codec:"myName"` //Use key "myName" in encode stream
+// Field3 int32 `codec:",omitempty"` //use key "Field3". Omit if empty.
+// Field4 bool `codec:"f4,omitempty"` //use key "f4". Omit if empty.
+// io.Reader //use key "Reader".
+// MyStruct `codec:"my1" //use key "my1".
+// MyStruct //inline it
+// ...
+// }
+//
+// type MyStruct struct {
+// _struct bool `codec:",toarray"` //encode struct as an array
+// }
+//
+// type MyStruct struct {
+// _struct bool `codec:",uint"` //encode struct with "unsigned integer" keys
+// Field1 string `codec:"1"` //encode Field1 key using: EncodeInt(1)
+// Field2 string `codec:"2"` //encode Field2 key using: EncodeInt(2)
+// }
+//
+// The mode of encoding is based on the type of the value. When a value is seen:
+// - If a Selfer, call its CodecEncodeSelf method
+// - If an extension is registered for it, call that extension function
+// - If implements encoding.(Binary|Text|JSON)Marshaler, call Marshal(Binary|Text|JSON) method
+// - Else encode it based on its reflect.Kind
+//
+// Note that struct field names and keys in map[string]XXX will be treated as symbols.
+// Some formats support symbols (e.g. binc) and will properly encode the string
+// only once in the stream, and use a tag to refer to it thereafter.
+func (e *Encoder) Encode(v interface{}) (err error) {
+ // tried to use closure, as runtime optimizes defer with no params.
+ // This seemed to be causing weird issues (like circular reference found, unexpected panic, etc).
+ // Also, see https://github.com/golang/go/issues/14939#issuecomment-417836139
+ // defer func() { e.deferred(&err) }() }
+ // { x, y := e, &err; defer func() { x.deferred(y) }() }
+ if e.err != nil {
+ return e.err
+ }
+ if recoverPanicToErr {
+ defer func() {
+ // if error occurred during encoding, return that error;
+ // else if error occurred on end'ing (i.e. during flush), return that error.
+ err = e.w.endErr()
+ x := recover()
+ if x == nil {
+ e.err = err
+ } else {
+ panicValToErr(e, x, &e.err)
+ err = e.err
+ }
+ }()
+ }
+
+ // defer e.deferred(&err)
+ e.mustEncode(v)
+ return
+}
+
+// MustEncode is like Encode, but panics if unable to Encode.
+// This provides insight to the code location that triggered the error.
+func (e *Encoder) MustEncode(v interface{}) {
+ if e.err != nil {
+ panic(e.err)
+ }
+ e.mustEncode(v)
+}
+
+func (e *Encoder) mustEncode(v interface{}) {
+ if e.wf == nil {
+ e.encode(v)
+ e.e.atEndOfEncode()
+ e.w.end()
+ return
+ }
+
+ if e.wf.buf == nil {
+ e.wf.buf = e.wf.bytesBufPooler.get(e.wf.sz)
+ }
+ e.wf.calls++
+
+ e.encode(v)
+
+ e.wf.calls--
+
+ if e.wf.calls == 0 {
+ e.e.atEndOfEncode()
+ e.w.end()
+ if !e.h.ExplicitRelease {
+ e.wf.release()
+ }
+ }
+}
+
+// func (e *Encoder) deferred(err1 *error) {
+// e.w.end()
+// if recoverPanicToErr {
+// if x := recover(); x != nil {
+// panicValToErr(e, x, err1)
+// panicValToErr(e, x, &e.err)
+// }
+// }
+// }
+
+//go:noinline -- as it is run by finalizer
+func (e *Encoder) finalize() {
+ // xdebugf("finalizing Encoder")
+ e.Release()
+}
+
+// Release releases shared (pooled) resources.
+//
+// It is important to call Release() when done with an Encoder, so those resources
+// are released instantly for use by subsequently created Encoders.
+func (e *Encoder) Release() {
+ if e.wf != nil {
+ e.wf.release()
+ }
+}
+
+func (e *Encoder) encode(iv interface{}) {
+ // a switch with only concrete types can be optimized.
+ // consequently, we deal with nil and interfaces outside the switch.
+
+ if iv == nil || definitelyNil(iv) {
+ e.e.EncodeNil()
+ return
+ }
+
+ switch v := iv.(type) {
+ // case nil:
+ // case Selfer:
+ case Raw:
+ e.rawBytes(v)
+ case reflect.Value:
+ e.encodeValue(v, nil, true)
+
+ case string:
+ if e.h.StringToRaw {
+ e.e.EncodeStringBytesRaw(bytesView(v))
+ } else {
+ e.e.EncodeStringEnc(cUTF8, v)
+ }
+ case bool:
+ e.e.EncodeBool(v)
+ case int:
+ e.e.EncodeInt(int64(v))
+ case int8:
+ e.e.EncodeInt(int64(v))
+ case int16:
+ e.e.EncodeInt(int64(v))
+ case int32:
+ e.e.EncodeInt(int64(v))
+ case int64:
+ e.e.EncodeInt(v)
+ case uint:
+ e.e.EncodeUint(uint64(v))
+ case uint8:
+ e.e.EncodeUint(uint64(v))
+ case uint16:
+ e.e.EncodeUint(uint64(v))
+ case uint32:
+ e.e.EncodeUint(uint64(v))
+ case uint64:
+ e.e.EncodeUint(v)
+ case uintptr:
+ e.e.EncodeUint(uint64(v))
+ case float32:
+ e.e.EncodeFloat32(v)
+ case float64:
+ e.e.EncodeFloat64(v)
+ case time.Time:
+ e.e.EncodeTime(v)
+ case []uint8:
+ e.e.EncodeStringBytesRaw(v)
+
+ case *Raw:
+ e.rawBytes(*v)
+
+ case *string:
+ if e.h.StringToRaw {
+ e.e.EncodeStringBytesRaw(bytesView(*v))
+ } else {
+ e.e.EncodeStringEnc(cUTF8, *v)
+ }
+ case *bool:
+ e.e.EncodeBool(*v)
+ case *int:
+ e.e.EncodeInt(int64(*v))
+ case *int8:
+ e.e.EncodeInt(int64(*v))
+ case *int16:
+ e.e.EncodeInt(int64(*v))
+ case *int32:
+ e.e.EncodeInt(int64(*v))
+ case *int64:
+ e.e.EncodeInt(*v)
+ case *uint:
+ e.e.EncodeUint(uint64(*v))
+ case *uint8:
+ e.e.EncodeUint(uint64(*v))
+ case *uint16:
+ e.e.EncodeUint(uint64(*v))
+ case *uint32:
+ e.e.EncodeUint(uint64(*v))
+ case *uint64:
+ e.e.EncodeUint(*v)
+ case *uintptr:
+ e.e.EncodeUint(uint64(*v))
+ case *float32:
+ e.e.EncodeFloat32(*v)
+ case *float64:
+ e.e.EncodeFloat64(*v)
+ case *time.Time:
+ e.e.EncodeTime(*v)
+
+ case *[]uint8:
+ e.e.EncodeStringBytesRaw(*v)
+
+ default:
+ if v, ok := iv.(Selfer); ok {
+ v.CodecEncodeSelf(e)
+ } else if !fastpathEncodeTypeSwitch(iv, e) {
+ // checkfastpath=true (not false), as underlying slice/map type may be fast-path
+ e.encodeValue(reflect.ValueOf(iv), nil, true)
+ }
+ }
+}
+
+func (e *Encoder) encodeValue(rv reflect.Value, fn *codecFn, checkFastpath bool) {
+ // if a valid fn is passed, it MUST BE for the dereferenced type of rv
+ var sptr uintptr
+ var rvp reflect.Value
+ var rvpValid bool
+TOP:
+ switch rv.Kind() {
+ case reflect.Ptr:
+ if rv.IsNil() {
+ e.e.EncodeNil()
+ return
+ }
+ rvpValid = true
+ rvp = rv
+ rv = rv.Elem()
+ if e.h.CheckCircularRef && rv.Kind() == reflect.Struct {
+ // TODO: Movable pointers will be an issue here. Future problem.
+ sptr = rv.UnsafeAddr()
+ break TOP
+ }
+ goto TOP
+ case reflect.Interface:
+ if rv.IsNil() {
+ e.e.EncodeNil()
+ return
+ }
+ rv = rv.Elem()
+ goto TOP
+ case reflect.Slice, reflect.Map:
+ if rv.IsNil() {
+ e.e.EncodeNil()
+ return
+ }
+ case reflect.Invalid, reflect.Func:
+ e.e.EncodeNil()
+ return
+ }
+
+ if sptr != 0 && (&e.ci).add(sptr) {
+ e.errorf("circular reference found: # %d", sptr)
+ }
+
+ if fn == nil {
+ rt := rv.Type()
+ // always pass checkCodecSelfer=true, in case T or ****T is passed, where *T is a Selfer
+ fn = e.h.fn(rt, checkFastpath, true)
+ }
+ if fn.i.addrE {
+ if rvpValid {
+ fn.fe(e, &fn.i, rvp)
+ } else if rv.CanAddr() {
+ fn.fe(e, &fn.i, rv.Addr())
+ } else {
+ rv2 := reflect.New(rv.Type())
+ rv2.Elem().Set(rv)
+ fn.fe(e, &fn.i, rv2)
+ }
+ } else {
+ fn.fe(e, &fn.i, rv)
+ }
+ if sptr != 0 {
+ (&e.ci).remove(sptr)
+ }
+}
+
+// func (e *Encoder) marshal(bs []byte, fnerr error, asis bool, c charEncoding) {
+// if fnerr != nil {
+// panic(fnerr)
+// }
+// if bs == nil {
+// e.e.EncodeNil()
+// } else if asis {
+// e.asis(bs)
+// } else {
+// e.e.EncodeStringBytesRaw(bs)
+// }
+// }
+
+func (e *Encoder) marshalUtf8(bs []byte, fnerr error) {
+ if fnerr != nil {
+ panic(fnerr)
+ }
+ if bs == nil {
+ e.e.EncodeNil()
+ } else {
+ e.e.EncodeStringEnc(cUTF8, stringView(bs))
+ }
+}
+
+func (e *Encoder) marshalAsis(bs []byte, fnerr error) {
+ if fnerr != nil {
+ panic(fnerr)
+ }
+ if bs == nil {
+ e.e.EncodeNil()
+ } else {
+ e.asis(bs)
+ }
+}
+
+func (e *Encoder) marshalRaw(bs []byte, fnerr error) {
+ if fnerr != nil {
+ panic(fnerr)
+ }
+ if bs == nil {
+ e.e.EncodeNil()
+ } else {
+ e.e.EncodeStringBytesRaw(bs)
+ }
+}
+
+func (e *Encoder) asis(v []byte) {
+ if e.isas {
+ e.as.EncodeAsis(v)
+ } else {
+ e.w.writeb(v)
+ }
+}
+
+func (e *Encoder) rawBytes(vv Raw) {
+ v := []byte(vv)
+ if !e.h.Raw {
+ e.errorf("Raw values cannot be encoded: %v", v)
+ }
+ e.asis(v)
+}
+
+func (e *Encoder) wrapErr(v interface{}, err *error) {
+ *err = encodeError{codecError{name: e.hh.Name(), err: v}}
+}
+
+func encStructFieldKey(encName string, ee encDriver, w *encWriterSwitch,
+ keyType valueType, encNameAsciiAlphaNum bool, js bool) {
+ var m must
+ // use if-else-if, not switch (which compiles to binary-search)
+ // since keyType is typically valueTypeString, branch prediction is pretty good.
+ if keyType == valueTypeString {
+ if js && encNameAsciiAlphaNum { // keyType == valueTypeString
+ // w.writen1('"')
+ // w.writestr(encName)
+ // w.writen1('"')
+ // ----
+ // w.writestr(`"` + encName + `"`)
+ // ----
+ // do concat myself, so it is faster than the generic string concat
+ b := make([]byte, len(encName)+2)
+ copy(b[1:], encName)
+ b[0] = '"'
+ b[len(b)-1] = '"'
+ w.writeb(b)
+ } else { // keyType == valueTypeString
+ ee.EncodeStringEnc(cUTF8, encName)
+ }
+ } else if keyType == valueTypeInt {
+ ee.EncodeInt(m.Int(strconv.ParseInt(encName, 10, 64)))
+ } else if keyType == valueTypeUint {
+ ee.EncodeUint(m.Uint(strconv.ParseUint(encName, 10, 64)))
+ } else if keyType == valueTypeFloat {
+ ee.EncodeFloat64(m.Float(strconv.ParseFloat(encName, 64)))
+ }
+}
+
+// func encStringAsRawBytesMaybe(ee encDriver, s string, stringToRaw bool) {
+// if stringToRaw {
+// ee.EncodeStringBytesRaw(bytesView(s))
+// } else {
+// ee.EncodeStringEnc(cUTF8, s)
+// }
+// }
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/fast-path.not.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/fast-path.not.go
new file mode 100644
index 00000000000..93cb754a037
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/fast-path.not.go
@@ -0,0 +1,39 @@
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+package codec
+
+import "reflect"
+
+// fastpath was removed for safety reasons
+
+const fastpathEnabled = false
+
+func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { return false }
+func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { return false }
+func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { return false }
+func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { return false }
+func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool { return false }
+
+type fastpathT struct{}
+type fastpathE struct {
+ rtid uintptr
+ rt reflect.Type
+ encfn func(*Encoder, *codecFnInfo, reflect.Value)
+ decfn func(*Decoder, *codecFnInfo, reflect.Value)
+}
+type fastpathA [0]fastpathE
+
+func (x fastpathA) index(rtid uintptr) int { return -1 }
+
+func (_ fastpathT) DecSliceUint8V(v []uint8, canChange bool, d *Decoder) (_ []uint8, changed bool) {
+ fn := d.h.fn(uint8SliceTyp, true, true)
+ d.kSlice(&fn.i, reflect.ValueOf(&v).Elem())
+ return v, true
+}
+
+var fastpathAV fastpathA
+var fastpathTV fastpathT
+
+// ----
+// type TestMammoth2Wrapper struct{}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-dec-array.go.tmpl b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-dec-array.go.tmpl
new file mode 100644
index 00000000000..790e914e13c
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-dec-array.go.tmpl
@@ -0,0 +1,78 @@
+{{var "v"}} := {{if not isArray}}*{{end}}{{ .Varname }}
+{{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}}{{if not isArray}}
+var {{var "c"}} bool {{/* // changed */}}
+_ = {{var "c"}}{{end}}
+if {{var "l"}} == 0 {
+ {{if isSlice }}if {{var "v"}} == nil {
+ {{var "v"}} = []{{ .Typ }}{}
+ {{var "c"}} = true
+ } else if len({{var "v"}}) != 0 {
+ {{var "v"}} = {{var "v"}}[:0]
+ {{var "c"}} = true
+ } {{else if isChan }}if {{var "v"}} == nil {
+ {{var "v"}} = make({{ .CTyp }}, 0)
+ {{var "c"}} = true
+ } {{end}}
+} else {
+ {{var "hl"}} := {{var "l"}} > 0
+ var {{var "rl"}} int
+ _ = {{var "rl"}}
+ {{if isSlice }} if {{var "hl"}} {
+ if {{var "l"}} > cap({{var "v"}}) {
+ {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
+ if {{var "rl"}} <= cap({{var "v"}}) {
+ {{var "v"}} = {{var "v"}}[:{{var "rl"}}]
+ } else {
+ {{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
+ }
+ {{var "c"}} = true
+ } else if {{var "l"}} != len({{var "v"}}) {
+ {{var "v"}} = {{var "v"}}[:{{var "l"}}]
+ {{var "c"}} = true
+ }
+ } {{end}}
+ var {{var "j"}} int
+ // var {{var "dn"}} bool
+ for {{var "j"}} = 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ { // bounds-check-elimination
+ {{if not isArray}} if {{var "j"}} == 0 && {{var "v"}} == nil {
+ if {{var "hl"}} {
+ {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
+ } else {
+ {{var "rl"}} = {{if isSlice}}8{{else if isChan}}64{{end}}
+ }
+ {{var "v"}} = make({{if isSlice}}[]{{ .Typ }}{{else if isChan}}{{.CTyp}}{{end}}, {{var "rl"}})
+ {{var "c"}} = true
+ }{{end}}
+ {{var "h"}}.ElemContainerState({{var "j"}})
+ {{/* {{var "dn"}} = r.TryDecodeAsNil() */}}{{/* commented out, as decLineVar handles this already each time */}}
+ {{if isChan}}{{ $x := printf "%[1]vvcx%[2]v" .TempVar .Rand }}var {{$x}} {{ .Typ }}
+ {{ decLineVar $x }}
+ {{var "v"}} <- {{ $x }}
+ // println(">>>> sending ", {{ $x }}, " into ", {{var "v"}}) // TODO: remove this
+ {{else}}{{/* // if indefinite, etc, then expand the slice if necessary */}}
+ var {{var "db"}} bool
+ if {{var "j"}} >= len({{var "v"}}) {
+ {{if isSlice }} {{var "v"}} = append({{var "v"}}, {{ zero }})
+ {{var "c"}} = true
+ {{else}} z.DecArrayCannotExpand(len(v), {{var "j"}}+1); {{var "db"}} = true
+ {{end}}
+ }
+ if {{var "db"}} {
+ z.DecSwallow()
+ } else {
+ {{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
+ }
+ {{end}}
+ }
+ {{if isSlice}} if {{var "j"}} < len({{var "v"}}) {
+ {{var "v"}} = {{var "v"}}[:{{var "j"}}]
+ {{var "c"}} = true
+ } else if {{var "j"}} == 0 && {{var "v"}} == nil {
+ {{var "v"}} = make([]{{ .Typ }}, 0)
+ {{var "c"}} = true
+ } {{end}}
+}
+{{var "h"}}.End()
+{{if not isArray }}if {{var "c"}} {
+ *{{ .Varname }} = {{var "v"}}
+}{{end}}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-dec-map.go.tmpl b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-dec-map.go.tmpl
new file mode 100644
index 00000000000..8323b54940d
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-dec-map.go.tmpl
@@ -0,0 +1,42 @@
+{{var "v"}} := *{{ .Varname }}
+{{var "l"}} := r.ReadMapStart()
+{{var "bh"}} := z.DecBasicHandle()
+if {{var "v"}} == nil {
+ {{var "rl"}} := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }})
+ {{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}})
+ *{{ .Varname }} = {{var "v"}}
+}
+var {{var "mk"}} {{ .KTyp }}
+var {{var "mv"}} {{ .Typ }}
+var {{var "mg"}}, {{var "mdn"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool
+if {{var "bh"}}.MapValueReset {
+ {{if decElemKindPtr}}{{var "mg"}} = true
+ {{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true }
+ {{else if not decElemKindImmutable}}{{var "mg"}} = true
+ {{end}} }
+if {{var "l"}} != 0 {
+{{var "hl"}} := {{var "l"}} > 0
+ for {{var "j"}} := 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ {
+ r.ReadMapElemKey() {{/* z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }}) */}}
+ {{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
+{{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} {
+ {{var "mk"}} = string({{var "bv"}})
+ }{{ end }}{{if decElemKindPtr}}
+ {{var "ms"}} = true{{end}}
+ if {{var "mg"}} {
+ {{if decElemKindPtr}}{{var "mv"}}, {{var "mok"}} = {{var "v"}}[{{var "mk"}}]
+ if {{var "mok"}} {
+ {{var "ms"}} = false
+ } {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}}
+ } {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
+ r.ReadMapElemValue() {{/* z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }}) */}}
+ {{var "mdn"}} = false
+ {{ $x := printf "%vmv%v" .TempVar .Rand }}{{ $y := printf "%vmdn%v" .TempVar .Rand }}{{ decLineVar $x $y }}
+ if {{var "mdn"}} {
+ if {{ var "bh" }}.DeleteOnNilMapValue { delete({{var "v"}}, {{var "mk"}}) } else { {{var "v"}}[{{var "mk"}}] = {{decElemZero}} }
+ } else if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
+ {{var "v"}}[{{var "mk"}}] = {{var "mv"}}
+ }
+}
+} // else len==0: TODO: Should we clear map entries?
+r.ReadMapEnd() {{/* z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) */}}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-enc-chan.go.tmpl b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-enc-chan.go.tmpl
new file mode 100644
index 00000000000..4249588a3cf
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-enc-chan.go.tmpl
@@ -0,0 +1,27 @@
+{{.Label}}:
+switch timeout{{.Sfx}} := z.EncBasicHandle().ChanRecvTimeout; {
+case timeout{{.Sfx}} == 0: // only consume available
+ for {
+ select {
+ case b{{.Sfx}} := <-{{.Chan}}:
+ {{ .Slice }} = append({{.Slice}}, b{{.Sfx}})
+ default:
+ break {{.Label}}
+ }
+ }
+case timeout{{.Sfx}} > 0: // consume until timeout
+ tt{{.Sfx}} := time.NewTimer(timeout{{.Sfx}})
+ for {
+ select {
+ case b{{.Sfx}} := <-{{.Chan}}:
+ {{.Slice}} = append({{.Slice}}, b{{.Sfx}})
+ case <-tt{{.Sfx}}.C:
+ // close(tt.C)
+ break {{.Label}}
+ }
+ }
+default: // consume until close
+ for b{{.Sfx}} := range {{.Chan}} {
+ {{.Slice}} = append({{.Slice}}, b{{.Sfx}})
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-helper.generated.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-helper.generated.go
new file mode 100644
index 00000000000..2a7d1aab70b
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-helper.generated.go
@@ -0,0 +1,343 @@
+// comment this out // + build ignore
+
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+// Code generated from gen-helper.go.tmpl - DO NOT EDIT.
+
+package codec
+
+import (
+ "encoding"
+ "reflect"
+)
+
+// GenVersion is the current version of codecgen.
+const GenVersion = 10
+
+// This file is used to generate helper code for codecgen.
+// The values here i.e. genHelper(En|De)coder are not to be used directly by
+// library users. They WILL change continuously and without notice.
+//
+// To help enforce this, we create an unexported type with exported members.
+// The only way to get the type is via the one exported type that we control (somewhat).
+//
+// When static codecs are created for types, they will use this value
+// to perform encoding or decoding of primitives or known slice or map types.
+
+// GenHelperEncoder is exported so that it can be used externally by codecgen.
+//
+// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
+func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) {
+ ge = genHelperEncoder{e: e}
+ ee = genHelperEncDriver{encDriver: e.e}
+ return
+}
+
+// GenHelperDecoder is exported so that it can be used externally by codecgen.
+//
+// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
+func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) {
+ gd = genHelperDecoder{d: d}
+ dd = genHelperDecDriver{decDriver: d.d}
+ return
+}
+
+type genHelperEncDriver struct {
+ encDriver
+}
+
+func (x genHelperEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {}
+func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
+ encStructFieldKey(s, x.encDriver, nil, keyType, false, false)
+}
+func (x genHelperEncDriver) EncodeSymbol(s string) {
+ x.encDriver.EncodeStringEnc(cUTF8, s)
+}
+
+type genHelperDecDriver struct {
+ decDriver
+ C checkOverflow
+}
+
+func (x genHelperDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {}
+func (x genHelperDecDriver) DecStructFieldKey(keyType valueType, buf *[decScratchByteArrayLen]byte) []byte {
+ return decStructFieldKey(x.decDriver, keyType, buf)
+}
+func (x genHelperDecDriver) DecodeInt(bitsize uint8) (i int64) {
+ return x.C.IntV(x.decDriver.DecodeInt64(), bitsize)
+}
+func (x genHelperDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
+ return x.C.UintV(x.decDriver.DecodeUint64(), bitsize)
+}
+func (x genHelperDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
+ f = x.DecodeFloat64()
+ if chkOverflow32 && chkOvf.Float32(f) {
+ panicv.errorf("float32 overflow: %v", f)
+ }
+ return
+}
+func (x genHelperDecDriver) DecodeFloat32As64() (f float64) {
+ f = x.DecodeFloat64()
+ if chkOvf.Float32(f) {
+ panicv.errorf("float32 overflow: %v", f)
+ }
+ return
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+type genHelperEncoder struct {
+ M must
+ e *Encoder
+ F fastpathT
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+type genHelperDecoder struct {
+ C checkOverflow
+ d *Decoder
+ F fastpathT
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncBasicHandle() *BasicHandle {
+ return f.e.h
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncBinary() bool {
+ return f.e.be // f.e.hh.isBinaryEncoding()
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) IsJSONHandle() bool {
+ return f.e.js
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncFallback(iv interface{}) {
+ // println(">>>>>>>>> EncFallback")
+ // f.e.encodeI(iv, false, false)
+ f.e.encodeValue(reflect.ValueOf(iv), nil, false)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
+ bs, fnerr := iv.MarshalText()
+ f.e.marshalUtf8(bs, fnerr)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) {
+ bs, fnerr := iv.MarshalJSON()
+ f.e.marshalAsis(bs, fnerr)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
+ bs, fnerr := iv.MarshalBinary()
+ f.e.marshalRaw(bs, fnerr)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncRaw(iv Raw) { f.e.rawBytes(iv) }
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: builtin no longer supported - so we make this method a no-op,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperEncoder) TimeRtidIfBinc() (v uintptr) { return }
+
+// func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
+// if _, ok := f.e.hh.(*BincHandle); ok {
+// return timeTypId
+// }
+// }
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) I2Rtid(v interface{}) uintptr {
+ return i2rtid(v)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) Extension(rtid uintptr) (xfn *extTypeTagFn) {
+ return f.e.h.getExt(rtid)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncExtension(v interface{}, xfFn *extTypeTagFn) {
+ f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) WriteStr(s string) {
+ f.e.w.writestr(s)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) BytesView(v string) []byte { return bytesView(v) }
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: No longer used,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperEncoder) HasExtensions() bool {
+ return len(f.e.h.extHandle) != 0
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: No longer used,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperEncoder) EncExt(v interface{}) (r bool) {
+ if xfFn := f.e.h.getExt(i2rtid(v)); xfFn != nil {
+ f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e)
+ return true
+ }
+ return false
+}
+
+// ---------------- DECODER FOLLOWS -----------------
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecBasicHandle() *BasicHandle {
+ return f.d.h
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecBinary() bool {
+ return f.d.be // f.d.hh.isBinaryEncoding()
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecSwallow() { f.d.swallow() }
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecScratchBuffer() []byte {
+ return f.d.b[:]
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecScratchArrayBuffer() *[decScratchByteArrayLen]byte {
+ return &f.d.b
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) {
+ // println(">>>>>>>>> DecFallback")
+ rv := reflect.ValueOf(iv)
+ if chkPtr {
+ rv = f.d.ensureDecodeable(rv)
+ }
+ f.d.decodeValue(rv, nil, false)
+ // f.d.decodeValueFallback(rv)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecSliceHelperStart() (decSliceHelper, int) {
+ return f.d.decSliceHelperStart()
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecStructFieldNotFound(index int, name string) {
+ f.d.structFieldNotFound(index, name)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) {
+ f.d.arrayCannotExpand(sliceLen, streamLen)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) {
+ fnerr := tm.UnmarshalText(f.d.d.DecodeStringAsBytes())
+ if fnerr != nil {
+ panic(fnerr)
+ }
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
+ // bs := f.dd.DecodeStringAsBytes()
+ // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself.
+ fnerr := tm.UnmarshalJSON(f.d.nextValueBytes())
+ if fnerr != nil {
+ panic(fnerr)
+ }
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) {
+ fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, true))
+ if fnerr != nil {
+ panic(fnerr)
+ }
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecRaw() []byte { return f.d.rawBytes() }
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: builtin no longer supported - so we make this method a no-op,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperDecoder) TimeRtidIfBinc() (v uintptr) { return }
+
+// func (f genHelperDecoder) TimeRtidIfBinc() uintptr {
+// // Note: builtin is no longer supported - so make this a no-op
+// if _, ok := f.d.hh.(*BincHandle); ok {
+// return timeTypId
+// }
+// return 0
+// }
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) IsJSONHandle() bool {
+ return f.d.js
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) I2Rtid(v interface{}) uintptr {
+ return i2rtid(v)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) Extension(rtid uintptr) (xfn *extTypeTagFn) {
+ return f.d.h.getExt(rtid)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecExtension(v interface{}, xfFn *extTypeTagFn) {
+ f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: No longer used,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperDecoder) HasExtensions() bool {
+ return len(f.d.h.extHandle) != 0
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: No longer used,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
+ if xfFn := f.d.h.getExt(i2rtid(v)); xfFn != nil {
+ f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext)
+ return true
+ }
+ return false
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int) {
+ return decInferLen(clen, maxlen, unit)
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: no longer used,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperDecoder) StringView(v []byte) string { return stringView(v) }
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-helper.go.tmpl b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-helper.go.tmpl
new file mode 100644
index 00000000000..f5d0634e6a1
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-helper.go.tmpl
@@ -0,0 +1,308 @@
+// comment this out // + build ignore
+
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+// Code generated from gen-helper.go.tmpl - DO NOT EDIT.
+
+package codec
+
+import (
+ "encoding"
+ "reflect"
+)
+
+// GenVersion is the current version of codecgen.
+const GenVersion = {{ .Version }}
+
+// This file is used to generate helper code for codecgen.
+// The values here i.e. genHelper(En|De)coder are not to be used directly by
+// library users. They WILL change continuously and without notice.
+//
+// To help enforce this, we create an unexported type with exported members.
+// The only way to get the type is via the one exported type that we control (somewhat).
+//
+// When static codecs are created for types, they will use this value
+// to perform encoding or decoding of primitives or known slice or map types.
+
+// GenHelperEncoder is exported so that it can be used externally by codecgen.
+//
+// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
+func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) {
+ ge = genHelperEncoder{e: e}
+ ee = genHelperEncDriver{encDriver: e.e}
+ return
+}
+
+// GenHelperDecoder is exported so that it can be used externally by codecgen.
+//
+// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
+func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) {
+ gd = genHelperDecoder{d: d}
+ dd = genHelperDecDriver{decDriver: d.d}
+ return
+}
+
+type genHelperEncDriver struct {
+ encDriver
+}
+
+func (x genHelperEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {}
+func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
+ encStructFieldKey(s, x.encDriver, nil, keyType, false, false)
+}
+func (x genHelperEncDriver) EncodeSymbol(s string) {
+ x.encDriver.EncodeStringEnc(cUTF8, s)
+}
+
+type genHelperDecDriver struct {
+ decDriver
+ C checkOverflow
+}
+
+func (x genHelperDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {}
+func (x genHelperDecDriver) DecStructFieldKey(keyType valueType, buf *[decScratchByteArrayLen]byte) []byte {
+ return decStructFieldKey(x.decDriver, keyType, buf)
+}
+func (x genHelperDecDriver) DecodeInt(bitsize uint8) (i int64) {
+ return x.C.IntV(x.decDriver.DecodeInt64(), bitsize)
+}
+func (x genHelperDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
+ return x.C.UintV(x.decDriver.DecodeUint64(), bitsize)
+}
+func (x genHelperDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
+ f = x.DecodeFloat64()
+ if chkOverflow32 && chkOvf.Float32(f) {
+ panicv.errorf("float32 overflow: %v", f)
+ }
+ return
+}
+func (x genHelperDecDriver) DecodeFloat32As64() (f float64) {
+ f = x.DecodeFloat64()
+ if chkOvf.Float32(f) {
+ panicv.errorf("float32 overflow: %v", f)
+ }
+ return
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+type genHelperEncoder struct {
+ M must
+ e *Encoder
+ F fastpathT
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+type genHelperDecoder struct {
+ C checkOverflow
+ d *Decoder
+ F fastpathT
+}
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncBasicHandle() *BasicHandle {
+ return f.e.h
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncBinary() bool {
+ return f.e.be // f.e.hh.isBinaryEncoding()
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) IsJSONHandle() bool {
+ return f.e.js
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncFallback(iv interface{}) {
+ // println(">>>>>>>>> EncFallback")
+ // f.e.encodeI(iv, false, false)
+ f.e.encodeValue(reflect.ValueOf(iv), nil, false)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
+ bs, fnerr := iv.MarshalText()
+ f.e.marshalUtf8(bs, fnerr)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) {
+ bs, fnerr := iv.MarshalJSON()
+ f.e.marshalAsis(bs, fnerr)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
+ bs, fnerr := iv.MarshalBinary()
+ f.e.marshalRaw(bs, fnerr)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncRaw(iv Raw) { f.e.rawBytes(iv) }
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: builtin no longer supported - so we make this method a no-op,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperEncoder) TimeRtidIfBinc() (v uintptr) { return }
+// func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
+// if _, ok := f.e.hh.(*BincHandle); ok {
+// return timeTypId
+// }
+// }
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) I2Rtid(v interface{}) uintptr {
+ return i2rtid(v)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) Extension(rtid uintptr) (xfn *extTypeTagFn) {
+ return f.e.h.getExt(rtid)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) EncExtension(v interface{}, xfFn *extTypeTagFn) {
+ f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) WriteStr(s string) {
+ f.e.w.writestr(s)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperEncoder) BytesView(v string) []byte { return bytesView(v) }
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: No longer used,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperEncoder) HasExtensions() bool {
+ return len(f.e.h.extHandle) != 0
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: No longer used,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperEncoder) EncExt(v interface{}) (r bool) {
+ if xfFn := f.e.h.getExt(i2rtid(v)); xfFn != nil {
+ f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e)
+ return true
+ }
+ return false
+}
+
+// ---------------- DECODER FOLLOWS -----------------
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecBasicHandle() *BasicHandle {
+ return f.d.h
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecBinary() bool {
+ return f.d.be // f.d.hh.isBinaryEncoding()
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecSwallow() { f.d.swallow() }
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecScratchBuffer() []byte {
+ return f.d.b[:]
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecScratchArrayBuffer() *[decScratchByteArrayLen]byte {
+ return &f.d.b
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) {
+ // println(">>>>>>>>> DecFallback")
+ rv := reflect.ValueOf(iv)
+ if chkPtr {
+ rv = f.d.ensureDecodeable(rv)
+ }
+ f.d.decodeValue(rv, nil, false)
+ // f.d.decodeValueFallback(rv)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecSliceHelperStart() (decSliceHelper, int) {
+ return f.d.decSliceHelperStart()
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecStructFieldNotFound(index int, name string) {
+ f.d.structFieldNotFound(index, name)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) {
+ f.d.arrayCannotExpand(sliceLen, streamLen)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) {
+ fnerr := tm.UnmarshalText(f.d.d.DecodeStringAsBytes())
+ if fnerr != nil {
+ panic(fnerr)
+ }
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
+ // bs := f.dd.DecodeStringAsBytes()
+ // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself.
+ fnerr := tm.UnmarshalJSON(f.d.nextValueBytes())
+ if fnerr != nil {
+ panic(fnerr)
+ }
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) {
+ fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, true))
+ if fnerr != nil {
+ panic(fnerr)
+ }
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecRaw() []byte { return f.d.rawBytes() }
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: builtin no longer supported - so we make this method a no-op,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperDecoder) TimeRtidIfBinc() (v uintptr) { return }
+// func (f genHelperDecoder) TimeRtidIfBinc() uintptr {
+// // Note: builtin is no longer supported - so make this a no-op
+// if _, ok := f.d.hh.(*BincHandle); ok {
+// return timeTypId
+// }
+// return 0
+// }
+
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) IsJSONHandle() bool {
+ return f.d.js
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) I2Rtid(v interface{}) uintptr {
+ return i2rtid(v)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) Extension(rtid uintptr) (xfn *extTypeTagFn) {
+ return f.d.h.getExt(rtid)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecExtension(v interface{}, xfFn *extTypeTagFn) {
+ f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: No longer used,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperDecoder) HasExtensions() bool {
+ return len(f.d.h.extHandle) != 0
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: No longer used,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
+ if xfFn := f.d.h.getExt(i2rtid(v)); xfFn != nil {
+ f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext)
+ return true
+ }
+ return false
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int) {
+ return decInferLen(clen, maxlen, unit)
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+//
+// Deprecated: no longer used,
+// but leave in-place so that old generated files continue to work without regeneration.
+func (f genHelperDecoder) StringView(v []byte) string { return stringView(v) }
+
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-internal.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-internal.go
new file mode 100644
index 00000000000..8b52e229536
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-internal.go
@@ -0,0 +1,288 @@
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+package codec
+
+import (
+ "bytes"
+ "errors"
+ "go/format"
+ "io"
+ "strings"
+ "sync"
+ "text/template"
+)
+
+const genVersion = 10
+
+func genInternalEncCommandAsString(s string, vname string) string {
+ switch s {
+ case "uint", "uint8", "uint16", "uint32", "uint64":
+ return "ee.EncodeUint(uint64(" + vname + "))"
+ case "int", "int8", "int16", "int32", "int64":
+ return "ee.EncodeInt(int64(" + vname + "))"
+ case "string":
+ return "if e.h.StringToRaw { ee.EncodeStringBytesRaw(bytesView(" + vname + ")) " +
+ "} else { ee.EncodeStringEnc(cUTF8, " + vname + ") }"
+ case "float32":
+ return "ee.EncodeFloat32(" + vname + ")"
+ case "float64":
+ return "ee.EncodeFloat64(" + vname + ")"
+ case "bool":
+ return "ee.EncodeBool(" + vname + ")"
+ // case "symbol":
+ // return "ee.EncodeSymbol(" + vname + ")"
+ default:
+ return "e.encode(" + vname + ")"
+ }
+}
+
+func genInternalDecCommandAsString(s string) string {
+ switch s {
+ case "uint":
+ return "uint(chkOvf.UintV(dd.DecodeUint64(), uintBitsize))"
+ case "uint8":
+ return "uint8(chkOvf.UintV(dd.DecodeUint64(), 8))"
+ case "uint16":
+ return "uint16(chkOvf.UintV(dd.DecodeUint64(), 16))"
+ case "uint32":
+ return "uint32(chkOvf.UintV(dd.DecodeUint64(), 32))"
+ case "uint64":
+ return "dd.DecodeUint64()"
+ case "uintptr":
+ return "uintptr(chkOvf.UintV(dd.DecodeUint64(), uintBitsize))"
+ case "int":
+ return "int(chkOvf.IntV(dd.DecodeInt64(), intBitsize))"
+ case "int8":
+ return "int8(chkOvf.IntV(dd.DecodeInt64(), 8))"
+ case "int16":
+ return "int16(chkOvf.IntV(dd.DecodeInt64(), 16))"
+ case "int32":
+ return "int32(chkOvf.IntV(dd.DecodeInt64(), 32))"
+ case "int64":
+ return "dd.DecodeInt64()"
+
+ case "string":
+ return "dd.DecodeString()"
+ case "float32":
+ return "float32(chkOvf.Float32V(dd.DecodeFloat64()))"
+ case "float64":
+ return "dd.DecodeFloat64()"
+ case "bool":
+ return "dd.DecodeBool()"
+ default:
+ panic(errors.New("gen internal: unknown type for decode: " + s))
+ }
+}
+
+func genInternalZeroValue(s string) string {
+ switch s {
+ case "interface{}", "interface {}":
+ return "nil"
+ case "bool":
+ return "false"
+ case "string":
+ return `""`
+ default:
+ return "0"
+ }
+}
+
+var genInternalNonZeroValueIdx [5]uint64
+var genInternalNonZeroValueStrs = [2][5]string{
+ {`"string-is-an-interface"`, "true", `"some-string"`, "11.1", "33"},
+ {`"string-is-an-interface-2"`, "true", `"some-string-2"`, "22.2", "44"},
+}
+
+func genInternalNonZeroValue(s string) string {
+ switch s {
+ case "interface{}", "interface {}":
+ genInternalNonZeroValueIdx[0]++
+ return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[0]%2][0] // return string, to remove ambiguity
+ case "bool":
+ genInternalNonZeroValueIdx[1]++
+ return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[1]%2][1]
+ case "string":
+ genInternalNonZeroValueIdx[2]++
+ return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[2]%2][2]
+ case "float32", "float64", "float", "double":
+ genInternalNonZeroValueIdx[3]++
+ return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[3]%2][3]
+ default:
+ genInternalNonZeroValueIdx[4]++
+ return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[4]%2][4]
+ }
+}
+
+func genInternalSortType(s string, elem bool) string {
+ for _, v := range [...]string{"int", "uint", "float", "bool", "string"} {
+ if strings.HasPrefix(s, v) {
+ if elem {
+ if v == "int" || v == "uint" || v == "float" {
+ return v + "64"
+ } else {
+ return v
+ }
+ }
+ return v + "Slice"
+ }
+ }
+ panic("sorttype: unexpected type: " + s)
+}
+
+type genV struct {
+ // genV is either a primitive (Primitive != "") or a map (MapKey != "") or a slice
+ MapKey string
+ Elem string
+ Primitive string
+ Size int
+}
+
+type genInternal struct {
+ Version int
+ Values []genV
+}
+
+func (x genInternal) FastpathLen() (l int) {
+ for _, v := range x.Values {
+ if v.Primitive == "" && !(v.MapKey == "" && v.Elem == "uint8") {
+ l++
+ }
+ }
+ return
+}
+
+// var genInternalMu sync.Mutex
+var genInternalV = genInternal{Version: genVersion}
+var genInternalTmplFuncs template.FuncMap
+var genInternalOnce sync.Once
+
+func genInternalInit() {
+ types := [...]string{
+ "interface{}",
+ "string",
+ "float32",
+ "float64",
+ "uint",
+ "uint8",
+ "uint16",
+ "uint32",
+ "uint64",
+ "uintptr",
+ "int",
+ "int8",
+ "int16",
+ "int32",
+ "int64",
+ "bool",
+ }
+ // keep as slice, so it is in specific iteration order.
+ // Initial order was uint64, string, interface{}, int, int64
+ mapvaltypes := [...]string{
+ "interface{}",
+ "string",
+ "uint",
+ "uint8",
+ "uint16",
+ "uint32",
+ "uint64",
+ "uintptr",
+ "int",
+ "int8",
+ "int16",
+ "int32",
+ "int64",
+ "float32",
+ "float64",
+ "bool",
+ }
+ wordSizeBytes := int(intBitsize) / 8
+
+ mapvaltypes2 := map[string]int{
+ "interface{}": 2 * wordSizeBytes,
+ "string": 2 * wordSizeBytes,
+ "uint": 1 * wordSizeBytes,
+ "uint8": 1,
+ "uint16": 2,
+ "uint32": 4,
+ "uint64": 8,
+ "uintptr": 1 * wordSizeBytes,
+ "int": 1 * wordSizeBytes,
+ "int8": 1,
+ "int16": 2,
+ "int32": 4,
+ "int64": 8,
+ "float32": 4,
+ "float64": 8,
+ "bool": 1,
+ }
+ var gt = genInternal{Version: genVersion}
+
+ // For each slice or map type, there must be a (symmetrical) Encode and Decode fast-path function
+ for _, s := range types {
+ gt.Values = append(gt.Values, genV{Primitive: s, Size: mapvaltypes2[s]})
+ // if s != "uint8" { // do not generate fast path for slice of bytes. Treat specially already.
+ // gt.Values = append(gt.Values, genV{Elem: s, Size: mapvaltypes2[s]})
+ // }
+ gt.Values = append(gt.Values, genV{Elem: s, Size: mapvaltypes2[s]})
+ if _, ok := mapvaltypes2[s]; !ok {
+ gt.Values = append(gt.Values, genV{MapKey: s, Elem: s, Size: 2 * mapvaltypes2[s]})
+ }
+ for _, ms := range mapvaltypes {
+ gt.Values = append(gt.Values, genV{MapKey: s, Elem: ms, Size: mapvaltypes2[s] + mapvaltypes2[ms]})
+ }
+ }
+
+ funcs := make(template.FuncMap)
+ // funcs["haspfx"] = strings.HasPrefix
+ funcs["encmd"] = genInternalEncCommandAsString
+ funcs["decmd"] = genInternalDecCommandAsString
+ funcs["zerocmd"] = genInternalZeroValue
+ funcs["nonzerocmd"] = genInternalNonZeroValue
+ funcs["hasprefix"] = strings.HasPrefix
+ funcs["sorttype"] = genInternalSortType
+
+ genInternalV = gt
+ genInternalTmplFuncs = funcs
+}
+
+// genInternalGoFile is used to generate source files from templates.
+// It is run by the program author alone.
+// Unfortunately, it has to be exported so that it can be called from a command line tool.
+// *** DO NOT USE ***
+func genInternalGoFile(r io.Reader, w io.Writer) (err error) {
+ genInternalOnce.Do(genInternalInit)
+
+ gt := genInternalV
+
+ t := template.New("").Funcs(genInternalTmplFuncs)
+
+ tmplstr, err := io.ReadAll(r)
+ if err != nil {
+ return
+ }
+
+ if t, err = t.Parse(string(tmplstr)); err != nil {
+ return
+ }
+
+ var out bytes.Buffer
+ err = t.Execute(&out, gt)
+ if err != nil {
+ return
+ }
+
+ bout, err := format.Source(out.Bytes())
+ if err != nil {
+ if _, err := w.Write(out.Bytes()); err != nil {
+ return err
+ }
+ // write out if error, so we can still see.
+ // w.Write(bout) // write out if error, as much as possible, so we can still see.
+ return
+ }
+ if _, err := w.Write(bout); err != nil {
+ return err
+ }
+ return
+}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen.generated.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen.generated.go
new file mode 100644
index 00000000000..2178efd5b71
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen.generated.go
@@ -0,0 +1,165 @@
+//go:build codecgen.exec
+// +build codecgen.exec
+
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+package codec
+
+// DO NOT EDIT. THIS FILE IS AUTO-GENERATED FROM gen-dec-(map|array).go.tmpl
+
+const genDecMapTmpl = `
+{{var "v"}} := *{{ .Varname }}
+{{var "l"}} := r.ReadMapStart()
+{{var "bh"}} := z.DecBasicHandle()
+if {{var "v"}} == nil {
+ {{var "rl"}} := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }})
+ {{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}})
+ *{{ .Varname }} = {{var "v"}}
+}
+var {{var "mk"}} {{ .KTyp }}
+var {{var "mv"}} {{ .Typ }}
+var {{var "mg"}}, {{var "mdn"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool
+if {{var "bh"}}.MapValueReset {
+ {{if decElemKindPtr}}{{var "mg"}} = true
+ {{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true }
+ {{else if not decElemKindImmutable}}{{var "mg"}} = true
+ {{end}} }
+if {{var "l"}} != 0 {
+{{var "hl"}} := {{var "l"}} > 0
+ for {{var "j"}} := 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ {
+ r.ReadMapElemKey() {{/* z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }}) */}}
+ {{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
+{{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} {
+ {{var "mk"}} = string({{var "bv"}})
+ }{{ end }}{{if decElemKindPtr}}
+ {{var "ms"}} = true{{end}}
+ if {{var "mg"}} {
+ {{if decElemKindPtr}}{{var "mv"}}, {{var "mok"}} = {{var "v"}}[{{var "mk"}}]
+ if {{var "mok"}} {
+ {{var "ms"}} = false
+ } {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}}
+ } {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
+ r.ReadMapElemValue() {{/* z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }}) */}}
+ {{var "mdn"}} = false
+ {{ $x := printf "%vmv%v" .TempVar .Rand }}{{ $y := printf "%vmdn%v" .TempVar .Rand }}{{ decLineVar $x $y }}
+ if {{var "mdn"}} {
+ if {{ var "bh" }}.DeleteOnNilMapValue { delete({{var "v"}}, {{var "mk"}}) } else { {{var "v"}}[{{var "mk"}}] = {{decElemZero}} }
+ } else if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
+ {{var "v"}}[{{var "mk"}}] = {{var "mv"}}
+ }
+}
+} // else len==0: TODO: Should we clear map entries?
+r.ReadMapEnd() {{/* z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) */}}
+`
+
+const genDecListTmpl = `
+{{var "v"}} := {{if not isArray}}*{{end}}{{ .Varname }}
+{{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}}{{if not isArray}}
+var {{var "c"}} bool {{/* // changed */}}
+_ = {{var "c"}}{{end}}
+if {{var "l"}} == 0 {
+ {{if isSlice }}if {{var "v"}} == nil {
+ {{var "v"}} = []{{ .Typ }}{}
+ {{var "c"}} = true
+ } else if len({{var "v"}}) != 0 {
+ {{var "v"}} = {{var "v"}}[:0]
+ {{var "c"}} = true
+ } {{else if isChan }}if {{var "v"}} == nil {
+ {{var "v"}} = make({{ .CTyp }}, 0)
+ {{var "c"}} = true
+ } {{end}}
+} else {
+ {{var "hl"}} := {{var "l"}} > 0
+ var {{var "rl"}} int
+ _ = {{var "rl"}}
+ {{if isSlice }} if {{var "hl"}} {
+ if {{var "l"}} > cap({{var "v"}}) {
+ {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
+ if {{var "rl"}} <= cap({{var "v"}}) {
+ {{var "v"}} = {{var "v"}}[:{{var "rl"}}]
+ } else {
+ {{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
+ }
+ {{var "c"}} = true
+ } else if {{var "l"}} != len({{var "v"}}) {
+ {{var "v"}} = {{var "v"}}[:{{var "l"}}]
+ {{var "c"}} = true
+ }
+ } {{end}}
+ var {{var "j"}} int
+ // var {{var "dn"}} bool
+ for {{var "j"}} = 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ { // bounds-check-elimination
+ {{if not isArray}} if {{var "j"}} == 0 && {{var "v"}} == nil {
+ if {{var "hl"}} {
+ {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
+ } else {
+ {{var "rl"}} = {{if isSlice}}8{{else if isChan}}64{{end}}
+ }
+ {{var "v"}} = make({{if isSlice}}[]{{ .Typ }}{{else if isChan}}{{.CTyp}}{{end}}, {{var "rl"}})
+ {{var "c"}} = true
+ }{{end}}
+ {{var "h"}}.ElemContainerState({{var "j"}})
+ {{/* {{var "dn"}} = r.TryDecodeAsNil() */}}{{/* commented out, as decLineVar handles this already each time */}}
+ {{if isChan}}{{ $x := printf "%[1]vvcx%[2]v" .TempVar .Rand }}var {{$x}} {{ .Typ }}
+ {{ decLineVar $x }}
+ {{var "v"}} <- {{ $x }}
+ // println(">>>> sending ", {{ $x }}, " into ", {{var "v"}}) // TODO: remove this
+ {{else}}{{/* // if indefinite, etc, then expand the slice if necessary */}}
+ var {{var "db"}} bool
+ if {{var "j"}} >= len({{var "v"}}) {
+ {{if isSlice }} {{var "v"}} = append({{var "v"}}, {{ zero }})
+ {{var "c"}} = true
+ {{else}} z.DecArrayCannotExpand(len(v), {{var "j"}}+1); {{var "db"}} = true
+ {{end}}
+ }
+ if {{var "db"}} {
+ z.DecSwallow()
+ } else {
+ {{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
+ }
+ {{end}}
+ }
+ {{if isSlice}} if {{var "j"}} < len({{var "v"}}) {
+ {{var "v"}} = {{var "v"}}[:{{var "j"}}]
+ {{var "c"}} = true
+ } else if {{var "j"}} == 0 && {{var "v"}} == nil {
+ {{var "v"}} = make([]{{ .Typ }}, 0)
+ {{var "c"}} = true
+ } {{end}}
+}
+{{var "h"}}.End()
+{{if not isArray }}if {{var "c"}} {
+ *{{ .Varname }} = {{var "v"}}
+}{{end}}
+`
+
+const genEncChanTmpl = `
+{{.Label}}:
+switch timeout{{.Sfx}} := z.EncBasicHandle().ChanRecvTimeout; {
+case timeout{{.Sfx}} == 0: // only consume available
+ for {
+ select {
+ case b{{.Sfx}} := <-{{.Chan}}:
+ {{ .Slice }} = append({{.Slice}}, b{{.Sfx}})
+ default:
+ break {{.Label}}
+ }
+ }
+case timeout{{.Sfx}} > 0: // consume until timeout
+ tt{{.Sfx}} := time.NewTimer(timeout{{.Sfx}})
+ for {
+ select {
+ case b{{.Sfx}} := <-{{.Chan}}:
+ {{.Slice}} = append({{.Slice}}, b{{.Sfx}})
+ case <-tt{{.Sfx}}.C:
+ // close(tt.C)
+ break {{.Label}}
+ }
+ }
+default: // consume until close
+ for b{{.Sfx}} := range {{.Chan}} {
+ {{.Slice}} = append({{.Slice}}, b{{.Sfx}})
+ }
+}
+`
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen.go
new file mode 100644
index 00000000000..92e631cad6e
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen.go
@@ -0,0 +1,1875 @@
+//go:build codecgen.exec
+// +build codecgen.exec
+
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+package codec
+
+import (
+ "encoding/base32"
+ "errors"
+ "fmt"
+ "io"
+ "math/rand"
+ "reflect"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+ "text/template"
+ "time"
+ "unicode"
+ "unicode/utf8"
+)
+
+// ---------------------------------------------------
+// codecgen supports the full cycle of reflection-based codec:
+// - RawExt
+// - Raw
+// - Extensions
+// - (Binary|Text|JSON)(Unm|M)arshal
+// - generic by-kind
+//
+// This means that, for dynamic things, we MUST use reflection to at least get the reflect.Type.
+// In those areas, we try to only do reflection or interface-conversion when NECESSARY:
+// - Extensions, only if Extensions are configured.
+//
+// However, codecgen doesn't support the following:
+// - Canonical option. (codecgen IGNORES it currently)
+// This is just because it has not been implemented.
+// - MissingFielder implementation.
+// If a type implements MissingFielder, it is completely ignored by codecgen.
+//
+// During encode/decode, Selfer takes precedence.
+// A type implementing Selfer will know how to encode/decode itself statically.
+//
+// The following field types are supported:
+//
+// array: [n]T
+// slice: []T
+// map: map[K]V
+// primitive: [u]int[n], float(32|64), bool, string
+// struct
+//
+// ---------------------------------------------------
+// Note that a Selfer cannot call (e|d).(En|De)code on itself,
+// as this will cause a circular reference, as (En|De)code will call Selfer methods.
+// Any type that implements Selfer must implement completely and not fallback to (En|De)code.
+//
+// In addition, code in this file manages the generation of fast-path implementations of
+// encode/decode of slices/maps of primitive keys/values.
+//
+// Users MUST re-generate their implementations whenever the code shape changes.
+// The generated code will panic if it was generated with a version older than the supporting library.
+// ---------------------------------------------------
+//
+// codec framework is very feature rich.
+// When encoding or decoding into an interface, it depends on the runtime type of the interface.
+// The type of the interface may be a named type, an extension, etc.
+// Consequently, we fallback to runtime codec for encoding/decoding interfaces.
+// In addition, we fallback for any value which cannot be guaranteed at runtime.
+// This allows us support ANY value, including any named types, specifically those which
+// do not implement our interfaces (e.g. Selfer).
+//
+// This explains some slowness compared to other code generation codecs (e.g. msgp).
+// This reduction in speed is only seen when your refers to interfaces,
+// e.g. type T struct { A interface{}; B []interface{}; C map[string]interface{} }
+//
+// codecgen will panic if the file was generated with an old version of the library in use.
+//
+// Note:
+//
+// It was a conscious decision to have gen.go always explicitly call EncodeNil or TryDecodeAsNil.
+// This way, there isn't a function call overhead just to see that we should not enter a block of code.
+//
+// GenVersion is the current version of codecgen.
+//
+// NOTE: Increment this value each time codecgen changes fundamentally.
+// Fundamental changes are:
+// - helper methods change (signature change, new ones added, some removed, etc)
+// - codecgen command line changes
+//
+// v1: Initial Version
+// v2:
+// v3: Changes for Kubernetes:
+//
+// changes in signature of some unpublished helper methods and codecgen cmdline arguments.
+//
+// v4: Removed separator support from (en|de)cDriver, and refactored codec(gen)
+// v5: changes to support faster json decoding. Let encoder/decoder maintain state of collections.
+// v6: removed unsafe from gen, and now uses codecgen.exec tag
+// v7:
+// v8: current - we now maintain compatibility with old generated code.
+// v9: skipped
+// v10: modified encDriver and decDriver interfaces. Remove deprecated methods after Jan 1, 2019
+const (
+ genCodecPkg = "codec1978"
+ genTempVarPfx = "yy"
+ genTopLevelVarName = "x"
+
+ // ignore canBeNil parameter, and always set to true.
+ // This is because nil can appear anywhere, so we should always check.
+ genAnythingCanBeNil = true
+
+ // if genUseOneFunctionForDecStructMap, make a single codecDecodeSelferFromMap function;
+ // else make codecDecodeSelferFromMap{LenPrefix,CheckBreak} so that conditionals
+ // are not executed a lot.
+ //
+ // From testing, it didn't make much difference in runtime, so keep as true (one function only)
+ genUseOneFunctionForDecStructMap = true
+)
+
+type genStructMapStyle uint8
+
+const (
+ genStructMapStyleConsolidated genStructMapStyle = iota
+ genStructMapStyleLenPrefix
+ genStructMapStyleCheckBreak
+)
+
+var (
+ errGenAllTypesSamePkg = errors.New("All types must be in the same package")
+ errGenExpectArrayOrMap = errors.New("unexpected type. Expecting array/map/slice")
+
+ // base64 requires 64 unique characters in Go 1.22+, which is not possible for Go identifiers.
+ genBase32enc = base32.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef")
+ genQNameRegex = regexp.MustCompile(`[A-Za-z_.]+`)
+)
+
+type genBuf struct {
+ buf []byte
+}
+
+func (x *genBuf) s(s string) *genBuf { x.buf = append(x.buf, s...); return x }
+func (x *genBuf) b(s []byte) *genBuf { x.buf = append(x.buf, s...); return x }
+func (x *genBuf) v() string { return string(x.buf) }
+func (x *genBuf) f(s string, args ...interface{}) { x.s(fmt.Sprintf(s, args...)) }
+func (x *genBuf) reset() {
+ if x.buf != nil {
+ x.buf = x.buf[:0]
+ }
+}
+
+// genRunner holds some state used during a Gen run.
+type genRunner struct {
+ w io.Writer // output
+ c uint64 // counter used for generating varsfx
+ t []reflect.Type // list of types to run selfer on
+
+ tc reflect.Type // currently running selfer on this type
+ te map[uintptr]bool // types for which the encoder has been created
+ td map[uintptr]bool // types for which the decoder has been created
+ cp string // codec import path
+
+ im map[string]reflect.Type // imports to add
+ imn map[string]string // package names of imports to add
+ imc uint64 // counter for import numbers
+
+ is map[reflect.Type]struct{} // types seen during import search
+ bp string // base PkgPath, for which we are generating for
+
+ cpfx string // codec package prefix
+
+ tm map[reflect.Type]struct{} // types for which enc/dec must be generated
+ ts []reflect.Type // types for which enc/dec must be generated
+
+ xs string // top level variable/constant suffix
+ hn string // fn helper type name
+
+ ti *TypeInfos
+ // rr *rand.Rand // random generator for file-specific types
+
+ nx bool // no extensions
+}
+
+// Gen will write a complete go file containing Selfer implementations for each
+// type passed. All the types must be in the same package.
+//
+// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINUOUSLY WITHOUT NOTICE.
+func Gen(w io.Writer, buildTags, pkgName, uid string, noExtensions bool,
+ ti *TypeInfos, typ ...reflect.Type) {
+ // All types passed to this method do not have a codec.Selfer method implemented directly.
+ // codecgen already checks the AST and skips any types that define the codec.Selfer methods.
+ // Consequently, there's no need to check and trim them if they implement codec.Selfer
+
+ if len(typ) == 0 {
+ return
+ }
+ x := genRunner{
+ w: w,
+ t: typ,
+ te: make(map[uintptr]bool),
+ td: make(map[uintptr]bool),
+ im: make(map[string]reflect.Type),
+ imn: make(map[string]string),
+ is: make(map[reflect.Type]struct{}),
+ tm: make(map[reflect.Type]struct{}),
+ ts: []reflect.Type{},
+ bp: genImportPath(typ[0]),
+ xs: uid,
+ ti: ti,
+ nx: noExtensions,
+ }
+ if x.ti == nil {
+ x.ti = defTypeInfos
+ }
+ if x.xs == "" {
+ rr := rand.New(rand.NewSource(time.Now().UnixNano()))
+ x.xs = strconv.FormatInt(rr.Int63n(9999), 10)
+ }
+
+ // gather imports first:
+ x.cp = genImportPath(reflect.TypeOf(x))
+ x.imn[x.cp] = genCodecPkg
+ for _, t := range typ {
+ // fmt.Printf("###########: PkgPath: '%v', Name: '%s'\n", genImportPath(t), t.Name())
+ if genImportPath(t) != x.bp {
+ panic(errGenAllTypesSamePkg)
+ }
+ x.genRefPkgs(t)
+ }
+ if buildTags != "" {
+ x.line("// +build " + buildTags)
+ x.line("")
+ }
+ x.line(`
+
+// Code generated by codecgen - DO NOT EDIT.
+
+`)
+ x.line("package " + pkgName)
+ x.line("")
+ x.line("import (")
+ if x.cp != x.bp {
+ x.cpfx = genCodecPkg + "."
+ x.linef("%s \"%s\"", genCodecPkg, x.cp)
+ }
+ // use a sorted set of im keys, so that we can get consistent output
+ imKeys := make([]string, 0, len(x.im))
+ for k := range x.im {
+ imKeys = append(imKeys, k)
+ }
+ sort.Strings(imKeys)
+ for _, k := range imKeys { // for k, _ := range x.im {
+ if k == x.imn[k] {
+ x.linef("\"%s\"", k)
+ } else {
+ x.linef("%s \"%s\"", x.imn[k], k)
+ }
+ }
+ // add required packages
+ for _, k := range [...]string{"runtime", "errors", "strconv"} { // "reflect", "fmt"
+ if _, ok := x.im[k]; !ok {
+ x.line("\"" + k + "\"")
+ }
+ }
+ x.line(")")
+ x.line("")
+
+ x.line("const (")
+ x.linef("// ----- content types ----")
+ x.linef("codecSelferCcUTF8%s = %v", x.xs, int64(cUTF8))
+ x.linef("codecSelferCcRAW%s = %v", x.xs, int64(cRAW))
+ x.linef("// ----- value types used ----")
+ for _, vt := range [...]valueType{
+ valueTypeArray, valueTypeMap, valueTypeString,
+ valueTypeInt, valueTypeUint, valueTypeFloat} {
+ x.linef("codecSelferValueType%s%s = %v", vt.String(), x.xs, int64(vt))
+ }
+
+ x.linef("codecSelferBitsize%s = uint8(32 << (^uint(0) >> 63))", x.xs)
+ x.line(")")
+ x.line("var (")
+ x.line("errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + " = errors.New(`only encoded map or array can be decoded into a struct`)")
+ x.line(")")
+ x.line("")
+
+ x.hn = "codecSelfer" + x.xs
+ x.line("type " + x.hn + " struct{}")
+ x.line("")
+
+ x.varsfxreset()
+ x.line("func init() {")
+ x.linef("if %sGenVersion != %v {", x.cpfx, genVersion)
+ x.line("_, file, _, _ := runtime.Caller(0)")
+ x.outf(`panic("codecgen version mismatch: current: %v, need " + strconv.FormatInt(int64(%sGenVersion), 10) + ". Re-generate file: " + file)`, genVersion, x.cpfx)
+ // x.out(`panic(fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v", `)
+ // x.linef(`%v, %sGenVersion, file))`, genVersion, x.cpfx)
+ x.linef("}")
+ x.line("if false { var _ byte = 0; // reference the types, but skip this branch at build/run time")
+ // x.line("_ = strconv.ParseInt")
+ var n int
+ // for k, t := range x.im {
+ for _, k := range imKeys {
+ t := x.im[k]
+ x.linef("var v%v %s.%s", n, x.imn[k], t.Name())
+ n++
+ }
+ if n > 0 {
+ x.out("_")
+ for i := 1; i < n; i++ {
+ x.out(", _")
+ }
+ x.out(" = v0")
+ for i := 1; i < n; i++ {
+ x.outf(", v%v", i)
+ }
+ }
+ x.line("} ") // close if false
+ x.line("}") // close init
+ x.line("")
+
+ // generate rest of type info
+ for _, t := range typ {
+ x.tc = t
+ x.selfer(true)
+ x.selfer(false)
+ }
+
+ for _, t := range x.ts {
+ rtid := rt2id(t)
+ // generate enc functions for all these slice/map types.
+ x.varsfxreset()
+ x.linef("func (x %s) enc%s(v %s%s, e *%sEncoder) {", x.hn, x.genMethodNameT(t), x.arr2str(t, "*"), x.genTypeName(t), x.cpfx)
+ x.genRequiredMethodVars(true)
+ switch t.Kind() {
+ case reflect.Array, reflect.Slice, reflect.Chan:
+ x.encListFallback("v", t)
+ case reflect.Map:
+ x.encMapFallback("v", t)
+ default:
+ panic(errGenExpectArrayOrMap)
+ }
+ x.line("}")
+ x.line("")
+
+ // generate dec functions for all these slice/map types.
+ x.varsfxreset()
+ x.linef("func (x %s) dec%s(v *%s, d *%sDecoder) {", x.hn, x.genMethodNameT(t), x.genTypeName(t), x.cpfx)
+ x.genRequiredMethodVars(false)
+ switch t.Kind() {
+ case reflect.Array, reflect.Slice, reflect.Chan:
+ x.decListFallback("v", rtid, t)
+ case reflect.Map:
+ x.decMapFallback("v", rtid, t)
+ default:
+ panic(errGenExpectArrayOrMap)
+ }
+ x.line("}")
+ x.line("")
+ }
+
+ x.line("")
+}
+
+func (x *genRunner) checkForSelfer(t reflect.Type, varname string) bool {
+ // return varname != genTopLevelVarName && t != x.tc
+ // the only time we checkForSelfer is if we are not at the TOP of the generated code.
+ return varname != genTopLevelVarName
+}
+
+func (x *genRunner) arr2str(t reflect.Type, s string) string {
+ if t.Kind() == reflect.Array {
+ return s
+ }
+ return ""
+}
+
+func (x *genRunner) genRequiredMethodVars(encode bool) {
+ x.line("var h " + x.hn)
+ if encode {
+ x.line("z, r := " + x.cpfx + "GenHelperEncoder(e)")
+ } else {
+ x.line("z, r := " + x.cpfx + "GenHelperDecoder(d)")
+ }
+ x.line("_, _, _ = h, z, r")
+}
+
+func (x *genRunner) genRefPkgs(t reflect.Type) {
+ if _, ok := x.is[t]; ok {
+ return
+ }
+ x.is[t] = struct{}{}
+ tpkg, tname := genImportPath(t), t.Name()
+ if tpkg != "" && tpkg != x.bp && tpkg != x.cp && tname != "" && tname[0] >= 'A' && tname[0] <= 'Z' {
+ if _, ok := x.im[tpkg]; !ok {
+ x.im[tpkg] = t
+ if idx := strings.LastIndex(tpkg, "/"); idx < 0 {
+ x.imn[tpkg] = tpkg
+ } else {
+ x.imc++
+ x.imn[tpkg] = "pkg" + strconv.FormatUint(x.imc, 10) + "_" + genGoIdentifier(tpkg[idx+1:], false)
+ }
+ }
+ }
+ switch t.Kind() {
+ case reflect.Array, reflect.Slice, reflect.Ptr, reflect.Chan:
+ x.genRefPkgs(t.Elem())
+ case reflect.Map:
+ x.genRefPkgs(t.Elem())
+ x.genRefPkgs(t.Key())
+ case reflect.Struct:
+ for i := 0; i < t.NumField(); i++ {
+ if fname := t.Field(i).Name; fname != "" && fname[0] >= 'A' && fname[0] <= 'Z' {
+ x.genRefPkgs(t.Field(i).Type)
+ }
+ }
+ }
+}
+
+func (x *genRunner) varsfx() string {
+ x.c++
+ return strconv.FormatUint(x.c, 10)
+}
+
+func (x *genRunner) varsfxreset() {
+ x.c = 0
+}
+
+func (x *genRunner) out(s string) {
+ _, err := io.WriteString(x.w, s)
+ if err != nil {
+ panic(err)
+ }
+}
+
+func (x *genRunner) outf(s string, params ...interface{}) {
+ _, err := fmt.Fprintf(x.w, s, params...)
+ if err != nil {
+ panic(err)
+ }
+}
+
+func (x *genRunner) line(s string) {
+ x.out(s)
+ if len(s) == 0 || s[len(s)-1] != '\n' {
+ x.out("\n")
+ }
+}
+
+func (x *genRunner) linef(s string, params ...interface{}) {
+ x.outf(s, params...)
+ if len(s) == 0 || s[len(s)-1] != '\n' {
+ x.out("\n")
+ }
+}
+
+func (x *genRunner) genTypeName(t reflect.Type) (n string) {
+ // defer func() { fmt.Printf(">>>> ####: genTypeName: t: %v, name: '%s'\n", t, n) }()
+
+ // if the type has a PkgPath, which doesn't match the current package,
+ // then include it.
+ // We cannot depend on t.String() because it includes current package,
+ // or t.PkgPath because it includes full import path,
+ //
+ var ptrPfx string
+ for t.Kind() == reflect.Ptr {
+ ptrPfx += "*"
+ t = t.Elem()
+ }
+ if tn := t.Name(); tn != "" {
+ return ptrPfx + x.genTypeNamePrim(t)
+ }
+ switch t.Kind() {
+ case reflect.Map:
+ return ptrPfx + "map[" + x.genTypeName(t.Key()) + "]" + x.genTypeName(t.Elem())
+ case reflect.Slice:
+ return ptrPfx + "[]" + x.genTypeName(t.Elem())
+ case reflect.Array:
+ return ptrPfx + "[" + strconv.FormatInt(int64(t.Len()), 10) + "]" + x.genTypeName(t.Elem())
+ case reflect.Chan:
+ return ptrPfx + t.ChanDir().String() + " " + x.genTypeName(t.Elem())
+ default:
+ if t == intfTyp {
+ return ptrPfx + "interface{}"
+ } else {
+ return ptrPfx + x.genTypeNamePrim(t)
+ }
+ }
+}
+
+func (x *genRunner) genTypeNamePrim(t reflect.Type) (n string) {
+ if t.Name() == "" {
+ return t.String()
+ } else if genImportPath(t) == "" || genImportPath(t) == genImportPath(x.tc) {
+ return t.Name()
+ } else {
+ return x.imn[genImportPath(t)] + "." + t.Name()
+ // return t.String() // best way to get the package name inclusive
+ }
+}
+
+func (x *genRunner) genZeroValueR(t reflect.Type) string {
+ // if t is a named type, w
+ switch t.Kind() {
+ case reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func,
+ reflect.Slice, reflect.Map, reflect.Invalid:
+ return "nil"
+ case reflect.Bool:
+ return "false"
+ case reflect.String:
+ return `""`
+ case reflect.Struct, reflect.Array:
+ return x.genTypeName(t) + "{}"
+ default: // all numbers
+ return "0"
+ }
+}
+
+func (x *genRunner) genMethodNameT(t reflect.Type) (s string) {
+ return genMethodNameT(t, x.tc)
+}
+
+func (x *genRunner) selfer(encode bool) {
+ t := x.tc
+ t0 := t
+ // always make decode use a pointer receiver,
+ // and structs/arrays always use a ptr receiver (encode|decode)
+ isptr := !encode || t.Kind() == reflect.Array || (t.Kind() == reflect.Struct && t != timeTyp)
+ x.varsfxreset()
+
+ fnSigPfx := "func (" + genTopLevelVarName + " "
+ if isptr {
+ fnSigPfx += "*"
+ }
+ fnSigPfx += x.genTypeName(t)
+ x.out(fnSigPfx)
+
+ if isptr {
+ t = reflect.PtrTo(t)
+ }
+ if encode {
+ x.line(") CodecEncodeSelf(e *" + x.cpfx + "Encoder) {")
+ x.genRequiredMethodVars(true)
+ x.encVar(genTopLevelVarName, t)
+ } else {
+ x.line(") CodecDecodeSelf(d *" + x.cpfx + "Decoder) {")
+ x.genRequiredMethodVars(false)
+ // do not use decVar, as there is no need to check TryDecodeAsNil
+ // or way to elegantly handle that, and also setting it to a
+ // non-nil value doesn't affect the pointer passed.
+ // x.decVar(genTopLevelVarName, t, false)
+ x.dec(genTopLevelVarName, t0, true)
+ }
+ x.line("}")
+ x.line("")
+
+ if encode || t0.Kind() != reflect.Struct {
+ return
+ }
+
+ // write is containerMap
+ if genUseOneFunctionForDecStructMap {
+ x.out(fnSigPfx)
+ x.line(") codecDecodeSelfFromMap(l int, d *" + x.cpfx + "Decoder) {")
+ x.genRequiredMethodVars(false)
+ x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleConsolidated)
+ x.line("}")
+ x.line("")
+ } else {
+ x.out(fnSigPfx)
+ x.line(") codecDecodeSelfFromMapLenPrefix(l int, d *" + x.cpfx + "Decoder) {")
+ x.genRequiredMethodVars(false)
+ x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleLenPrefix)
+ x.line("}")
+ x.line("")
+
+ x.out(fnSigPfx)
+ x.line(") codecDecodeSelfFromMapCheckBreak(l int, d *" + x.cpfx + "Decoder) {")
+ x.genRequiredMethodVars(false)
+ x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleCheckBreak)
+ x.line("}")
+ x.line("")
+ }
+
+ // write containerArray
+ x.out(fnSigPfx)
+ x.line(") codecDecodeSelfFromArray(l int, d *" + x.cpfx + "Decoder) {")
+ x.genRequiredMethodVars(false)
+ x.decStructArray(genTopLevelVarName, "l", "return", rt2id(t0), t0)
+ x.line("}")
+ x.line("")
+
+}
+
+// used for chan, array, slice, map
+func (x *genRunner) xtraSM(varname string, t reflect.Type, encode, isptr bool) {
+ var ptrPfx, addrPfx string
+ if isptr {
+ ptrPfx = "*"
+ } else {
+ addrPfx = "&"
+ }
+ if encode {
+ x.linef("h.enc%s((%s%s)(%s), e)", x.genMethodNameT(t), ptrPfx, x.genTypeName(t), varname)
+ } else {
+ x.linef("h.dec%s((*%s)(%s%s), d)", x.genMethodNameT(t), x.genTypeName(t), addrPfx, varname)
+ }
+ x.registerXtraT(t)
+}
+
+func (x *genRunner) registerXtraT(t reflect.Type) {
+ // recursively register the types
+ if _, ok := x.tm[t]; ok {
+ return
+ }
+ var tkey reflect.Type
+ switch t.Kind() {
+ case reflect.Chan, reflect.Slice, reflect.Array:
+ case reflect.Map:
+ tkey = t.Key()
+ default:
+ return
+ }
+ x.tm[t] = struct{}{}
+ x.ts = append(x.ts, t)
+ // check if this refers to any xtra types eg. a slice of array: add the array
+ x.registerXtraT(t.Elem())
+ if tkey != nil {
+ x.registerXtraT(tkey)
+ }
+}
+
+// encVar will encode a variable.
+// The parameter, t, is the reflect.Type of the variable itself
+func (x *genRunner) encVar(varname string, t reflect.Type) {
+ // fmt.Printf(">>>>>> varname: %s, t: %v\n", varname, t)
+ var checkNil bool
+ switch t.Kind() {
+ case reflect.Ptr, reflect.Interface, reflect.Slice, reflect.Map, reflect.Chan:
+ checkNil = true
+ }
+ if checkNil {
+ x.linef("if %s == nil { r.EncodeNil() } else { ", varname)
+ }
+
+ switch t.Kind() {
+ case reflect.Ptr:
+ telem := t.Elem()
+ tek := telem.Kind()
+ if tek == reflect.Array || (tek == reflect.Struct && telem != timeTyp) {
+ x.enc(varname, genNonPtr(t))
+ break
+ }
+ i := x.varsfx()
+ x.line(genTempVarPfx + i + " := *" + varname)
+ x.enc(genTempVarPfx+i, genNonPtr(t))
+ case reflect.Struct, reflect.Array:
+ if t == timeTyp {
+ x.enc(varname, t)
+ break
+ }
+ i := x.varsfx()
+ x.line(genTempVarPfx + i + " := &" + varname)
+ x.enc(genTempVarPfx+i, t)
+ default:
+ x.enc(varname, t)
+ }
+
+ if checkNil {
+ x.line("}")
+ }
+
+}
+
+// enc will encode a variable (varname) of type t, where t represents T.
+// if t is !time.Time and t is of kind reflect.Struct or reflect.Array, varname is of type *T
+// (to prevent copying),
+// else t is of type T
+func (x *genRunner) enc(varname string, t reflect.Type) {
+ rtid := rt2id(t)
+ ti2 := x.ti.get(rtid, t)
+ // We call CodecEncodeSelf if one of the following are honored:
+ // - the type already implements Selfer, call that
+ // - the type has a Selfer implementation just created, use that
+ // - the type is in the list of the ones we will generate for, but it is not currently being generated
+
+ mi := x.varsfx()
+ // tptr := reflect.PtrTo(t)
+ tk := t.Kind()
+ if x.checkForSelfer(t, varname) {
+ if tk == reflect.Array || (tk == reflect.Struct && rtid != timeTypId) { // varname is of type *T
+ // if tptr.Implements(selferTyp) || t.Implements(selferTyp) {
+ if ti2.isFlag(typeInfoFlagIsZeroerPtr) || ti2.isFlag(typeInfoFlagIsZeroer) {
+ x.line(varname + ".CodecEncodeSelf(e)")
+ return
+ }
+ } else { // varname is of type T
+ if ti2.cs { // t.Implements(selferTyp) {
+ x.line(varname + ".CodecEncodeSelf(e)")
+ return
+ } else if ti2.csp { // tptr.Implements(selferTyp) {
+ x.linef("%ssf%s := &%s", genTempVarPfx, mi, varname)
+ x.linef("%ssf%s.CodecEncodeSelf(e)", genTempVarPfx, mi)
+ return
+ }
+ }
+
+ if _, ok := x.te[rtid]; ok {
+ x.line(varname + ".CodecEncodeSelf(e)")
+ return
+ }
+ }
+
+ inlist := false
+ for _, t0 := range x.t {
+ if t == t0 {
+ inlist = true
+ if x.checkForSelfer(t, varname) {
+ x.line(varname + ".CodecEncodeSelf(e)")
+ return
+ }
+ break
+ }
+ }
+
+ var rtidAdded bool
+ if t == x.tc {
+ x.te[rtid] = true
+ rtidAdded = true
+ }
+
+ // check if
+ // - type is time.Time, RawExt, Raw
+ // - the type implements (Text|JSON|Binary)(Unm|M)arshal
+
+ x.line("if false {") //start if block
+ defer func() { x.line("}") }() //end if block
+
+ if t == timeTyp {
+ x.linef("} else if !z.EncBasicHandle().TimeNotBuiltin { r.EncodeTime(%s)", varname)
+ // return
+ }
+ if t == rawTyp {
+ x.linef("} else { z.EncRaw(%s)", varname)
+ return
+ }
+ if t == rawExtTyp {
+ x.linef("} else { r.EncodeRawExt(%s, e)", varname)
+ return
+ }
+ // only check for extensions if the type is named, and has a packagePath.
+ var arrayOrStruct = tk == reflect.Array || tk == reflect.Struct // meaning varname if of type *T
+ if !x.nx && genImportPath(t) != "" && t.Name() != "" {
+ yy := fmt.Sprintf("%sxt%s", genTempVarPfx, mi)
+ x.linef("} else if %s := z.Extension(z.I2Rtid(%s)); %s != nil { z.EncExtension(%s, %s) ", yy, varname, yy, varname, yy)
+ }
+ if arrayOrStruct { // varname is of type *T
+ if ti2.bm || ti2.bmp { // t.Implements(binaryMarshalerTyp) || tptr.Implements(binaryMarshalerTyp) {
+ x.linef("} else if z.EncBinary() { z.EncBinaryMarshal(%v) ", varname)
+ }
+ if ti2.jm || ti2.jmp { // t.Implements(jsonMarshalerTyp) || tptr.Implements(jsonMarshalerTyp) {
+ x.linef("} else if !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(%v) ", varname)
+ } else if ti2.tm || ti2.tmp { // t.Implements(textMarshalerTyp) || tptr.Implements(textMarshalerTyp) {
+ x.linef("} else if !z.EncBinary() { z.EncTextMarshal(%v) ", varname)
+ }
+ } else { // varname is of type T
+ if ti2.bm { // t.Implements(binaryMarshalerTyp) {
+ x.linef("} else if z.EncBinary() { z.EncBinaryMarshal(%v) ", varname)
+ } else if ti2.bmp { // tptr.Implements(binaryMarshalerTyp) {
+ x.linef("} else if z.EncBinary() { z.EncBinaryMarshal(&%v) ", varname)
+ }
+ if ti2.jm { // t.Implements(jsonMarshalerTyp) {
+ x.linef("} else if !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(%v) ", varname)
+ } else if ti2.jmp { // tptr.Implements(jsonMarshalerTyp) {
+ x.linef("} else if !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(&%v) ", varname)
+ } else if ti2.tm { // t.Implements(textMarshalerTyp) {
+ x.linef("} else if !z.EncBinary() { z.EncTextMarshal(%v) ", varname)
+ } else if ti2.tmp { // tptr.Implements(textMarshalerTyp) {
+ x.linef("} else if !z.EncBinary() { z.EncTextMarshal(&%v) ", varname)
+ }
+ }
+ x.line("} else {")
+
+ switch t.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ x.line("r.EncodeInt(int64(" + varname + "))")
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ x.line("r.EncodeUint(uint64(" + varname + "))")
+ case reflect.Float32:
+ x.line("r.EncodeFloat32(float32(" + varname + "))")
+ case reflect.Float64:
+ x.line("r.EncodeFloat64(float64(" + varname + "))")
+ case reflect.Bool:
+ x.line("r.EncodeBool(bool(" + varname + "))")
+ case reflect.String:
+ x.linef("if z.EncBasicHandle().StringToRaw { r.EncodeStringBytesRaw(z.BytesView(string(%s))) } else { r.EncodeStringEnc(codecSelferCcUTF8%s, string(%s)) }", varname, x.xs, varname)
+ case reflect.Chan:
+ x.xtraSM(varname, t, true, false)
+ // x.encListFallback(varname, rtid, t)
+ case reflect.Array:
+ x.xtraSM(varname, t, true, true)
+ case reflect.Slice:
+ // if nil, call dedicated function
+ // if a []uint8, call dedicated function
+ // if a known fastpath slice, call dedicated function
+ // else write encode function in-line.
+ // - if elements are primitives or Selfers, call dedicated function on each member.
+ // - else call Encoder.encode(XXX) on it.
+ if rtid == uint8SliceTypId {
+ x.line("r.EncodeStringBytesRaw([]byte(" + varname + "))")
+ } else if fastpathAV.index(rtid) != -1 {
+ g := x.newGenV(t)
+ x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", e)")
+ } else {
+ x.xtraSM(varname, t, true, false)
+ // x.encListFallback(varname, rtid, t)
+ }
+ case reflect.Map:
+ // if nil, call dedicated function
+ // if a known fastpath map, call dedicated function
+ // else write encode function in-line.
+ // - if elements are primitives or Selfers, call dedicated function on each member.
+ // - else call Encoder.encode(XXX) on it.
+ // x.line("if " + varname + " == nil { \nr.EncodeNil()\n } else { ")
+ if fastpathAV.index(rtid) != -1 {
+ g := x.newGenV(t)
+ x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", e)")
+ } else {
+ x.xtraSM(varname, t, true, false)
+ // x.encMapFallback(varname, rtid, t)
+ }
+ case reflect.Struct:
+ if !inlist {
+ delete(x.te, rtid)
+ x.line("z.EncFallback(" + varname + ")")
+ break
+ }
+ x.encStruct(varname, rtid, t)
+ default:
+ if rtidAdded {
+ delete(x.te, rtid)
+ }
+ x.line("z.EncFallback(" + varname + ")")
+ }
+}
+
+func (x *genRunner) encZero(t reflect.Type) {
+ switch t.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ x.line("r.EncodeInt(0)")
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ x.line("r.EncodeUint(0)")
+ case reflect.Float32:
+ x.line("r.EncodeFloat32(0)")
+ case reflect.Float64:
+ x.line("r.EncodeFloat64(0)")
+ case reflect.Bool:
+ x.line("r.EncodeBool(false)")
+ case reflect.String:
+ x.linef(`if z.EncBasicHandle().StringToRaw { r.EncodeStringBytesRaw([]byte{}) } else { r.EncodeStringEnc(codecSelferCcUTF8%s, "") }`, x.xs)
+ default:
+ x.line("r.EncodeNil()")
+ }
+}
+
+func (x *genRunner) encOmitEmptyLine(t2 reflect.StructField, varname string, buf *genBuf) {
+ // smartly check omitEmpty on a struct type, as it may contain uncomparable map/slice/etc.
+ // also, for maps/slices/arrays, check if len ! 0 (not if == zero value)
+ varname2 := varname + "." + t2.Name
+ switch t2.Type.Kind() {
+ case reflect.Struct:
+ rtid2 := rt2id(t2.Type)
+ ti2 := x.ti.get(rtid2, t2.Type)
+ // fmt.Printf(">>>> structfield: omitempty: type: %s, field: %s\n", t2.Type.Name(), t2.Name)
+ if ti2.rtid == timeTypId {
+ buf.s("!(").s(varname2).s(".IsZero())")
+ break
+ }
+ if ti2.isFlag(typeInfoFlagIsZeroerPtr) || ti2.isFlag(typeInfoFlagIsZeroer) {
+ buf.s("!(").s(varname2).s(".IsZero())")
+ break
+ }
+ if ti2.isFlag(typeInfoFlagComparable) {
+ buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type))
+ break
+ }
+ // buf.s("(")
+ buf.s("false")
+ for i, n := 0, t2.Type.NumField(); i < n; i++ {
+ f := t2.Type.Field(i)
+ if f.PkgPath != "" { // unexported
+ continue
+ }
+ buf.s(" || ")
+ x.encOmitEmptyLine(f, varname2, buf)
+ }
+ //buf.s(")")
+ case reflect.Bool:
+ buf.s(varname2)
+ case reflect.Map, reflect.Slice, reflect.Array, reflect.Chan:
+ buf.s("len(").s(varname2).s(") != 0")
+ default:
+ buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type))
+ }
+}
+
+func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
+ // Use knowledge from structfieldinfo (mbs, encodable fields. Ignore omitempty. )
+ // replicate code in kStruct i.e. for each field, deref type to non-pointer, and call x.enc on it
+
+ // if t === type currently running selfer on, do for all
+ ti := x.ti.get(rtid, t)
+ i := x.varsfx()
+ sepVarname := genTempVarPfx + "sep" + i
+ numfieldsvar := genTempVarPfx + "q" + i
+ ti2arrayvar := genTempVarPfx + "r" + i
+ struct2arrvar := genTempVarPfx + "2arr" + i
+
+ x.line(sepVarname + " := !z.EncBinary()")
+ x.linef("%s := z.EncBasicHandle().StructToArray", struct2arrvar)
+ x.linef("_, _ = %s, %s", sepVarname, struct2arrvar)
+ x.linef("const %s bool = %v // struct tag has 'toArray'", ti2arrayvar, ti.toArray)
+
+ tisfi := ti.sfiSrc // always use sequence from file. decStruct expects same thing.
+
+ // var nn int
+ // due to omitEmpty, we need to calculate the
+ // number of non-empty things we write out first.
+ // This is required as we need to pre-determine the size of the container,
+ // to support length-prefixing.
+ if ti.anyOmitEmpty {
+ x.linef("var %s = [%v]bool{ // should field at this index be written?", numfieldsvar, len(tisfi))
+
+ for j, si := range tisfi {
+ _ = j
+ if !si.omitEmpty() {
+ // x.linef("%s[%v] = true // %s", numfieldsvar, j, si.fieldName)
+ x.linef("true, // %s", si.fieldName)
+ // nn++
+ continue
+ }
+ var t2 reflect.StructField
+ var omitline genBuf
+ {
+ t2typ := t
+ varname3 := varname
+ // go through the loop, record the t2 field explicitly,
+ // and gather the omit line if embedded in pointers.
+ for ij, ix := range si.is {
+ if uint8(ij) == si.nis {
+ break
+ }
+ for t2typ.Kind() == reflect.Ptr {
+ t2typ = t2typ.Elem()
+ }
+ t2 = t2typ.Field(int(ix))
+ t2typ = t2.Type
+ varname3 = varname3 + "." + t2.Name
+ // do not include actual field in the omit line.
+ // that is done subsequently (right after - below).
+ if uint8(ij+1) < si.nis && t2typ.Kind() == reflect.Ptr {
+ omitline.s(varname3).s(" != nil && ")
+ }
+ }
+ }
+ x.encOmitEmptyLine(t2, varname, &omitline)
+ x.linef("%s, // %s", omitline.v(), si.fieldName)
+ }
+ x.line("}")
+ x.linef("_ = %s", numfieldsvar)
+ }
+ // x.linef("var %snn%s int", genTempVarPfx, i)
+ x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray {
+ x.linef("r.WriteArrayStart(%d)", len(tisfi))
+ x.linef("} else {") // if not ti.toArray
+ if ti.anyOmitEmpty {
+ // nn = 0
+ // x.linef("var %snn%s = %v", genTempVarPfx, i, nn)
+ x.linef("var %snn%s int", genTempVarPfx, i)
+ x.linef("for _, b := range %s { if b { %snn%s++ } }", numfieldsvar, genTempVarPfx, i)
+ x.linef("r.WriteMapStart(%snn%s)", genTempVarPfx, i)
+ x.linef("%snn%s = %v", genTempVarPfx, i, 0)
+ } else {
+ x.linef("r.WriteMapStart(%d)", len(tisfi))
+ }
+ x.line("}") // close if not StructToArray
+
+ for j, si := range tisfi {
+ i := x.varsfx()
+ isNilVarName := genTempVarPfx + "n" + i
+ var labelUsed bool
+ var t2 reflect.StructField
+ {
+ t2typ := t
+ varname3 := varname
+ for ij, ix := range si.is {
+ if uint8(ij) == si.nis {
+ break
+ }
+ for t2typ.Kind() == reflect.Ptr {
+ t2typ = t2typ.Elem()
+ }
+ t2 = t2typ.Field(int(ix))
+ t2typ = t2.Type
+ varname3 = varname3 + "." + t2.Name
+ if t2typ.Kind() == reflect.Ptr {
+ if !labelUsed {
+ x.line("var " + isNilVarName + " bool")
+ }
+ x.line("if " + varname3 + " == nil { " + isNilVarName + " = true ")
+ x.line("goto LABEL" + i)
+ x.line("}")
+ labelUsed = true
+ // "varname3 = new(" + x.genTypeName(t3.Elem()) + ") }")
+ }
+ }
+ // t2 = t.FieldByIndex(si.is)
+ }
+ if labelUsed {
+ x.line("LABEL" + i + ":")
+ }
+ // if the type of the field is a Selfer, or one of the ones
+
+ x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray
+ if labelUsed {
+ x.linef("if %s { r.WriteArrayElem(); r.EncodeNil() } else { ", isNilVarName)
+ }
+ x.line("r.WriteArrayElem()")
+ if si.omitEmpty() {
+ x.linef("if %s[%v] {", numfieldsvar, j)
+ }
+ x.encVar(varname+"."+t2.Name, t2.Type)
+ if si.omitEmpty() {
+ x.linef("} else {")
+ x.encZero(t2.Type)
+ x.linef("}")
+ }
+ if labelUsed {
+ x.line("}")
+ }
+
+ x.linef("} else {") // if not ti.toArray
+
+ if si.omitEmpty() {
+ x.linef("if %s[%v] {", numfieldsvar, j)
+ }
+ x.line("r.WriteMapElemKey()")
+
+ // emulate EncStructFieldKey
+ switch ti.keyType {
+ case valueTypeInt:
+ x.linef("r.EncodeInt(z.M.Int(strconv.ParseInt(`%s`, 10, 64)))", si.encName)
+ case valueTypeUint:
+ x.linef("r.EncodeUint(z.M.Uint(strconv.ParseUint(`%s`, 10, 64)))", si.encName)
+ case valueTypeFloat:
+ x.linef("r.EncodeFloat64(z.M.Float(strconv.ParseFloat(`%s`, 64)))", si.encName)
+ default: // string
+ if si.encNameAsciiAlphaNum {
+ x.linef(`if z.IsJSONHandle() { z.WriteStr("\"%s\"") } else { `, si.encName)
+ }
+ x.linef("r.EncodeStringEnc(codecSelferCcUTF8%s, `%s`)", x.xs, si.encName)
+ if si.encNameAsciiAlphaNum {
+ x.linef("}")
+ }
+ }
+ // x.linef("r.EncStructFieldKey(codecSelferValueType%s%s, `%s`)", ti.keyType.String(), x.xs, si.encName)
+ x.line("r.WriteMapElemValue()")
+ if labelUsed {
+ x.line("if " + isNilVarName + " { r.EncodeNil() } else { ")
+ x.encVar(varname+"."+t2.Name, t2.Type)
+ x.line("}")
+ } else {
+ x.encVar(varname+"."+t2.Name, t2.Type)
+ }
+ if si.omitEmpty() {
+ x.line("}")
+ }
+ x.linef("} ") // end if/else ti.toArray
+ }
+ x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray {
+ x.line("r.WriteArrayEnd()")
+ x.line("} else {")
+ x.line("r.WriteMapEnd()")
+ x.line("}")
+
+}
+
+func (x *genRunner) encListFallback(varname string, t reflect.Type) {
+ elemBytes := t.Elem().Kind() == reflect.Uint8
+ if t.AssignableTo(uint8SliceTyp) {
+ x.linef("r.EncodeStringBytesRaw([]byte(%s))", varname)
+ return
+ }
+ if t.Kind() == reflect.Array && elemBytes {
+ x.linef("r.EncodeStringBytesRaw(((*[%d]byte)(%s))[:])", t.Len(), varname)
+ return
+ }
+ i := x.varsfx()
+ if t.Kind() == reflect.Chan {
+ type ts struct {
+ Label, Chan, Slice, Sfx string
+ }
+ tm, err := template.New("").Parse(genEncChanTmpl)
+ if err != nil {
+ panic(err)
+ }
+ x.linef("if %s == nil { r.EncodeNil() } else { ", varname)
+ x.linef("var sch%s []%s", i, x.genTypeName(t.Elem()))
+ err = tm.Execute(x.w, &ts{"Lsch" + i, varname, "sch" + i, i})
+ if err != nil {
+ panic(err)
+ }
+ // x.linef("%s = sch%s", varname, i)
+ if elemBytes {
+ x.linef("r.EncodeStringBytesRaw([]byte(%s))", "sch"+i)
+ x.line("}")
+ return
+ }
+ varname = "sch" + i
+ }
+
+ x.line("r.WriteArrayStart(len(" + varname + "))")
+ x.linef("for _, %sv%s := range %s {", genTempVarPfx, i, varname)
+ x.line("r.WriteArrayElem()")
+
+ x.encVar(genTempVarPfx+"v"+i, t.Elem())
+ x.line("}")
+ x.line("r.WriteArrayEnd()")
+ if t.Kind() == reflect.Chan {
+ x.line("}")
+ }
+}
+
+func (x *genRunner) encMapFallback(varname string, t reflect.Type) {
+ // TODO: expand this to handle canonical.
+ i := x.varsfx()
+ x.line("r.WriteMapStart(len(" + varname + "))")
+ x.linef("for %sk%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname)
+ x.line("r.WriteMapElemKey()")
+ x.encVar(genTempVarPfx+"k"+i, t.Key())
+ x.line("r.WriteMapElemValue()")
+ x.encVar(genTempVarPfx+"v"+i, t.Elem())
+ x.line("}")
+ x.line("r.WriteMapEnd()")
+}
+
+func (x *genRunner) decVarInitPtr(varname, nilvar string, t reflect.Type, si *structFieldInfo,
+ newbuf, nilbuf *genBuf) (t2 reflect.StructField) {
+ //we must accommodate anonymous fields, where the embedded field is a nil pointer in the value.
+ // t2 = t.FieldByIndex(si.is)
+ t2typ := t
+ varname3 := varname
+ t2kind := t2typ.Kind()
+ var nilbufed bool
+ if si != nil {
+ for ij, ix := range si.is {
+ if uint8(ij) == si.nis {
+ break
+ }
+ for t2typ.Kind() == reflect.Ptr {
+ t2typ = t2typ.Elem()
+ }
+ t2 = t2typ.Field(int(ix))
+ t2typ = t2.Type
+ varname3 = varname3 + "." + t2.Name
+ t2kind = t2typ.Kind()
+ if t2kind != reflect.Ptr {
+ continue
+ }
+ if newbuf != nil {
+ newbuf.f("if %s == nil { %s = new(%s) }\n", varname3, varname3, x.genTypeName(t2typ.Elem()))
+ }
+ if nilbuf != nil {
+ if !nilbufed {
+ nilbuf.s("if true")
+ nilbufed = true
+ }
+ nilbuf.s(" && ").s(varname3).s(" != nil")
+ }
+ }
+ }
+ // if t2typ.Kind() == reflect.Ptr {
+ // varname3 = varname3 + t2.Name
+ // }
+ if nilbuf != nil {
+ if nilbufed {
+ nilbuf.s(" { ")
+ }
+ if nilvar != "" {
+ nilbuf.s(nilvar).s(" = true")
+ } else if tk := t2typ.Kind(); tk == reflect.Ptr {
+ if strings.IndexByte(varname3, '.') != -1 || strings.IndexByte(varname3, '[') != -1 {
+ nilbuf.s(varname3).s(" = nil")
+ } else {
+ nilbuf.s("*").s(varname3).s(" = ").s(x.genZeroValueR(t2typ.Elem()))
+ }
+ } else {
+ nilbuf.s(varname3).s(" = ").s(x.genZeroValueR(t2typ))
+ }
+ if nilbufed {
+ nilbuf.s("}")
+ }
+ }
+ return t2
+}
+
+// decVar takes a variable called varname, of type t
+func (x *genRunner) decVarMain(varname, rand string, t reflect.Type, checkNotNil bool) {
+ // We only encode as nil if a nillable value.
+ // This removes some of the wasted checks for TryDecodeAsNil.
+ // We need to think about this more, to see what happens if omitempty, etc
+ // cause a nil value to be stored when something is expected.
+ // This could happen when decoding from a struct encoded as an array.
+ // For that, decVar should be called with canNil=true, to force true as its value.
+ var varname2 string
+ if t.Kind() != reflect.Ptr {
+ if t.PkgPath() != "" || !x.decTryAssignPrimitive(varname, t, false) {
+ x.dec(varname, t, false)
+ }
+ } else {
+ if checkNotNil {
+ x.linef("if %s == nil { %s = new(%s) }", varname, varname, x.genTypeName(t.Elem()))
+ }
+ // Ensure we set underlying ptr to a non-nil value (so we can deref to it later).
+ // There's a chance of a **T in here which is nil.
+ var ptrPfx string
+ for t = t.Elem(); t.Kind() == reflect.Ptr; t = t.Elem() {
+ ptrPfx += "*"
+ if checkNotNil {
+ x.linef("if %s%s == nil { %s%s = new(%s)}",
+ ptrPfx, varname, ptrPfx, varname, x.genTypeName(t))
+ }
+ }
+ // Should we create temp var if a slice/map indexing? No. dec(...) can now handle it.
+
+ if ptrPfx == "" {
+ x.dec(varname, t, true)
+ } else {
+ varname2 = genTempVarPfx + "z" + rand
+ x.line(varname2 + " := " + ptrPfx + varname)
+ x.dec(varname2, t, true)
+ }
+ }
+}
+
+// decVar takes a variable called varname, of type t
+func (x *genRunner) decVar(varname, nilvar string, t reflect.Type, canBeNil, checkNotNil bool) {
+ i := x.varsfx()
+
+ // We only encode as nil if a nillable value.
+ // This removes some of the wasted checks for TryDecodeAsNil.
+ // We need to think about this more, to see what happens if omitempty, etc
+ // cause a nil value to be stored when something is expected.
+ // This could happen when decoding from a struct encoded as an array.
+ // For that, decVar should be called with canNil=true, to force true as its value.
+
+ if !canBeNil {
+ canBeNil = genAnythingCanBeNil || !genIsImmutable(t)
+ }
+
+ if canBeNil {
+ var buf genBuf
+ x.decVarInitPtr(varname, nilvar, t, nil, nil, &buf)
+ x.linef("if r.TryDecodeAsNil() { %s } else {", buf.buf)
+ } else {
+ x.line("// cannot be nil")
+ }
+
+ x.decVarMain(varname, i, t, checkNotNil)
+
+ if canBeNil {
+ x.line("} ")
+ }
+}
+
+// dec will decode a variable (varname) of type t or ptrTo(t) if isptr==true.
+// t is always a basetype (i.e. not of kind reflect.Ptr).
+func (x *genRunner) dec(varname string, t reflect.Type, isptr bool) {
+ // assumptions:
+ // - the varname is to a pointer already. No need to take address of it
+ // - t is always a baseType T (not a *T, etc).
+ rtid := rt2id(t)
+ ti2 := x.ti.get(rtid, t)
+ // tptr := reflect.PtrTo(t)
+ if x.checkForSelfer(t, varname) {
+ if ti2.cs || ti2.csp { // t.Implements(selferTyp) || tptr.Implements(selferTyp) {
+ x.line(varname + ".CodecDecodeSelf(d)")
+ return
+ }
+ if _, ok := x.td[rtid]; ok {
+ x.line(varname + ".CodecDecodeSelf(d)")
+ return
+ }
+ }
+
+ inlist := false
+ for _, t0 := range x.t {
+ if t == t0 {
+ inlist = true
+ if x.checkForSelfer(t, varname) {
+ x.line(varname + ".CodecDecodeSelf(d)")
+ return
+ }
+ break
+ }
+ }
+
+ var rtidAdded bool
+ if t == x.tc {
+ x.td[rtid] = true
+ rtidAdded = true
+ }
+
+ // check if
+ // - type is time.Time, Raw, RawExt
+ // - the type implements (Text|JSON|Binary)(Unm|M)arshal
+
+ mi := x.varsfx()
+ // x.linef("%sm%s := z.DecBinary()", genTempVarPfx, mi)
+ // x.linef("_ = %sm%s", genTempVarPfx, mi)
+ x.line("if false {") //start if block
+ defer func() { x.line("}") }() //end if block
+
+ var ptrPfx, addrPfx string
+ if isptr {
+ ptrPfx = "*"
+ } else {
+ addrPfx = "&"
+ }
+ if t == timeTyp {
+ x.linef("} else if !z.DecBasicHandle().TimeNotBuiltin { %s%v = r.DecodeTime()", ptrPfx, varname)
+ // return
+ }
+ if t == rawTyp {
+ x.linef("} else { %s%v = z.DecRaw()", ptrPfx, varname)
+ return
+ }
+
+ if t == rawExtTyp {
+ x.linef("} else { r.DecodeExt(%s%v, 0, nil)", addrPfx, varname)
+ return
+ }
+
+ // only check for extensions if the type is named, and has a packagePath.
+ if !x.nx && genImportPath(t) != "" && t.Name() != "" {
+ // first check if extensions are configued, before doing the interface conversion
+ // x.linef("} else if z.HasExtensions() && z.DecExt(%s) {", varname)
+ yy := fmt.Sprintf("%sxt%s", genTempVarPfx, mi)
+ x.linef("} else if %s := z.Extension(z.I2Rtid(%s)); %s != nil { z.DecExtension(%s, %s) ", yy, varname, yy, varname, yy)
+ }
+
+ if ti2.bu || ti2.bup { // t.Implements(binaryUnmarshalerTyp) || tptr.Implements(binaryUnmarshalerTyp) {
+ x.linef("} else if z.DecBinary() { z.DecBinaryUnmarshal(%s%v) ", addrPfx, varname)
+ }
+ if ti2.ju || ti2.jup { // t.Implements(jsonUnmarshalerTyp) || tptr.Implements(jsonUnmarshalerTyp) {
+ x.linef("} else if !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(%s%v)", addrPfx, varname)
+ } else if ti2.tu || ti2.tup { // t.Implements(textUnmarshalerTyp) || tptr.Implements(textUnmarshalerTyp) {
+ x.linef("} else if !z.DecBinary() { z.DecTextUnmarshal(%s%v)", addrPfx, varname)
+ }
+
+ x.line("} else {")
+
+ if x.decTryAssignPrimitive(varname, t, isptr) {
+ return
+ }
+
+ switch t.Kind() {
+ case reflect.Array, reflect.Chan:
+ x.xtraSM(varname, t, false, isptr)
+ case reflect.Slice:
+ // if a []uint8, call dedicated function
+ // if a known fastpath slice, call dedicated function
+ // else write encode function in-line.
+ // - if elements are primitives or Selfers, call dedicated function on each member.
+ // - else call Encoder.encode(XXX) on it.
+ if rtid == uint8SliceTypId {
+ x.linef("%s%s = r.DecodeBytes(%s(%s[]byte)(%s), false)",
+ ptrPfx, varname, ptrPfx, ptrPfx, varname)
+ } else if fastpathAV.index(rtid) != -1 {
+ g := x.newGenV(t)
+ x.linef("z.F.%sX(%s%s, d)", g.MethodNamePfx("Dec", false), addrPfx, varname)
+ } else {
+ x.xtraSM(varname, t, false, isptr)
+ // x.decListFallback(varname, rtid, false, t)
+ }
+ case reflect.Map:
+ // if a known fastpath map, call dedicated function
+ // else write encode function in-line.
+ // - if elements are primitives or Selfers, call dedicated function on each member.
+ // - else call Encoder.encode(XXX) on it.
+ if fastpathAV.index(rtid) != -1 {
+ g := x.newGenV(t)
+ x.linef("z.F.%sX(%s%s, d)", g.MethodNamePfx("Dec", false), addrPfx, varname)
+ } else {
+ x.xtraSM(varname, t, false, isptr)
+ // x.decMapFallback(varname, rtid, t)
+ }
+ case reflect.Struct:
+ if inlist {
+ // no need to create temp variable if isptr, or x.F or x[F]
+ if isptr || strings.IndexByte(varname, '.') != -1 || strings.IndexByte(varname, '[') != -1 {
+ x.decStruct(varname, rtid, t)
+ } else {
+ varname2 := genTempVarPfx + "j" + mi
+ x.line(varname2 + " := &" + varname)
+ x.decStruct(varname2, rtid, t)
+ }
+ } else {
+ // delete(x.td, rtid)
+ x.line("z.DecFallback(" + addrPfx + varname + ", false)")
+ }
+ default:
+ if rtidAdded {
+ delete(x.te, rtid)
+ }
+ x.line("z.DecFallback(" + addrPfx + varname + ", true)")
+ }
+}
+
+func (x *genRunner) decTryAssignPrimitive(varname string, t reflect.Type, isptr bool) (done bool) {
+ // This should only be used for exact primitives (ie un-named types).
+ // Named types may be implementations of Selfer, Unmarshaler, etc.
+ // They should be handled by dec(...)
+
+ var ptr string
+ if isptr {
+ ptr = "*"
+ }
+ switch t.Kind() {
+ case reflect.Int:
+ x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs)
+ case reflect.Int8:
+ x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 8))", ptr, varname, x.genTypeName(t))
+ case reflect.Int16:
+ x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 16))", ptr, varname, x.genTypeName(t))
+ case reflect.Int32:
+ x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 32))", ptr, varname, x.genTypeName(t))
+ case reflect.Int64:
+ x.linef("%s%s = (%s)(r.DecodeInt64())", ptr, varname, x.genTypeName(t))
+
+ case reflect.Uint:
+ x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs)
+ case reflect.Uint8:
+ x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 8))", ptr, varname, x.genTypeName(t))
+ case reflect.Uint16:
+ x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 16))", ptr, varname, x.genTypeName(t))
+ case reflect.Uint32:
+ x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 32))", ptr, varname, x.genTypeName(t))
+ case reflect.Uint64:
+ x.linef("%s%s = (%s)(r.DecodeUint64())", ptr, varname, x.genTypeName(t))
+ case reflect.Uintptr:
+ x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs)
+
+ case reflect.Float32:
+ x.linef("%s%s = (%s)(r.DecodeFloat32As64())", ptr, varname, x.genTypeName(t))
+ case reflect.Float64:
+ x.linef("%s%s = (%s)(r.DecodeFloat64())", ptr, varname, x.genTypeName(t))
+
+ case reflect.Bool:
+ x.linef("%s%s = (%s)(r.DecodeBool())", ptr, varname, x.genTypeName(t))
+ case reflect.String:
+ x.linef("%s%s = (%s)(r.DecodeString())", ptr, varname, x.genTypeName(t))
+ default:
+ return false
+ }
+ return true
+}
+
+func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type) {
+ if t.AssignableTo(uint8SliceTyp) {
+ x.line("*" + varname + " = r.DecodeBytes(*((*[]byte)(" + varname + ")), false)")
+ return
+ }
+ if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 {
+ x.linef("r.DecodeBytes( ((*[%d]byte)(%s))[:], true)", t.Len(), varname)
+ return
+ }
+ type tstruc struct {
+ TempVar string
+ Rand string
+ Varname string
+ CTyp string
+ Typ string
+ Immutable bool
+ Size int
+ }
+ telem := t.Elem()
+ ts := tstruc{genTempVarPfx, x.varsfx(), varname, x.genTypeName(t), x.genTypeName(telem), genIsImmutable(telem), int(telem.Size())}
+
+ funcs := make(template.FuncMap)
+
+ funcs["decLineVar"] = func(varname string) string {
+ x.decVar(varname, "", telem, false, true)
+ return ""
+ }
+ funcs["var"] = func(s string) string {
+ return ts.TempVar + s + ts.Rand
+ }
+ funcs["zero"] = func() string {
+ return x.genZeroValueR(telem)
+ }
+ funcs["isArray"] = func() bool {
+ return t.Kind() == reflect.Array
+ }
+ funcs["isSlice"] = func() bool {
+ return t.Kind() == reflect.Slice
+ }
+ funcs["isChan"] = func() bool {
+ return t.Kind() == reflect.Chan
+ }
+ tm, err := template.New("").Funcs(funcs).Parse(genDecListTmpl)
+ if err != nil {
+ panic(err)
+ }
+ if err = tm.Execute(x.w, &ts); err != nil {
+ panic(err)
+ }
+}
+
+func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type) {
+ type tstruc struct {
+ TempVar string
+ Sfx string
+ Rand string
+ Varname string
+ KTyp string
+ Typ string
+ Size int
+ }
+ telem := t.Elem()
+ tkey := t.Key()
+ ts := tstruc{
+ genTempVarPfx, x.xs, x.varsfx(), varname, x.genTypeName(tkey),
+ x.genTypeName(telem), int(telem.Size() + tkey.Size()),
+ }
+
+ funcs := make(template.FuncMap)
+ funcs["decElemZero"] = func() string {
+ return x.genZeroValueR(telem)
+ }
+ funcs["decElemKindImmutable"] = func() bool {
+ return genIsImmutable(telem)
+ }
+ funcs["decElemKindPtr"] = func() bool {
+ return telem.Kind() == reflect.Ptr
+ }
+ funcs["decElemKindIntf"] = func() bool {
+ return telem.Kind() == reflect.Interface
+ }
+ funcs["decLineVarK"] = func(varname string) string {
+ x.decVar(varname, "", tkey, false, true)
+ return ""
+ }
+ funcs["decLineVar"] = func(varname, decodedNilVarname string) string {
+ x.decVar(varname, decodedNilVarname, telem, false, true)
+ return ""
+ }
+ funcs["var"] = func(s string) string {
+ return ts.TempVar + s + ts.Rand
+ }
+
+ tm, err := template.New("").Funcs(funcs).Parse(genDecMapTmpl)
+ if err != nil {
+ panic(err)
+ }
+ if err = tm.Execute(x.w, &ts); err != nil {
+ panic(err)
+ }
+}
+
+func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintptr, t reflect.Type) {
+ ti := x.ti.get(rtid, t)
+ tisfi := ti.sfiSrc // always use sequence from file. decStruct expects same thing.
+ x.line("switch (" + kName + ") {")
+ var newbuf, nilbuf genBuf
+ for _, si := range tisfi {
+ x.line("case \"" + si.encName + "\":")
+ newbuf.reset()
+ nilbuf.reset()
+ t2 := x.decVarInitPtr(varname, "", t, si, &newbuf, &nilbuf)
+ x.linef("if r.TryDecodeAsNil() { %s } else { %s", nilbuf.buf, newbuf.buf)
+ x.decVarMain(varname+"."+t2.Name, x.varsfx(), t2.Type, false)
+ x.line("}")
+ }
+ x.line("default:")
+ // pass the slice here, so that the string will not escape, and maybe save allocation
+ x.line("z.DecStructFieldNotFound(-1, " + kName + ")")
+ x.line("} // end switch " + kName)
+}
+
+func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type, style genStructMapStyle) {
+ tpfx := genTempVarPfx
+ ti := x.ti.get(rtid, t)
+ i := x.varsfx()
+ kName := tpfx + "s" + i
+
+ switch style {
+ case genStructMapStyleLenPrefix:
+ x.linef("for %sj%s := 0; %sj%s < %s; %sj%s++ {", tpfx, i, tpfx, i, lenvarname, tpfx, i)
+ case genStructMapStyleCheckBreak:
+ x.linef("for %sj%s := 0; !r.CheckBreak(); %sj%s++ {", tpfx, i, tpfx, i)
+ default: // 0, otherwise.
+ x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
+ x.linef("for %sj%s := 0; ; %sj%s++ {", tpfx, i, tpfx, i)
+ x.linef("if %shl%s { if %sj%s >= %s { break }", tpfx, i, tpfx, i, lenvarname)
+ x.line("} else { if r.CheckBreak() { break }; }")
+ }
+ x.line("r.ReadMapElemKey()")
+
+ // emulate decstructfieldkey
+ switch ti.keyType {
+ case valueTypeInt:
+ x.linef("%s := z.StringView(strconv.AppendInt(z.DecScratchArrayBuffer()[:0], r.DecodeInt64(), 10))", kName)
+ case valueTypeUint:
+ x.linef("%s := z.StringView(strconv.AppendUint(z.DecScratchArrayBuffer()[:0], r.DecodeUint64(), 10))", kName)
+ case valueTypeFloat:
+ x.linef("%s := z.StringView(strconv.AppendFloat(z.DecScratchArrayBuffer()[:0], r.DecodeFloat64(), 'f', -1, 64))", kName)
+ default: // string
+ x.linef("%s := z.StringView(r.DecodeStringAsBytes())", kName)
+ }
+ // x.linef("%s := z.StringView(r.DecStructFieldKey(codecSelferValueType%s%s, z.DecScratchArrayBuffer()))", kName, ti.keyType.String(), x.xs)
+
+ x.line("r.ReadMapElemValue()")
+ x.decStructMapSwitch(kName, varname, rtid, t)
+
+ x.line("} // end for " + tpfx + "j" + i)
+ x.line("r.ReadMapEnd()")
+}
+
+func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid uintptr, t reflect.Type) {
+ tpfx := genTempVarPfx
+ i := x.varsfx()
+ ti := x.ti.get(rtid, t)
+ tisfi := ti.sfiSrc // always use sequence from file. decStruct expects same thing.
+ x.linef("var %sj%s int", tpfx, i)
+ x.linef("var %sb%s bool", tpfx, i) // break
+ x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
+ var newbuf, nilbuf genBuf
+ for _, si := range tisfi {
+ x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = r.CheckBreak() }",
+ tpfx, i, tpfx, i, tpfx, i,
+ tpfx, i, lenvarname, tpfx, i)
+ x.linef("if %sb%s { r.ReadArrayEnd(); %s }", tpfx, i, breakString)
+ x.line("r.ReadArrayElem()")
+ newbuf.reset()
+ nilbuf.reset()
+ t2 := x.decVarInitPtr(varname, "", t, si, &newbuf, &nilbuf)
+ x.linef("if r.TryDecodeAsNil() { %s } else { %s", nilbuf.buf, newbuf.buf)
+ x.decVarMain(varname+"."+t2.Name, x.varsfx(), t2.Type, false)
+ x.line("}")
+ }
+ // read remaining values and throw away.
+ x.line("for {")
+ x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = r.CheckBreak() }",
+ tpfx, i, tpfx, i, tpfx, i,
+ tpfx, i, lenvarname, tpfx, i)
+ x.linef("if %sb%s { break }", tpfx, i)
+ x.line("r.ReadArrayElem()")
+ x.linef(`z.DecStructFieldNotFound(%sj%s - 1, "")`, tpfx, i)
+ x.line("}")
+ x.line("r.ReadArrayEnd()")
+}
+
+func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) {
+ // varname MUST be a ptr, or a struct field or a slice element.
+ i := x.varsfx()
+ x.linef("%sct%s := r.ContainerType()", genTempVarPfx, i)
+ x.linef("if %sct%s == codecSelferValueTypeMap%s {", genTempVarPfx, i, x.xs)
+ x.line(genTempVarPfx + "l" + i + " := r.ReadMapStart()")
+ x.linef("if %sl%s == 0 {", genTempVarPfx, i)
+ x.line("r.ReadMapEnd()")
+ if genUseOneFunctionForDecStructMap {
+ x.line("} else { ")
+ x.linef("%s.codecDecodeSelfFromMap(%sl%s, d)", varname, genTempVarPfx, i)
+ } else {
+ x.line("} else if " + genTempVarPfx + "l" + i + " > 0 { ")
+ x.line(varname + ".codecDecodeSelfFromMapLenPrefix(" + genTempVarPfx + "l" + i + ", d)")
+ x.line("} else {")
+ x.line(varname + ".codecDecodeSelfFromMapCheckBreak(" + genTempVarPfx + "l" + i + ", d)")
+ }
+ x.line("}")
+
+ // else if container is array
+ x.linef("} else if %sct%s == codecSelferValueTypeArray%s {", genTempVarPfx, i, x.xs)
+ x.line(genTempVarPfx + "l" + i + " := r.ReadArrayStart()")
+ x.linef("if %sl%s == 0 {", genTempVarPfx, i)
+ x.line("r.ReadArrayEnd()")
+ x.line("} else { ")
+ x.linef("%s.codecDecodeSelfFromArray(%sl%s, d)", varname, genTempVarPfx, i)
+ x.line("}")
+ // else panic
+ x.line("} else { ")
+ x.line("panic(errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + ")")
+ x.line("} ")
+}
+
+// --------
+
+func (x *genRunner) newGenV(t reflect.Type) (v genV) {
+ switch t.Kind() {
+ case reflect.Slice, reflect.Array:
+ te := t.Elem()
+ v.Elem = x.genTypeName(te)
+ v.Size = int(te.Size())
+ case reflect.Map:
+ te, tk := t.Elem(), t.Key()
+ v.Elem = x.genTypeName(te)
+ v.MapKey = x.genTypeName(tk)
+ v.Size = int(te.Size() + tk.Size())
+ default:
+ panic("unexpected type for newGenV. Requires map or slice type")
+ }
+ return
+}
+
+func (x *genV) MethodNamePfx(prefix string, prim bool) string {
+ var name []byte
+ if prefix != "" {
+ name = append(name, prefix...)
+ }
+ if prim {
+ name = append(name, genTitleCaseName(x.Primitive)...)
+ } else {
+ if x.MapKey == "" {
+ name = append(name, "Slice"...)
+ } else {
+ name = append(name, "Map"...)
+ name = append(name, genTitleCaseName(x.MapKey)...)
+ }
+ name = append(name, genTitleCaseName(x.Elem)...)
+ }
+ return string(name)
+
+}
+
+// genImportPath returns import path of a non-predeclared named typed, or an empty string otherwise.
+//
+// This handles the misbehaviour that occurs when 1.5-style vendoring is enabled,
+// where PkgPath returns the full path, including the vendoring pre-fix that should have been stripped.
+// We strip it here.
+func genImportPath(t reflect.Type) (s string) {
+ s = t.PkgPath()
+ s = genStripVendor(s)
+ return
+}
+
+// A go identifier is (letter|_)[letter|number|_]*
+func genGoIdentifier(s string, checkFirstChar bool) string {
+ b := make([]byte, 0, len(s))
+ t := make([]byte, 4)
+ var n int
+ for i, r := range s {
+ if checkFirstChar && i == 0 && !unicode.IsLetter(r) {
+ b = append(b, '_')
+ }
+ // r must be unicode_letter, unicode_digit or _
+ if unicode.IsLetter(r) || unicode.IsDigit(r) {
+ n = utf8.EncodeRune(t, r)
+ b = append(b, t[:n]...)
+ } else {
+ b = append(b, '_')
+ }
+ }
+ return string(b)
+}
+
+func genNonPtr(t reflect.Type) reflect.Type {
+ for t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+ return t
+}
+
+func genTitleCaseName(s string) string {
+ switch s {
+ case "interface{}", "interface {}":
+ return "Intf"
+ default:
+ return strings.ToUpper(s[0:1]) + s[1:]
+ }
+}
+
+func genMethodNameT(t reflect.Type, tRef reflect.Type) (n string) {
+ var ptrPfx string
+ for t.Kind() == reflect.Ptr {
+ ptrPfx += "Ptrto"
+ t = t.Elem()
+ }
+ tstr := t.String()
+ if tn := t.Name(); tn != "" {
+ if tRef != nil && genImportPath(t) == genImportPath(tRef) {
+ return ptrPfx + tn
+ } else {
+ if genQNameRegex.MatchString(tstr) {
+ return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
+ } else {
+ return ptrPfx + genCustomTypeName(tstr)
+ }
+ }
+ }
+ switch t.Kind() {
+ case reflect.Map:
+ return ptrPfx + "Map" + genMethodNameT(t.Key(), tRef) + genMethodNameT(t.Elem(), tRef)
+ case reflect.Slice:
+ return ptrPfx + "Slice" + genMethodNameT(t.Elem(), tRef)
+ case reflect.Array:
+ return ptrPfx + "Array" + strconv.FormatInt(int64(t.Len()), 10) + genMethodNameT(t.Elem(), tRef)
+ case reflect.Chan:
+ var cx string
+ switch t.ChanDir() {
+ case reflect.SendDir:
+ cx = "ChanSend"
+ case reflect.RecvDir:
+ cx = "ChanRecv"
+ default:
+ cx = "Chan"
+ }
+ return ptrPfx + cx + genMethodNameT(t.Elem(), tRef)
+ default:
+ if t == intfTyp {
+ return ptrPfx + "Interface"
+ } else {
+ if tRef != nil && genImportPath(t) == genImportPath(tRef) {
+ if t.Name() != "" {
+ return ptrPfx + t.Name()
+ } else {
+ return ptrPfx + genCustomTypeName(tstr)
+ }
+ } else {
+ // best way to get the package name inclusive
+ // return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
+ // return ptrPfx + genBase32enc.EncodeToString([]byte(tstr))
+ if t.Name() != "" && genQNameRegex.MatchString(tstr) {
+ return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
+ } else {
+ return ptrPfx + genCustomTypeName(tstr)
+ }
+ }
+ }
+ }
+}
+
+// genCustomNameForType base32encodes the t.String() value in such a way
+// that it can be used within a function name.
+func genCustomTypeName(tstr string) string {
+ len2 := genBase32enc.EncodedLen(len(tstr))
+ bufx := make([]byte, len2)
+ genBase32enc.Encode(bufx, []byte(tstr))
+ for i := len2 - 1; i >= 0; i-- {
+ if bufx[i] == '=' {
+ len2--
+ } else {
+ break
+ }
+ }
+ return string(bufx[:len2])
+}
+
+func genIsImmutable(t reflect.Type) (v bool) {
+ return isImmutableKind(t.Kind())
+}
+
+func genStripVendor(s string) string {
+ // HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later.
+ // if s contains /vendor/ OR startsWith vendor/, then return everything after it.
+ const vendorStart = "vendor/"
+ const vendorInline = "/vendor/"
+ if i := strings.LastIndex(s, vendorInline); i >= 0 {
+ s = s[i+len(vendorInline):]
+ } else if strings.HasPrefix(s, vendorStart) {
+ s = s[len(vendorStart):]
+ }
+ return s
+}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/helper.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/helper.go
new file mode 100644
index 00000000000..954ec8ebfd1
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/helper.go
@@ -0,0 +1,2926 @@
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+package codec
+
+// Contains code shared by both encode and decode.
+
+// Some shared ideas around encoding/decoding
+// ------------------------------------------
+//
+// If an interface{} is passed, we first do a type assertion to see if it is
+// a primitive type or a map/slice of primitive types, and use a fastpath to handle it.
+//
+// If we start with a reflect.Value, we are already in reflect.Value land and
+// will try to grab the function for the underlying Type and directly call that function.
+// This is more performant than calling reflect.Value.Interface().
+//
+// This still helps us bypass many layers of reflection, and give best performance.
+//
+// Containers
+// ------------
+// Containers in the stream are either associative arrays (key-value pairs) or
+// regular arrays (indexed by incrementing integers).
+//
+// Some streams support indefinite-length containers, and use a breaking
+// byte-sequence to denote that the container has come to an end.
+//
+// Some streams also are text-based, and use explicit separators to denote the
+// end/beginning of different values.
+//
+// During encode, we use a high-level condition to determine how to iterate through
+// the container. That decision is based on whether the container is text-based (with
+// separators) or binary (without separators). If binary, we do not even call the
+// encoding of separators.
+//
+// During decode, we use a different high-level condition to determine how to iterate
+// through the containers. That decision is based on whether the stream contained
+// a length prefix, or if it used explicit breaks. If length-prefixed, we assume that
+// it has to be binary, and we do not even try to read separators.
+//
+// Philosophy
+// ------------
+// On decode, this codec will update containers appropriately:
+// - If struct, update fields from stream into fields of struct.
+// If field in stream not found in struct, handle appropriately (based on option).
+// If a struct field has no corresponding value in the stream, leave it AS IS.
+// If nil in stream, set value to nil/zero value.
+// - If map, update map from stream.
+// If the stream value is NIL, set the map to nil.
+// - if slice, try to update up to length of array in stream.
+// if container len is less than stream array length,
+// and container cannot be expanded, handled (based on option).
+// This means you can decode 4-element stream array into 1-element array.
+//
+// ------------------------------------
+// On encode, user can specify omitEmpty. This means that the value will be omitted
+// if the zero value. The problem may occur during decode, where omitted values do not affect
+// the value being decoded into. This means that if decoding into a struct with an
+// int field with current value=5, and the field is omitted in the stream, then after
+// decoding, the value will still be 5 (not 0).
+// omitEmpty only works if you guarantee that you always decode into zero-values.
+//
+// ------------------------------------
+// We could have truncated a map to remove keys not available in the stream,
+// or set values in the struct which are not in the stream to their zero values.
+// We decided against it because there is no efficient way to do it.
+// We may introduce it as an option later.
+// However, that will require enabling it for both runtime and code generation modes.
+//
+// To support truncate, we need to do 2 passes over the container:
+// map
+// - first collect all keys (e.g. in k1)
+// - for each key in stream, mark k1 that the key should not be removed
+// - after updating map, do second pass and call delete for all keys in k1 which are not marked
+// struct:
+// - for each field, track the *typeInfo s1
+// - iterate through all s1, and for each one not marked, set value to zero
+// - this involves checking the possible anonymous fields which are nil ptrs.
+// too much work.
+//
+// ------------------------------------------
+// Error Handling is done within the library using panic.
+//
+// This way, the code doesn't have to keep checking if an error has happened,
+// and we don't have to keep sending the error value along with each call
+// or storing it in the En|Decoder and checking it constantly along the way.
+//
+// The disadvantage is that small functions which use panics cannot be inlined.
+// The code accounts for that by only using panics behind an interface;
+// since interface calls cannot be inlined, this is irrelevant.
+//
+// We considered storing the error is En|Decoder.
+// - once it has its err field set, it cannot be used again.
+// - panicing will be optional, controlled by const flag.
+// - code should always check error first and return early.
+// We eventually decided against it as it makes the code clumsier to always
+// check for these error conditions.
+
+import (
+ "bytes"
+ "encoding"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+const (
+ scratchByteArrayLen = 32
+ // initCollectionCap = 16 // 32 is defensive. 16 is preferred.
+
+ // Support encoding.(Binary|Text)(Unm|M)arshaler.
+ // This constant flag will enable or disable it.
+ supportMarshalInterfaces = true
+
+ // for debugging, set this to false, to catch panic traces.
+ // Note that this will always cause rpc tests to fail, since they need io.EOF sent via panic.
+ recoverPanicToErr = true
+
+ // arrayCacheLen is the length of the cache used in encoder or decoder for
+ // allowing zero-alloc initialization.
+ // arrayCacheLen = 8
+
+ // size of the cacheline: defaulting to value for archs: amd64, arm64, 386
+ // should use "runtime/internal/sys".CacheLineSize, but that is not exposed.
+ cacheLineSize = 64
+
+ wordSizeBits = 32 << (^uint(0) >> 63) // strconv.IntSize
+ wordSize = wordSizeBits / 8
+
+ // so structFieldInfo fits into 8 bytes
+ maxLevelsEmbedding = 14
+
+ // useFinalizers=true configures finalizers to release pool'ed resources
+ // acquired by Encoder/Decoder during their GC.
+ //
+ // Note that calling SetFinalizer is always expensive,
+ // as code must be run on the systemstack even for SetFinalizer(t, nil).
+ //
+ // We document that folks SHOULD call Release() when done, or they can
+ // explicitly call SetFinalizer themselves e.g.
+ // runtime.SetFinalizer(e, (*Encoder).Release)
+ // runtime.SetFinalizer(d, (*Decoder).Release)
+ useFinalizers = false
+)
+
+var oneByteArr [1]byte
+var zeroByteSlice = oneByteArr[:0:0]
+
+var codecgen bool
+
+var refBitset bitset256
+var pool pooler
+var panicv panicHdl
+
+func init() {
+ pool.init()
+
+ refBitset.set(byte(reflect.Map))
+ refBitset.set(byte(reflect.Ptr))
+ refBitset.set(byte(reflect.Func))
+ refBitset.set(byte(reflect.Chan))
+}
+
+type clsErr struct {
+ closed bool // is it closed?
+ errClosed error // error on closing
+}
+
+// type entryType uint8
+
+// const (
+// entryTypeBytes entryType = iota // make this 0, so a comparison is cheap
+// entryTypeIo
+// entryTypeBufio
+// entryTypeUnset = 255
+// )
+
+type charEncoding uint8
+
+const (
+ _ charEncoding = iota // make 0 unset
+ cUTF8
+ cUTF16LE
+ cUTF16BE
+ cUTF32LE
+ cUTF32BE
+ // Deprecated: not a true char encoding value
+ cRAW charEncoding = 255
+)
+
+// valueType is the stream type
+type valueType uint8
+
+const (
+ valueTypeUnset valueType = iota
+ valueTypeNil
+ valueTypeInt
+ valueTypeUint
+ valueTypeFloat
+ valueTypeBool
+ valueTypeString
+ valueTypeSymbol
+ valueTypeBytes
+ valueTypeMap
+ valueTypeArray
+ valueTypeTime
+ valueTypeExt
+
+ // valueTypeInvalid = 0xff
+)
+
+var valueTypeStrings = [...]string{
+ "Unset",
+ "Nil",
+ "Int",
+ "Uint",
+ "Float",
+ "Bool",
+ "String",
+ "Symbol",
+ "Bytes",
+ "Map",
+ "Array",
+ "Timestamp",
+ "Ext",
+}
+
+func (x valueType) String() string {
+ if int(x) < len(valueTypeStrings) {
+ return valueTypeStrings[x]
+ }
+ return strconv.FormatInt(int64(x), 10)
+}
+
+type seqType uint8
+
+const (
+ _ seqType = iota
+ seqTypeArray
+ seqTypeSlice
+ seqTypeChan
+)
+
+// note that containerMapStart and containerArraySend are not sent.
+// This is because the ReadXXXStart and EncodeXXXStart already does these.
+type containerState uint8
+
+const (
+ _ containerState = iota
+
+ containerMapStart // slot left open, since Driver method already covers it
+ containerMapKey
+ containerMapValue
+ containerMapEnd
+ containerArrayStart // slot left open, since Driver methods already cover it
+ containerArrayElem
+ containerArrayEnd
+)
+
+// // sfiIdx used for tracking where a (field/enc)Name is seen in a []*structFieldInfo
+// type sfiIdx struct {
+// name string
+// index int
+// }
+
+// do not recurse if a containing type refers to an embedded type
+// which refers back to its containing type (via a pointer).
+// The second time this back-reference happens, break out,
+// so as not to cause an infinite loop.
+const rgetMaxRecursion = 2
+
+// Anecdotally, we believe most types have <= 12 fields.
+// - even Java's PMD rules set TooManyFields threshold to 15.
+// However, go has embedded fields, which should be regarded as
+// top level, allowing structs to possibly double or triple.
+// In addition, we don't want to keep creating transient arrays,
+// especially for the sfi index tracking, and the evtypes tracking.
+//
+// So - try to keep typeInfoLoadArray within 2K bytes
+const (
+ typeInfoLoadArraySfisLen = 16
+ typeInfoLoadArraySfiidxLen = 8 * 112
+ typeInfoLoadArrayEtypesLen = 12
+ typeInfoLoadArrayBLen = 8 * 4
+)
+
+type typeInfoLoad struct {
+ // fNames []string
+ // encNames []string
+ etypes []uintptr
+ sfis []structFieldInfo
+}
+
+type typeInfoLoadArray struct {
+ // fNames [typeInfoLoadArrayLen]string
+ // encNames [typeInfoLoadArrayLen]string
+ sfis [typeInfoLoadArraySfisLen]structFieldInfo
+ sfiidx [typeInfoLoadArraySfiidxLen]byte
+ etypes [typeInfoLoadArrayEtypesLen]uintptr
+ b [typeInfoLoadArrayBLen]byte // scratch - used for struct field names
+}
+
+// mirror json.Marshaler and json.Unmarshaler here,
+// so we don't import the encoding/json package
+
+type jsonMarshaler interface {
+ MarshalJSON() ([]byte, error)
+}
+type jsonUnmarshaler interface {
+ UnmarshalJSON([]byte) error
+}
+
+type isZeroer interface {
+ IsZero() bool
+}
+
+type codecError struct {
+ name string
+ err interface{}
+}
+
+func (e codecError) Cause() error {
+ switch xerr := e.err.(type) {
+ case nil:
+ return nil
+ case error:
+ return xerr
+ case string:
+ return errors.New(xerr)
+ case fmt.Stringer:
+ return errors.New(xerr.String())
+ default:
+ return fmt.Errorf("%v", e.err)
+ }
+}
+
+func (e codecError) Error() string {
+ return fmt.Sprintf("%s error: %v", e.name, e.err)
+}
+
+// type byteAccepter func(byte) bool
+
+var (
+ bigen = binary.BigEndian
+ structInfoFieldName = "_struct"
+
+ mapStrIntfTyp = reflect.TypeOf(map[string]interface{}(nil))
+ mapIntfIntfTyp = reflect.TypeOf(map[interface{}]interface{}(nil))
+ intfSliceTyp = reflect.TypeOf([]interface{}(nil))
+ intfTyp = intfSliceTyp.Elem()
+
+ reflectValTyp = reflect.TypeOf((*reflect.Value)(nil)).Elem()
+
+ stringTyp = reflect.TypeOf("")
+ timeTyp = reflect.TypeOf(time.Time{})
+ rawExtTyp = reflect.TypeOf(RawExt{})
+ rawTyp = reflect.TypeOf(Raw{})
+ uintptrTyp = reflect.TypeOf(uintptr(0))
+ uint8Typ = reflect.TypeOf(uint8(0))
+ uint8SliceTyp = reflect.TypeOf([]uint8(nil))
+ uintTyp = reflect.TypeOf(uint(0))
+ intTyp = reflect.TypeOf(int(0))
+
+ mapBySliceTyp = reflect.TypeOf((*MapBySlice)(nil)).Elem()
+
+ binaryMarshalerTyp = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem()
+ binaryUnmarshalerTyp = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem()
+
+ textMarshalerTyp = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
+ textUnmarshalerTyp = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
+
+ jsonMarshalerTyp = reflect.TypeOf((*jsonMarshaler)(nil)).Elem()
+ jsonUnmarshalerTyp = reflect.TypeOf((*jsonUnmarshaler)(nil)).Elem()
+
+ selferTyp = reflect.TypeOf((*Selfer)(nil)).Elem()
+ missingFielderTyp = reflect.TypeOf((*MissingFielder)(nil)).Elem()
+ iszeroTyp = reflect.TypeOf((*isZeroer)(nil)).Elem()
+
+ uint8TypId = rt2id(uint8Typ)
+ uint8SliceTypId = rt2id(uint8SliceTyp)
+ rawExtTypId = rt2id(rawExtTyp)
+ rawTypId = rt2id(rawTyp)
+ intfTypId = rt2id(intfTyp)
+ timeTypId = rt2id(timeTyp)
+ stringTypId = rt2id(stringTyp)
+
+ mapStrIntfTypId = rt2id(mapStrIntfTyp)
+ mapIntfIntfTypId = rt2id(mapIntfIntfTyp)
+ intfSliceTypId = rt2id(intfSliceTyp)
+ // mapBySliceTypId = rt2id(mapBySliceTyp)
+
+ intBitsize = uint8(intTyp.Bits())
+ uintBitsize = uint8(uintTyp.Bits())
+
+ // bsAll0x00 = []byte{0, 0, 0, 0, 0, 0, 0, 0}
+ bsAll0xff = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+
+ chkOvf checkOverflow
+
+ errNoFieldNameToStructFieldInfo = errors.New("no field name passed to parseStructFieldInfo")
+)
+
+var defTypeInfos = NewTypeInfos([]string{"codec", "json"})
+
+var immutableKindsSet = [32]bool{
+ // reflect.Invalid: ,
+ reflect.Bool: true,
+ reflect.Int: true,
+ reflect.Int8: true,
+ reflect.Int16: true,
+ reflect.Int32: true,
+ reflect.Int64: true,
+ reflect.Uint: true,
+ reflect.Uint8: true,
+ reflect.Uint16: true,
+ reflect.Uint32: true,
+ reflect.Uint64: true,
+ reflect.Uintptr: true,
+ reflect.Float32: true,
+ reflect.Float64: true,
+ reflect.Complex64: true,
+ reflect.Complex128: true,
+ // reflect.Array
+ // reflect.Chan
+ // reflect.Func: true,
+ // reflect.Interface
+ // reflect.Map
+ // reflect.Ptr
+ // reflect.Slice
+ reflect.String: true,
+ reflect.Struct: true,
+ // reflect.UnsafePointer
+}
+
+// Selfer defines methods by which a value can encode or decode itself.
+//
+// Any type which implements Selfer will be able to encode or decode itself.
+// Consequently, during (en|de)code, this takes precedence over
+// (text|binary)(M|Unm)arshal or extension support.
+//
+// By definition, it is not allowed for a Selfer to directly call Encode or Decode on itself.
+// If that is done, Encode/Decode will rightfully fail with a Stack Overflow style error.
+// For example, the snippet below will cause such an error.
+//
+// type testSelferRecur struct{}
+// func (s *testSelferRecur) CodecEncodeSelf(e *Encoder) { e.MustEncode(s) }
+// func (s *testSelferRecur) CodecDecodeSelf(d *Decoder) { d.MustDecode(s) }
+//
+// Note: *the first set of bytes of any value MUST NOT represent nil in the format*.
+// This is because, during each decode, we first check the the next set of bytes
+// represent nil, and if so, we just set the value to nil.
+type Selfer interface {
+ CodecEncodeSelf(*Encoder)
+ CodecDecodeSelf(*Decoder)
+}
+
+// MissingFielder defines the interface allowing structs to internally decode or encode
+// values which do not map to struct fields.
+//
+// We expect that this interface is bound to a pointer type (so the mutation function works).
+//
+// A use-case is if a version of a type unexports a field, but you want compatibility between
+// both versions during encoding and decoding.
+//
+// Note that the interface is completely ignored during codecgen.
+type MissingFielder interface {
+ // CodecMissingField is called to set a missing field and value pair.
+ //
+ // It returns true if the missing field was set on the struct.
+ CodecMissingField(field []byte, value interface{}) bool
+
+ // CodecMissingFields returns the set of fields which are not struct fields
+ CodecMissingFields() map[string]interface{}
+}
+
+// MapBySlice is a tag interface that denotes wrapped slice should encode as a map in the stream.
+// The slice contains a sequence of key-value pairs.
+// This affords storing a map in a specific sequence in the stream.
+//
+// Example usage:
+//
+// type T1 []string // or []int or []Point or any other "slice" type
+// func (_ T1) MapBySlice{} // T1 now implements MapBySlice, and will be encoded as a map
+// type T2 struct { KeyValues T1 }
+//
+// var kvs = []string{"one", "1", "two", "2", "three", "3"}
+// var v2 = T2{ KeyValues: T1(kvs) }
+// // v2 will be encoded like the map: {"KeyValues": {"one": "1", "two": "2", "three": "3"} }
+//
+// The support of MapBySlice affords the following:
+// - A slice type which implements MapBySlice will be encoded as a map
+// - A slice can be decoded from a map in the stream
+// - It MUST be a slice type (not a pointer receiver) that implements MapBySlice
+type MapBySlice interface {
+ MapBySlice()
+}
+
+// BasicHandle encapsulates the common options and extension functions.
+//
+// Deprecated: DO NOT USE DIRECTLY. EXPORTED FOR GODOC BENEFIT. WILL BE REMOVED.
+type BasicHandle struct {
+ // BasicHandle is always a part of a different type.
+ // It doesn't have to fit into it own cache lines.
+
+ // TypeInfos is used to get the type info for any type.
+ //
+ // If not configured, the default TypeInfos is used, which uses struct tag keys: codec, json
+ TypeInfos *TypeInfos
+
+ // Note: BasicHandle is not comparable, due to these slices here (extHandle, intf2impls).
+ // If *[]T is used instead, this becomes comparable, at the cost of extra indirection.
+ // Thses slices are used all the time, so keep as slices (not pointers).
+
+ extHandle
+
+ intf2impls
+
+ inited uint32
+ _ uint32 // padding
+
+ // ---- cache line
+
+ RPCOptions
+
+ // TimeNotBuiltin configures whether time.Time should be treated as a builtin type.
+ //
+ // All Handlers should know how to encode/decode time.Time as part of the core
+ // format specification, or as a standard extension defined by the format.
+ //
+ // However, users can elect to handle time.Time as a custom extension, or via the
+ // standard library's encoding.Binary(M|Unm)arshaler or Text(M|Unm)arshaler interface.
+ // To elect this behavior, users can set TimeNotBuiltin=true.
+ // Note: Setting TimeNotBuiltin=true can be used to enable the legacy behavior
+ // (for Cbor and Msgpack), where time.Time was not a builtin supported type.
+ TimeNotBuiltin bool
+
+ // ExplicitRelease configures whether Release() is implicitly called after an encode or
+ // decode call.
+ //
+ // If you will hold onto an Encoder or Decoder for re-use, by calling Reset(...)
+ // on it or calling (Must)Encode repeatedly into a given []byte or io.Writer,
+ // then you do not want it to be implicitly closed after each Encode/Decode call.
+ // Doing so will unnecessarily return resources to the shared pool, only for you to
+ // grab them right after again to do another Encode/Decode call.
+ //
+ // Instead, you configure ExplicitRelease=true, and you explicitly call Release() when
+ // you are truly done.
+ //
+ // As an alternative, you can explicitly set a finalizer - so its resources
+ // are returned to the shared pool before it is garbage-collected. Do it as below:
+ // runtime.SetFinalizer(e, (*Encoder).Release)
+ // runtime.SetFinalizer(d, (*Decoder).Release)
+ ExplicitRelease bool
+
+ be bool // is handle a binary encoding?
+ js bool // is handle javascript handler?
+ n byte // first letter of handle name
+ _ uint16 // padding
+
+ // ---- cache line
+
+ DecodeOptions
+
+ // ---- cache line
+
+ EncodeOptions
+
+ // noBuiltInTypeChecker
+
+ rtidFns atomicRtidFnSlice
+ mu sync.Mutex
+ // r []uintptr // rtids mapped to s above
+}
+
+// basicHandle returns an initialized BasicHandle from the Handle.
+func basicHandle(hh Handle) (x *BasicHandle) {
+ x = hh.getBasicHandle()
+ // ** We need to simulate once.Do, to ensure no data race within the block.
+ // ** Consequently, below would not work.
+ // if atomic.CompareAndSwapUint32(&x.inited, 0, 1) {
+ // x.be = hh.isBinary()
+ // _, x.js = hh.(*JsonHandle)
+ // x.n = hh.Name()[0]
+ // }
+
+ // simulate once.Do using our own stored flag and mutex as a CompareAndSwap
+ // is not sufficient, since a race condition can occur within init(Handle) function.
+ // init is made noinline, so that this function can be inlined by its caller.
+ if atomic.LoadUint32(&x.inited) == 0 {
+ x.init(hh)
+ }
+ return
+}
+
+//go:noinline
+func (x *BasicHandle) init(hh Handle) {
+ // make it uninlineable, as it is called at most once
+ x.mu.Lock()
+ if x.inited == 0 {
+ x.be = hh.isBinary()
+ _, x.js = hh.(*JsonHandle)
+ x.n = hh.Name()[0]
+ atomic.StoreUint32(&x.inited, 1)
+ }
+ x.mu.Unlock()
+}
+
+func (x *BasicHandle) getBasicHandle() *BasicHandle {
+ return x
+}
+
+func (x *BasicHandle) getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
+ if x.TypeInfos == nil {
+ return defTypeInfos.get(rtid, rt)
+ }
+ return x.TypeInfos.get(rtid, rt)
+}
+
+func findFn(s []codecRtidFn, rtid uintptr) (i uint, fn *codecFn) {
+ // binary search. adapted from sort/search.go.
+ // Note: we use goto (instead of for loop) so this can be inlined.
+
+ // h, i, j := 0, 0, len(s)
+ var h uint // var h, i uint
+ var j = uint(len(s))
+LOOP:
+ if i < j {
+ h = i + (j-i)/2
+ if s[h].rtid < rtid {
+ i = h + 1
+ } else {
+ j = h
+ }
+ goto LOOP
+ }
+ if i < uint(len(s)) && s[i].rtid == rtid {
+ fn = s[i].fn
+ }
+ return
+}
+
+func (x *BasicHandle) fn(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (fn *codecFn) {
+ rtid := rt2id(rt)
+ sp := x.rtidFns.load()
+ if sp != nil {
+ if _, fn = findFn(sp, rtid); fn != nil {
+ // xdebugf("<<<< %c: found fn for %v in rtidfns of size: %v", c.n, rt, len(sp))
+ return
+ }
+ }
+ c := x
+ // xdebugf("#### for %c: load fn for %v in rtidfns of size: %v", c.n, rt, len(sp))
+ fn = new(codecFn)
+ fi := &(fn.i)
+ ti := c.getTypeInfo(rtid, rt)
+ fi.ti = ti
+
+ rk := reflect.Kind(ti.kind)
+
+ if checkCodecSelfer && (ti.cs || ti.csp) {
+ fn.fe = (*Encoder).selferMarshal
+ fn.fd = (*Decoder).selferUnmarshal
+ fi.addrF = true
+ fi.addrD = ti.csp
+ fi.addrE = ti.csp
+ } else if rtid == timeTypId && !c.TimeNotBuiltin {
+ fn.fe = (*Encoder).kTime
+ fn.fd = (*Decoder).kTime
+ } else if rtid == rawTypId {
+ fn.fe = (*Encoder).raw
+ fn.fd = (*Decoder).raw
+ } else if rtid == rawExtTypId {
+ fn.fe = (*Encoder).rawExt
+ fn.fd = (*Decoder).rawExt
+ fi.addrF = true
+ fi.addrD = true
+ fi.addrE = true
+ } else if xfFn := c.getExt(rtid); xfFn != nil {
+ fi.xfTag, fi.xfFn = xfFn.tag, xfFn.ext
+ fn.fe = (*Encoder).ext
+ fn.fd = (*Decoder).ext
+ fi.addrF = true
+ fi.addrD = true
+ if rk == reflect.Struct || rk == reflect.Array {
+ fi.addrE = true
+ }
+ } else if supportMarshalInterfaces && c.be && (ti.bm || ti.bmp) && (ti.bu || ti.bup) {
+ fn.fe = (*Encoder).binaryMarshal
+ fn.fd = (*Decoder).binaryUnmarshal
+ fi.addrF = true
+ fi.addrD = ti.bup
+ fi.addrE = ti.bmp
+ } else if supportMarshalInterfaces && !c.be && c.js && (ti.jm || ti.jmp) && (ti.ju || ti.jup) {
+ //If JSON, we should check JSONMarshal before textMarshal
+ fn.fe = (*Encoder).jsonMarshal
+ fn.fd = (*Decoder).jsonUnmarshal
+ fi.addrF = true
+ fi.addrD = ti.jup
+ fi.addrE = ti.jmp
+ } else if supportMarshalInterfaces && !c.be && (ti.tm || ti.tmp) && (ti.tu || ti.tup) {
+ fn.fe = (*Encoder).textMarshal
+ fn.fd = (*Decoder).textUnmarshal
+ fi.addrF = true
+ fi.addrD = ti.tup
+ fi.addrE = ti.tmp
+ } else {
+ if fastpathEnabled && checkFastpath && (rk == reflect.Map || rk == reflect.Slice) {
+ if ti.pkgpath == "" { // un-named slice or map
+ if idx := fastpathAV.index(rtid); idx != -1 {
+ fn.fe = fastpathAV[idx].encfn
+ fn.fd = fastpathAV[idx].decfn
+ fi.addrD = true
+ fi.addrF = false
+ }
+ } else {
+ // use mapping for underlying type if there
+ var rtu reflect.Type
+ if rk == reflect.Map {
+ rtu = reflect.MapOf(ti.key, ti.elem)
+ } else {
+ rtu = reflect.SliceOf(ti.elem)
+ }
+ rtuid := rt2id(rtu)
+ if idx := fastpathAV.index(rtuid); idx != -1 {
+ xfnf := fastpathAV[idx].encfn
+ xrt := fastpathAV[idx].rt
+ fn.fe = func(e *Encoder, xf *codecFnInfo, xrv reflect.Value) {
+ xfnf(e, xf, xrv.Convert(xrt))
+ }
+ fi.addrD = true
+ fi.addrF = false // meaning it can be an address(ptr) or a value
+ xfnf2 := fastpathAV[idx].decfn
+ fn.fd = func(d *Decoder, xf *codecFnInfo, xrv reflect.Value) {
+ if xrv.Kind() == reflect.Ptr {
+ xfnf2(d, xf, xrv.Convert(reflect.PointerTo(xrt)))
+ } else {
+ xfnf2(d, xf, xrv.Convert(xrt))
+ }
+ }
+ }
+ }
+ }
+ if fn.fe == nil && fn.fd == nil {
+ switch rk {
+ case reflect.Bool:
+ fn.fe = (*Encoder).kBool
+ fn.fd = (*Decoder).kBool
+ case reflect.String:
+ fn.fe = (*Encoder).kString
+ fn.fd = (*Decoder).kString
+ case reflect.Int:
+ fn.fd = (*Decoder).kInt
+ fn.fe = (*Encoder).kInt
+ case reflect.Int8:
+ fn.fe = (*Encoder).kInt8
+ fn.fd = (*Decoder).kInt8
+ case reflect.Int16:
+ fn.fe = (*Encoder).kInt16
+ fn.fd = (*Decoder).kInt16
+ case reflect.Int32:
+ fn.fe = (*Encoder).kInt32
+ fn.fd = (*Decoder).kInt32
+ case reflect.Int64:
+ fn.fe = (*Encoder).kInt64
+ fn.fd = (*Decoder).kInt64
+ case reflect.Uint:
+ fn.fd = (*Decoder).kUint
+ fn.fe = (*Encoder).kUint
+ case reflect.Uint8:
+ fn.fe = (*Encoder).kUint8
+ fn.fd = (*Decoder).kUint8
+ case reflect.Uint16:
+ fn.fe = (*Encoder).kUint16
+ fn.fd = (*Decoder).kUint16
+ case reflect.Uint32:
+ fn.fe = (*Encoder).kUint32
+ fn.fd = (*Decoder).kUint32
+ case reflect.Uint64:
+ fn.fe = (*Encoder).kUint64
+ fn.fd = (*Decoder).kUint64
+ case reflect.Uintptr:
+ fn.fe = (*Encoder).kUintptr
+ fn.fd = (*Decoder).kUintptr
+ case reflect.Float32:
+ fn.fe = (*Encoder).kFloat32
+ fn.fd = (*Decoder).kFloat32
+ case reflect.Float64:
+ fn.fe = (*Encoder).kFloat64
+ fn.fd = (*Decoder).kFloat64
+ case reflect.Invalid:
+ fn.fe = (*Encoder).kInvalid
+ fn.fd = (*Decoder).kErr
+ case reflect.Chan:
+ fi.seq = seqTypeChan
+ fn.fe = (*Encoder).kSlice
+ fn.fd = (*Decoder).kSlice
+ case reflect.Slice:
+ fi.seq = seqTypeSlice
+ fn.fe = (*Encoder).kSlice
+ fn.fd = (*Decoder).kSlice
+ case reflect.Array:
+ fi.seq = seqTypeArray
+ fn.fe = (*Encoder).kSlice
+ fi.addrF = false
+ fi.addrD = false
+ rt2 := reflect.SliceOf(ti.elem)
+ fn.fd = func(d *Decoder, xf *codecFnInfo, xrv reflect.Value) {
+ d.h.fn(rt2, true, false).fd(d, xf, xrv.Slice(0, xrv.Len()))
+ }
+ // fn.fd = (*Decoder).kArray
+ case reflect.Struct:
+ if ti.anyOmitEmpty || ti.mf || ti.mfp {
+ fn.fe = (*Encoder).kStruct
+ } else {
+ fn.fe = (*Encoder).kStructNoOmitempty
+ }
+ fn.fd = (*Decoder).kStruct
+ case reflect.Map:
+ fn.fe = (*Encoder).kMap
+ fn.fd = (*Decoder).kMap
+ case reflect.Interface:
+ // encode: reflect.Interface are handled already by preEncodeValue
+ fn.fd = (*Decoder).kInterface
+ fn.fe = (*Encoder).kErr
+ default:
+ // reflect.Ptr and reflect.Interface are handled already by preEncodeValue
+ fn.fe = (*Encoder).kErr
+ fn.fd = (*Decoder).kErr
+ }
+ }
+ }
+
+ c.mu.Lock()
+ var sp2 []codecRtidFn
+ sp = c.rtidFns.load()
+ if sp == nil {
+ sp2 = []codecRtidFn{{rtid, fn}}
+ c.rtidFns.store(sp2)
+ // xdebugf(">>>> adding rt: %v to rtidfns of size: %v", rt, len(sp2))
+ // xdebugf(">>>> loading stored rtidfns of size: %v", len(c.rtidFns.load()))
+ } else {
+ idx, fn2 := findFn(sp, rtid)
+ if fn2 == nil {
+ sp2 = make([]codecRtidFn, len(sp)+1)
+ copy(sp2, sp[:idx])
+ copy(sp2[idx+1:], sp[idx:])
+ sp2[idx] = codecRtidFn{rtid, fn}
+ c.rtidFns.store(sp2)
+ // xdebugf(">>>> adding rt: %v to rtidfns of size: %v", rt, len(sp2))
+
+ }
+ }
+ c.mu.Unlock()
+ return
+}
+
+// Handle defines a specific encoding format. It also stores any runtime state
+// used during an Encoding or Decoding session e.g. stored state about Types, etc.
+//
+// Once a handle is configured, it can be shared across multiple Encoders and Decoders.
+//
+// Note that a Handle is NOT safe for concurrent modification.
+// Consequently, do not modify it after it is configured if shared among
+// multiple Encoders and Decoders in different goroutines.
+//
+// Consequently, the typical usage model is that a Handle is pre-configured
+// before first time use, and not modified while in use.
+// Such a pre-configured Handle is safe for concurrent access.
+type Handle interface {
+ Name() string
+ // return the basic handle. It may not have been inited.
+ // Prefer to use basicHandle() helper function that ensures it has been inited.
+ getBasicHandle() *BasicHandle
+ recreateEncDriver(encDriver) bool
+ newEncDriver(w *Encoder) encDriver
+ newDecDriver(r *Decoder) decDriver
+ isBinary() bool
+ hasElemSeparators() bool
+ // IsBuiltinType(rtid uintptr) bool
+}
+
+// Raw represents raw formatted bytes.
+// We "blindly" store it during encode and retrieve the raw bytes during decode.
+// Note: it is dangerous during encode, so we may gate the behaviour
+// behind an Encode flag which must be explicitly set.
+type Raw []byte
+
+// RawExt represents raw unprocessed extension data.
+// Some codecs will decode extension data as a *RawExt
+// if there is no registered extension for the tag.
+//
+// Only one of Data or Value is nil.
+// If Data is nil, then the content of the RawExt is in the Value.
+type RawExt struct {
+ Tag uint64
+ // Data is the []byte which represents the raw ext. If nil, ext is exposed in Value.
+ // Data is used by codecs (e.g. binc, msgpack, simple) which do custom serialization of types
+ Data []byte
+ // Value represents the extension, if Data is nil.
+ // Value is used by codecs (e.g. cbor, json) which leverage the format to do
+ // custom serialization of the types.
+ Value interface{}
+}
+
+// BytesExt handles custom (de)serialization of types to/from []byte.
+// It is used by codecs (e.g. binc, msgpack, simple) which do custom serialization of the types.
+type BytesExt interface {
+ // WriteExt converts a value to a []byte.
+ //
+ // Note: v is a pointer iff the registered extension type is a struct or array kind.
+ WriteExt(v interface{}) []byte
+
+ // ReadExt updates a value from a []byte.
+ //
+ // Note: dst is always a pointer kind to the registered extension type.
+ ReadExt(dst interface{}, src []byte)
+}
+
+// InterfaceExt handles custom (de)serialization of types to/from another interface{} value.
+// The Encoder or Decoder will then handle the further (de)serialization of that known type.
+//
+// It is used by codecs (e.g. cbor, json) which use the format to do custom serialization of types.
+type InterfaceExt interface {
+ // ConvertExt converts a value into a simpler interface for easy encoding
+ // e.g. convert time.Time to int64.
+ //
+ // Note: v is a pointer iff the registered extension type is a struct or array kind.
+ ConvertExt(v interface{}) interface{}
+
+ // UpdateExt updates a value from a simpler interface for easy decoding
+ // e.g. convert int64 to time.Time.
+ //
+ // Note: dst is always a pointer kind to the registered extension type.
+ UpdateExt(dst interface{}, src interface{})
+}
+
+// Ext handles custom (de)serialization of custom types / extensions.
+type Ext interface {
+ BytesExt
+ InterfaceExt
+}
+
+// addExtWrapper is a wrapper implementation to support former AddExt exported method.
+type addExtWrapper struct {
+ encFn func(reflect.Value) ([]byte, error)
+ decFn func(reflect.Value, []byte) error
+}
+
+func (x addExtWrapper) WriteExt(v interface{}) []byte {
+ bs, err := x.encFn(reflect.ValueOf(v))
+ if err != nil {
+ panic(err)
+ }
+ return bs
+}
+
+func (x addExtWrapper) ReadExt(v interface{}, bs []byte) {
+ if err := x.decFn(reflect.ValueOf(v), bs); err != nil {
+ panic(err)
+ }
+}
+
+func (x addExtWrapper) ConvertExt(v interface{}) interface{} {
+ return x.WriteExt(v)
+}
+
+func (x addExtWrapper) UpdateExt(dest interface{}, v interface{}) {
+ x.ReadExt(dest, v.([]byte))
+}
+
+type extWrapper struct {
+ BytesExt
+ InterfaceExt
+}
+
+type bytesExtFailer struct{}
+
+func (bytesExtFailer) WriteExt(v interface{}) []byte {
+ panicv.errorstr("BytesExt.WriteExt is not supported")
+ return nil
+}
+func (bytesExtFailer) ReadExt(v interface{}, bs []byte) {
+ panicv.errorstr("BytesExt.ReadExt is not supported")
+}
+
+type interfaceExtFailer struct{}
+
+func (interfaceExtFailer) ConvertExt(v interface{}) interface{} {
+ panicv.errorstr("InterfaceExt.ConvertExt is not supported")
+ return nil
+}
+func (interfaceExtFailer) UpdateExt(dest interface{}, v interface{}) {
+ panicv.errorstr("InterfaceExt.UpdateExt is not supported")
+}
+
+type binaryEncodingType struct{}
+
+func (binaryEncodingType) isBinary() bool { return true }
+
+type textEncodingType struct{}
+
+func (textEncodingType) isBinary() bool { return false }
+
+// noBuiltInTypes is embedded into many types which do not support builtins
+// e.g. msgpack, simple, cbor.
+
+// type noBuiltInTypeChecker struct{}
+// func (noBuiltInTypeChecker) IsBuiltinType(rt uintptr) bool { return false }
+// type noBuiltInTypes struct{ noBuiltInTypeChecker }
+
+type noBuiltInTypes struct{}
+
+func (noBuiltInTypes) EncodeBuiltin(rt uintptr, v interface{}) {}
+func (noBuiltInTypes) DecodeBuiltin(rt uintptr, v interface{}) {}
+
+// type noStreamingCodec struct{}
+// func (noStreamingCodec) CheckBreak() bool { return false }
+// func (noStreamingCodec) hasElemSeparators() bool { return false }
+
+type noElemSeparators struct{}
+
+func (noElemSeparators) hasElemSeparators() (v bool) { return }
+func (noElemSeparators) recreateEncDriver(e encDriver) (v bool) { return }
+
+// bigenHelper.
+// Users must already slice the x completely, because we will not reslice.
+type bigenHelper struct {
+ x []byte // must be correctly sliced to appropriate len. slicing is a cost.
+ w *encWriterSwitch
+}
+
+func (z bigenHelper) writeUint16(v uint16) {
+ bigen.PutUint16(z.x, v)
+ z.w.writeb(z.x)
+}
+
+func (z bigenHelper) writeUint32(v uint32) {
+ bigen.PutUint32(z.x, v)
+ z.w.writeb(z.x)
+}
+
+func (z bigenHelper) writeUint64(v uint64) {
+ bigen.PutUint64(z.x, v)
+ z.w.writeb(z.x)
+}
+
+type extTypeTagFn struct {
+ rtid uintptr
+ rtidptr uintptr
+ rt reflect.Type
+ tag uint64
+ ext Ext
+ _padding [1]uint64 // padding
+}
+
+type extHandle []extTypeTagFn
+
+// AddExt registes an encode and decode function for a reflect.Type.
+// To deregister an Ext, call AddExt with nil encfn and/or nil decfn.
+//
+// Deprecated: Use SetBytesExt or SetInterfaceExt on the Handle instead.
+func (o *extHandle) AddExt(rt reflect.Type, tag byte,
+ encfn func(reflect.Value) ([]byte, error),
+ decfn func(reflect.Value, []byte) error) (err error) {
+ if encfn == nil || decfn == nil {
+ return o.SetExt(rt, uint64(tag), nil)
+ }
+ return o.SetExt(rt, uint64(tag), addExtWrapper{encfn, decfn})
+}
+
+// SetExt will set the extension for a tag and reflect.Type.
+// Note that the type must be a named type, and specifically not a pointer or Interface.
+// An error is returned if that is not honored.
+// To Deregister an ext, call SetExt with nil Ext.
+//
+// Deprecated: Use SetBytesExt or SetInterfaceExt on the Handle instead.
+func (o *extHandle) SetExt(rt reflect.Type, tag uint64, ext Ext) (err error) {
+ // o is a pointer, because we may need to initialize it
+ rk := rt.Kind()
+ for rk == reflect.Ptr {
+ rt = rt.Elem()
+ rk = rt.Kind()
+ }
+
+ if rt.PkgPath() == "" || rk == reflect.Interface { // || rk == reflect.Ptr {
+ return fmt.Errorf("codec.Handle.SetExt: Takes named type, not a pointer or interface: %v", rt)
+ }
+
+ rtid := rt2id(rt)
+ switch rtid {
+ case timeTypId, rawTypId, rawExtTypId:
+ // all natively supported type, so cannot have an extension
+ return // TODO: should we silently ignore, or return an error???
+ }
+ o2 := *o
+ for i := range o2 {
+ v := &o2[i]
+ if v.rtid == rtid {
+ v.tag, v.ext = tag, ext
+ return
+ }
+ }
+ rtidptr := rt2id(reflect.PtrTo(rt))
+ *o = append(o2, extTypeTagFn{rtid, rtidptr, rt, tag, ext, [1]uint64{}})
+ return
+}
+
+func (o extHandle) getExt(rtid uintptr) (v *extTypeTagFn) {
+ for i := range o {
+ v = &o[i]
+ if v.rtid == rtid || v.rtidptr == rtid {
+ return
+ }
+ }
+ return nil
+}
+
+func (o extHandle) getExtForTag(tag uint64) (v *extTypeTagFn) {
+ for i := range o {
+ v = &o[i]
+ if v.tag == tag {
+ return
+ }
+ }
+ return nil
+}
+
+type intf2impl struct {
+ rtid uintptr // for intf
+ impl reflect.Type
+ // _ [1]uint64 // padding // not-needed, as *intf2impl is never returned.
+}
+
+type intf2impls []intf2impl
+
+// Intf2Impl maps an interface to an implementing type.
+// This allows us support infering the concrete type
+// and populating it when passed an interface.
+// e.g. var v io.Reader can be decoded as a bytes.Buffer, etc.
+//
+// Passing a nil impl will clear the mapping.
+func (o *intf2impls) Intf2Impl(intf, impl reflect.Type) (err error) {
+ if impl != nil && !impl.Implements(intf) {
+ return fmt.Errorf("Intf2Impl: %v does not implement %v", impl, intf)
+ }
+ rtid := rt2id(intf)
+ o2 := *o
+ for i := range o2 {
+ v := &o2[i]
+ if v.rtid == rtid {
+ v.impl = impl
+ return
+ }
+ }
+ *o = append(o2, intf2impl{rtid, impl})
+ return
+}
+
+func (o intf2impls) intf2impl(rtid uintptr) (rv reflect.Value) {
+ for i := range o {
+ v := &o[i]
+ if v.rtid == rtid {
+ if v.impl == nil {
+ return
+ }
+ if v.impl.Kind() == reflect.Ptr {
+ return reflect.New(v.impl.Elem())
+ }
+ return reflect.New(v.impl).Elem()
+ }
+ }
+ return
+}
+
+type structFieldInfoFlag uint8
+
+const (
+ _ structFieldInfoFlag = 1 << iota
+ structFieldInfoFlagReady
+ structFieldInfoFlagOmitEmpty
+)
+
+func (x *structFieldInfoFlag) flagSet(f structFieldInfoFlag) {
+ *x = *x | f
+}
+
+func (x *structFieldInfoFlag) flagClr(f structFieldInfoFlag) {
+ *x = *x &^ f
+}
+
+func (x structFieldInfoFlag) flagGet(f structFieldInfoFlag) bool {
+ return x&f != 0
+}
+
+func (x structFieldInfoFlag) omitEmpty() bool {
+ return x.flagGet(structFieldInfoFlagOmitEmpty)
+}
+
+func (x structFieldInfoFlag) ready() bool {
+ return x.flagGet(structFieldInfoFlagReady)
+}
+
+type structFieldInfo struct {
+ encName string // encode name
+ fieldName string // field name
+
+ is [maxLevelsEmbedding]uint16 // (recursive/embedded) field index in struct
+ nis uint8 // num levels of embedding. if 1, then it's not embedded.
+
+ encNameAsciiAlphaNum bool // the encName only contains ascii alphabet and numbers
+ structFieldInfoFlag
+ _ [1]byte // padding
+}
+
+func (si *structFieldInfo) setToZeroValue(v reflect.Value) {
+ if v, valid := si.field(v, false); valid {
+ v.Set(reflect.Zero(v.Type()))
+ }
+}
+
+// rv returns the field of the struct.
+// If anonymous, it returns an Invalid
+func (si *structFieldInfo) field(v reflect.Value, update bool) (rv2 reflect.Value, valid bool) {
+ // replicate FieldByIndex
+ for i, x := range si.is {
+ if uint8(i) == si.nis {
+ break
+ }
+ if v, valid = baseStructRv(v, update); !valid {
+ return
+ }
+ v = v.Field(int(x))
+ }
+
+ return v, true
+}
+
+// func (si *structFieldInfo) fieldval(v reflect.Value, update bool) reflect.Value {
+// v, _ = si.field(v, update)
+// return v
+// }
+
+func parseStructInfo(stag string) (toArray, omitEmpty bool, keytype valueType) {
+ keytype = valueTypeString // default
+ if stag == "" {
+ return
+ }
+ for i, s := range strings.Split(stag, ",") {
+ if i == 0 {
+ } else {
+ switch s {
+ case "omitempty":
+ omitEmpty = true
+ case "toarray":
+ toArray = true
+ case "int":
+ keytype = valueTypeInt
+ case "uint":
+ keytype = valueTypeUint
+ case "float":
+ keytype = valueTypeFloat
+ // case "bool":
+ // keytype = valueTypeBool
+ case "string":
+ keytype = valueTypeString
+ }
+ }
+ }
+ return
+}
+
+func (si *structFieldInfo) parseTag(stag string) {
+ // if fname == "" {
+ // panic(errNoFieldNameToStructFieldInfo)
+ // }
+
+ if stag == "" {
+ return
+ }
+ for i, s := range strings.Split(stag, ",") {
+ if i == 0 {
+ if s != "" {
+ si.encName = s
+ }
+ } else {
+ switch s {
+ case "omitempty":
+ si.flagSet(structFieldInfoFlagOmitEmpty)
+ // si.omitEmpty = true
+ // case "toarray":
+ // si.toArray = true
+ }
+ }
+ }
+}
+
+type sfiSortedByEncName []*structFieldInfo
+
+func (p sfiSortedByEncName) Len() int { return len(p) }
+func (p sfiSortedByEncName) Less(i, j int) bool { return p[uint(i)].encName < p[uint(j)].encName }
+func (p sfiSortedByEncName) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+const structFieldNodeNumToCache = 4
+
+type structFieldNodeCache struct {
+ rv [structFieldNodeNumToCache]reflect.Value
+ idx [structFieldNodeNumToCache]uint32
+ num uint8
+}
+
+func (x *structFieldNodeCache) get(key uint32) (fv reflect.Value, valid bool) {
+ for i, k := range &x.idx {
+ if uint8(i) == x.num {
+ return // break
+ }
+ if key == k {
+ return x.rv[i], true
+ }
+ }
+ return
+}
+
+func (x *structFieldNodeCache) tryAdd(fv reflect.Value, key uint32) {
+ if x.num < structFieldNodeNumToCache {
+ x.rv[x.num] = fv
+ x.idx[x.num] = key
+ x.num++
+ return
+ }
+}
+
+type structFieldNode struct {
+ v reflect.Value
+ cache2 structFieldNodeCache
+ cache3 structFieldNodeCache
+ update bool
+}
+
+func (x *structFieldNode) field(si *structFieldInfo) (fv reflect.Value) {
+ // return si.fieldval(x.v, x.update)
+ // Note: we only cache if nis=2 or nis=3 i.e. up to 2 levels of embedding
+ // This mostly saves us time on the repeated calls to v.Elem, v.Field, etc.
+ var valid bool
+ switch si.nis {
+ case 1:
+ fv = x.v.Field(int(si.is[0]))
+ case 2:
+ if fv, valid = x.cache2.get(uint32(si.is[0])); valid {
+ fv = fv.Field(int(si.is[1]))
+ return
+ }
+ fv = x.v.Field(int(si.is[0]))
+ if fv, valid = baseStructRv(fv, x.update); !valid {
+ return
+ }
+ x.cache2.tryAdd(fv, uint32(si.is[0]))
+ fv = fv.Field(int(si.is[1]))
+ case 3:
+ var key uint32 = uint32(si.is[0])<<16 | uint32(si.is[1])
+ if fv, valid = x.cache3.get(key); valid {
+ fv = fv.Field(int(si.is[2]))
+ return
+ }
+ fv = x.v.Field(int(si.is[0]))
+ if fv, valid = baseStructRv(fv, x.update); !valid {
+ return
+ }
+ fv = fv.Field(int(si.is[1]))
+ if fv, valid = baseStructRv(fv, x.update); !valid {
+ return
+ }
+ x.cache3.tryAdd(fv, key)
+ fv = fv.Field(int(si.is[2]))
+ default:
+ fv, _ = si.field(x.v, x.update)
+ }
+ return
+}
+
+func baseStructRv(v reflect.Value, update bool) (v2 reflect.Value, valid bool) {
+ for v.Kind() == reflect.Ptr {
+ if v.IsNil() {
+ if !update {
+ return
+ }
+ v.Set(reflect.New(v.Type().Elem()))
+ }
+ v = v.Elem()
+ }
+ return v, true
+}
+
+type typeInfoFlag uint8
+
+const (
+ typeInfoFlagComparable = 1 << iota
+ typeInfoFlagIsZeroer
+ typeInfoFlagIsZeroerPtr
+)
+
+// typeInfo keeps information about each (non-ptr) type referenced in the encode/decode sequence.
+//
+// During an encode/decode sequence, we work as below:
+// - If base is a built in type, en/decode base value
+// - If base is registered as an extension, en/decode base value
+// - If type is binary(M/Unm)arshaler, call Binary(M/Unm)arshal method
+// - If type is text(M/Unm)arshaler, call Text(M/Unm)arshal method
+// - Else decode appropriately based on the reflect.Kind
+type typeInfo struct {
+ rt reflect.Type
+ elem reflect.Type
+ pkgpath string
+
+ rtid uintptr
+ // rv0 reflect.Value // saved zero value, used if immutableKind
+
+ numMeth uint16 // number of methods
+ kind uint8
+ chandir uint8
+
+ anyOmitEmpty bool // true if a struct, and any of the fields are tagged "omitempty"
+ toArray bool // whether this (struct) type should be encoded as an array
+ keyType valueType // if struct, how is the field name stored in a stream? default is string
+ mbs bool // base type (T or *T) is a MapBySlice
+
+ // ---- cpu cache line boundary?
+ sfiSort []*structFieldInfo // sorted. Used when enc/dec struct to map.
+ sfiSrc []*structFieldInfo // unsorted. Used when enc/dec struct to array.
+
+ key reflect.Type
+
+ // ---- cpu cache line boundary?
+ // sfis []structFieldInfo // all sfi, in src order, as created.
+ sfiNamesSort []byte // all names, with indexes into the sfiSort
+
+ // format of marshal type fields below: [btj][mu]p? OR csp?
+
+ bm bool // T is a binaryMarshaler
+ bmp bool // *T is a binaryMarshaler
+ bu bool // T is a binaryUnmarshaler
+ bup bool // *T is a binaryUnmarshaler
+ tm bool // T is a textMarshaler
+ tmp bool // *T is a textMarshaler
+ tu bool // T is a textUnmarshaler
+ tup bool // *T is a textUnmarshaler
+
+ jm bool // T is a jsonMarshaler
+ jmp bool // *T is a jsonMarshaler
+ ju bool // T is a jsonUnmarshaler
+ jup bool // *T is a jsonUnmarshaler
+ cs bool // T is a Selfer
+ csp bool // *T is a Selfer
+ mf bool // T is a MissingFielder
+ mfp bool // *T is a MissingFielder
+
+ // other flags, with individual bits representing if set.
+ flags typeInfoFlag
+ infoFieldOmitempty bool
+
+ _ [6]byte // padding
+ _ [2]uint64 // padding
+}
+
+func (ti *typeInfo) isFlag(f typeInfoFlag) bool {
+ return ti.flags&f != 0
+}
+
+func (ti *typeInfo) indexForEncName(name []byte) (index int16) {
+ var sn []byte
+ if len(name)+2 <= 32 {
+ var buf [32]byte // should not escape to heap
+ sn = buf[:len(name)+2]
+ } else {
+ sn = make([]byte, len(name)+2)
+ }
+ copy(sn[1:], name)
+ sn[0], sn[len(sn)-1] = tiSep2(name), 0xff
+ j := bytes.Index(ti.sfiNamesSort, sn)
+ if j < 0 {
+ return -1
+ }
+ index = int16(uint16(ti.sfiNamesSort[j+len(sn)+1]) | uint16(ti.sfiNamesSort[j+len(sn)])<<8)
+ return
+}
+
+type rtid2ti struct {
+ rtid uintptr
+ ti *typeInfo
+}
+
+// TypeInfos caches typeInfo for each type on first inspection.
+//
+// It is configured with a set of tag keys, which are used to get
+// configuration for the type.
+type TypeInfos struct {
+ // infos: formerly map[uintptr]*typeInfo, now *[]rtid2ti, 2 words expected
+ infos atomicTypeInfoSlice
+ mu sync.Mutex
+ tags []string
+ _ [2]uint64 // padding
+}
+
+// NewTypeInfos creates a TypeInfos given a set of struct tags keys.
+//
+// This allows users customize the struct tag keys which contain configuration
+// of their types.
+func NewTypeInfos(tags []string) *TypeInfos {
+ return &TypeInfos{tags: tags}
+}
+
+func (x *TypeInfos) structTag(t reflect.StructTag) (s string) {
+ // check for tags: codec, json, in that order.
+ // this allows seamless support for many configured structs.
+ for _, x := range x.tags {
+ s = t.Get(x)
+ if s != "" {
+ return s
+ }
+ }
+ return
+}
+
+func findTypeInfo(s []rtid2ti, rtid uintptr) (i uint, ti *typeInfo) {
+ // binary search. adapted from sort/search.go.
+ // Note: we use goto (instead of for loop) so this can be inlined.
+
+ // if sp == nil {
+ // return -1, nil
+ // }
+ // s := *sp
+
+ // h, i, j := 0, 0, len(s)
+ var h uint // var h, i uint
+ var j = uint(len(s))
+LOOP:
+ if i < j {
+ h = i + (j-i)/2
+ if s[h].rtid < rtid {
+ i = h + 1
+ } else {
+ j = h
+ }
+ goto LOOP
+ }
+ if i < uint(len(s)) && s[i].rtid == rtid {
+ ti = s[i].ti
+ }
+ return
+}
+
+func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
+ sp := x.infos.load()
+ if sp != nil {
+ _, pti = findTypeInfo(sp, rtid)
+ if pti != nil {
+ return
+ }
+ }
+
+ rk := rt.Kind()
+
+ if rk == reflect.Ptr { // || (rk == reflect.Interface && rtid != intfTypId) {
+ panicv.errorf("invalid kind passed to TypeInfos.get: %v - %v", rk, rt)
+ }
+
+ // do not hold lock while computing this.
+ // it may lead to duplication, but that's ok.
+ ti := typeInfo{
+ rt: rt,
+ rtid: rtid,
+ kind: uint8(rk),
+ pkgpath: rt.PkgPath(),
+ keyType: valueTypeString, // default it - so it's never 0
+ }
+ // ti.rv0 = reflect.Zero(rt)
+
+ // ti.comparable = rt.Comparable()
+ ti.numMeth = uint16(rt.NumMethod())
+
+ ti.bm, ti.bmp = implIntf(rt, binaryMarshalerTyp)
+ ti.bu, ti.bup = implIntf(rt, binaryUnmarshalerTyp)
+ ti.tm, ti.tmp = implIntf(rt, textMarshalerTyp)
+ ti.tu, ti.tup = implIntf(rt, textUnmarshalerTyp)
+ ti.jm, ti.jmp = implIntf(rt, jsonMarshalerTyp)
+ ti.ju, ti.jup = implIntf(rt, jsonUnmarshalerTyp)
+ ti.cs, ti.csp = implIntf(rt, selferTyp)
+ ti.mf, ti.mfp = implIntf(rt, missingFielderTyp)
+
+ b1, b2 := implIntf(rt, iszeroTyp)
+ if b1 {
+ ti.flags |= typeInfoFlagIsZeroer
+ }
+ if b2 {
+ ti.flags |= typeInfoFlagIsZeroerPtr
+ }
+ if rt.Comparable() {
+ ti.flags |= typeInfoFlagComparable
+ }
+
+ switch rk {
+ case reflect.Struct:
+ var omitEmpty bool
+ if f, ok := rt.FieldByName(structInfoFieldName); ok {
+ ti.toArray, omitEmpty, ti.keyType = parseStructInfo(x.structTag(f.Tag))
+ ti.infoFieldOmitempty = omitEmpty
+ } else {
+ ti.keyType = valueTypeString
+ }
+ pp, pi := &pool.tiload, pool.tiload.Get() // pool.tiLoad()
+ pv := pi.(*typeInfoLoadArray)
+ pv.etypes[0] = ti.rtid
+ // vv := typeInfoLoad{pv.fNames[:0], pv.encNames[:0], pv.etypes[:1], pv.sfis[:0]}
+ vv := typeInfoLoad{pv.etypes[:1], pv.sfis[:0]}
+ x.rget(rt, rtid, omitEmpty, nil, &vv)
+ // ti.sfis = vv.sfis
+ ti.sfiSrc, ti.sfiSort, ti.sfiNamesSort, ti.anyOmitEmpty = rgetResolveSFI(rt, vv.sfis, pv)
+ pp.Put(pi)
+ case reflect.Map:
+ ti.elem = rt.Elem()
+ ti.key = rt.Key()
+ case reflect.Slice:
+ ti.mbs, _ = implIntf(rt, mapBySliceTyp)
+ ti.elem = rt.Elem()
+ case reflect.Chan:
+ ti.elem = rt.Elem()
+ ti.chandir = uint8(rt.ChanDir())
+ case reflect.Array, reflect.Ptr:
+ ti.elem = rt.Elem()
+ }
+ // sfi = sfiSrc
+
+ x.mu.Lock()
+ sp = x.infos.load()
+ var sp2 []rtid2ti
+ if sp == nil {
+ pti = &ti
+ sp2 = []rtid2ti{{rtid, pti}}
+ x.infos.store(sp2)
+ } else {
+ var idx uint
+ idx, pti = findTypeInfo(sp, rtid)
+ if pti == nil {
+ pti = &ti
+ sp2 = make([]rtid2ti, len(sp)+1)
+ copy(sp2, sp[:idx])
+ copy(sp2[idx+1:], sp[idx:])
+ sp2[idx] = rtid2ti{rtid, pti}
+ x.infos.store(sp2)
+ }
+ }
+ x.mu.Unlock()
+ return
+}
+
+func (x *TypeInfos) rget(rt reflect.Type, rtid uintptr, omitEmpty bool,
+ indexstack []uint16, pv *typeInfoLoad) {
+ // Read up fields and store how to access the value.
+ //
+ // It uses go's rules for message selectors,
+ // which say that the field with the shallowest depth is selected.
+ //
+ // Note: we consciously use slices, not a map, to simulate a set.
+ // Typically, types have < 16 fields,
+ // and iteration using equals is faster than maps there
+ flen := rt.NumField()
+ if flen > (1< %v fields are not supported - has %v fields",
+ (1<= 0; i-- { // bounds-check elimination
+ b := si.encName[i]
+ if (b >= '0' && b <= '9') || (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') {
+ continue
+ }
+ si.encNameAsciiAlphaNum = false
+ break
+ }
+ si.fieldName = f.Name
+ si.flagSet(structFieldInfoFlagReady)
+
+ // pv.encNames = append(pv.encNames, si.encName)
+
+ // si.ikind = int(f.Type.Kind())
+ if len(indexstack) > maxLevelsEmbedding-1 {
+ panicv.errorf("codec: only supports up to %v depth of embedding - type has %v depth",
+ maxLevelsEmbedding-1, len(indexstack))
+ }
+ si.nis = uint8(len(indexstack)) + 1
+ copy(si.is[:], indexstack)
+ si.is[len(indexstack)] = j
+
+ if omitEmpty {
+ si.flagSet(structFieldInfoFlagOmitEmpty)
+ }
+ pv.sfis = append(pv.sfis, si)
+ }
+}
+
+func tiSep(name string) uint8 {
+ // (xn[0]%64) // (between 192-255 - outside ascii BMP)
+ // return 0xfe - (name[0] & 63)
+ // return 0xfe - (name[0] & 63) - uint8(len(name))
+ // return 0xfe - (name[0] & 63) - uint8(len(name)&63)
+ // return ((0xfe - (name[0] & 63)) & 0xf8) | (uint8(len(name) & 0x07))
+ return 0xfe - (name[0] & 63) - uint8(len(name)&63)
+}
+
+func tiSep2(name []byte) uint8 {
+ return 0xfe - (name[0] & 63) - uint8(len(name)&63)
+}
+
+// resolves the struct field info got from a call to rget.
+// Returns a trimmed, unsorted and sorted []*structFieldInfo.
+func rgetResolveSFI(rt reflect.Type, x []structFieldInfo, pv *typeInfoLoadArray) (
+ y, z []*structFieldInfo, ss []byte, anyOmitEmpty bool) {
+ sa := pv.sfiidx[:0]
+ sn := pv.b[:]
+ n := len(x)
+
+ var xn string
+ var ui uint16
+ var sep byte
+
+ for i := range x {
+ ui = uint16(i)
+ xn = x[i].encName // fieldName or encName? use encName for now.
+ if len(xn)+2 > cap(pv.b) {
+ sn = make([]byte, len(xn)+2)
+ } else {
+ sn = sn[:len(xn)+2]
+ }
+ // use a custom sep, so that misses are less frequent,
+ // since the sep (first char in search) is as unique as first char in field name.
+ sep = tiSep(xn)
+ sn[0], sn[len(sn)-1] = sep, 0xff
+ copy(sn[1:], xn)
+ j := bytes.Index(sa, sn)
+ if j == -1 {
+ sa = append(sa, sep)
+ sa = append(sa, xn...)
+ sa = append(sa, 0xff, byte(ui>>8), byte(ui))
+ } else {
+ index := uint16(sa[j+len(sn)+1]) | uint16(sa[j+len(sn)])<<8
+ // one of them must be reset to nil,
+ // and the index updated appropriately to the other one
+ if x[i].nis == x[index].nis {
+ } else if x[i].nis < x[index].nis {
+ sa[j+len(sn)], sa[j+len(sn)+1] = byte(ui>>8), byte(ui)
+ if x[index].ready() {
+ x[index].flagClr(structFieldInfoFlagReady)
+ n--
+ }
+ } else {
+ if x[i].ready() {
+ x[i].flagClr(structFieldInfoFlagReady)
+ n--
+ }
+ }
+ }
+
+ }
+ var w []structFieldInfo
+ sharingArray := len(x) <= typeInfoLoadArraySfisLen // sharing array with typeInfoLoadArray
+ if sharingArray {
+ w = make([]structFieldInfo, n)
+ }
+
+ // remove all the nils (non-ready)
+ y = make([]*structFieldInfo, n)
+ n = 0
+ var sslen int
+ for i := range x {
+ if !x[i].ready() {
+ continue
+ }
+ if !anyOmitEmpty && x[i].omitEmpty() {
+ anyOmitEmpty = true
+ }
+ if sharingArray {
+ w[n] = x[i]
+ y[n] = &w[n]
+ } else {
+ y[n] = &x[i]
+ }
+ sslen = sslen + len(x[i].encName) + 4
+ n++
+ }
+ if n != len(y) {
+ panicv.errorf("failure reading struct %v - expecting %d of %d valid fields, got %d",
+ rt, len(y), len(x), n)
+ }
+
+ z = make([]*structFieldInfo, len(y))
+ copy(z, y)
+ sort.Sort(sfiSortedByEncName(z))
+
+ sharingArray = len(sa) <= typeInfoLoadArraySfiidxLen
+ if sharingArray {
+ ss = make([]byte, 0, sslen)
+ } else {
+ ss = sa[:0] // reuse the newly made sa array if necessary
+ }
+ for i := range z {
+ xn = z[i].encName
+ sep = tiSep(xn)
+ ui = uint16(i)
+ ss = append(ss, sep)
+ ss = append(ss, xn...)
+ ss = append(ss, 0xff, byte(ui>>8), byte(ui))
+ }
+ return
+}
+
+func implIntf(rt, iTyp reflect.Type) (base bool, indir bool) {
+ return rt.Implements(iTyp), reflect.PointerTo(rt).Implements(iTyp)
+}
+
+// isEmptyStruct is only called from isEmptyValue, and checks if a struct is empty:
+// - does it implement IsZero() bool
+// - is it comparable, and can i compare directly using ==
+// - if checkStruct, then walk through the encodable fields
+// and check if they are empty or not.
+func isEmptyStruct(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool) bool {
+ // v is a struct kind - no need to check again.
+ // We only check isZero on a struct kind, to reduce the amount of times
+ // that we lookup the rtid and typeInfo for each type as we walk the tree.
+
+ vt := v.Type()
+ rtid := rt2id(vt)
+ if tinfos == nil {
+ tinfos = defTypeInfos
+ }
+ ti := tinfos.get(rtid, vt)
+ if ti.rtid == timeTypId {
+ return rv2i(v).(time.Time).IsZero()
+ }
+ if ti.isFlag(typeInfoFlagIsZeroerPtr) && v.CanAddr() {
+ return rv2i(v.Addr()).(isZeroer).IsZero()
+ }
+ if ti.isFlag(typeInfoFlagIsZeroer) {
+ return rv2i(v).(isZeroer).IsZero()
+ }
+ if ti.isFlag(typeInfoFlagComparable) {
+ return rv2i(v) == rv2i(reflect.Zero(vt))
+ }
+ if !checkStruct {
+ return false
+ }
+ // We only care about what we can encode/decode,
+ // so that is what we use to check omitEmpty.
+ for _, si := range ti.sfiSrc {
+ sfv, valid := si.field(v, false)
+ if valid && !isEmptyValue(sfv, tinfos, deref, checkStruct) {
+ return false
+ }
+ }
+ return true
+}
+
+// func roundFloat(x float64) float64 {
+// t := math.Trunc(x)
+// if math.Abs(x-t) >= 0.5 {
+// return t + math.Copysign(1, x)
+// }
+// return t
+// }
+
+func panicToErr(h errDecorator, err *error) {
+ // Note: This method MUST be called directly from defer i.e. defer panicToErr ...
+ // else it seems the recover is not fully handled
+ if recoverPanicToErr {
+ if x := recover(); x != nil {
+ // fmt.Printf("panic'ing with: %v\n", x)
+ // debug.PrintStack()
+ panicValToErr(h, x, err)
+ }
+ }
+}
+
+func panicValToErr(h errDecorator, v interface{}, err *error) {
+ switch xerr := v.(type) {
+ case nil:
+ case error:
+ switch xerr {
+ case nil:
+ case io.EOF, io.ErrUnexpectedEOF, errEncoderNotInitialized, errDecoderNotInitialized:
+ // treat as special (bubble up)
+ *err = xerr
+ default:
+ h.wrapErr(xerr, err)
+ }
+ case string:
+ if xerr != "" {
+ h.wrapErr(xerr, err)
+ }
+ case fmt.Stringer:
+ if xerr != nil {
+ h.wrapErr(xerr, err)
+ }
+ default:
+ h.wrapErr(v, err)
+ }
+}
+
+func isImmutableKind(k reflect.Kind) (v bool) {
+ // return immutableKindsSet[k]
+ // since we know reflect.Kind is in range 0..31, then use the k%32 == k constraint
+ return immutableKindsSet[k%reflect.Kind(len(immutableKindsSet))] // bounds-check-elimination
+}
+
+// ----
+
+type codecFnInfo struct {
+ ti *typeInfo
+ xfFn Ext
+ xfTag uint64
+ seq seqType
+ addrD bool
+ addrF bool // if addrD, this says whether decode function can take a value or a ptr
+ addrE bool
+}
+
+// codecFn encapsulates the captured variables and the encode function.
+// This way, we only do some calculations one times, and pass to the
+// code block that should be called (encapsulated in a function)
+// instead of executing the checks every time.
+type codecFn struct {
+ i codecFnInfo
+ fe func(*Encoder, *codecFnInfo, reflect.Value)
+ fd func(*Decoder, *codecFnInfo, reflect.Value)
+ _ [1]uint64 // padding
+}
+
+type codecRtidFn struct {
+ rtid uintptr
+ fn *codecFn
+}
+
+// ----
+
+// these "checkOverflow" functions must be inlinable, and not call anybody.
+// Overflow means that the value cannot be represented without wrapping/overflow.
+// Overflow=false does not mean that the value can be represented without losing precision
+// (especially for floating point).
+
+type checkOverflow struct{}
+
+// func (checkOverflow) Float16(f float64) (overflow bool) {
+// panicv.errorf("unimplemented")
+// if f < 0 {
+// f = -f
+// }
+// return math.MaxFloat32 < f && f <= math.MaxFloat64
+// }
+
+func (checkOverflow) Float32(v float64) (overflow bool) {
+ if v < 0 {
+ v = -v
+ }
+ return math.MaxFloat32 < v && v <= math.MaxFloat64
+}
+func (checkOverflow) Uint(v uint64, bitsize uint8) (overflow bool) {
+ if bitsize == 0 || bitsize >= 64 || v == 0 {
+ return
+ }
+ if trunc := (v << (64 - bitsize)) >> (64 - bitsize); v != trunc {
+ overflow = true
+ }
+ return
+}
+func (checkOverflow) Int(v int64, bitsize uint8) (overflow bool) {
+ if bitsize == 0 || bitsize >= 64 || v == 0 {
+ return
+ }
+ if trunc := (v << (64 - bitsize)) >> (64 - bitsize); v != trunc {
+ overflow = true
+ }
+ return
+}
+func (checkOverflow) SignedInt(v uint64) (overflow bool) {
+ //e.g. -127 to 128 for int8
+ pos := (v >> 63) == 0
+ ui2 := v & 0x7fffffffffffffff
+ if pos {
+ if ui2 > math.MaxInt64 {
+ overflow = true
+ }
+ } else {
+ if ui2 > math.MaxInt64-1 {
+ overflow = true
+ }
+ }
+ return
+}
+
+func (x checkOverflow) Float32V(v float64) float64 {
+ if x.Float32(v) {
+ panicv.errorf("float32 overflow: %v", v)
+ }
+ return v
+}
+func (x checkOverflow) UintV(v uint64, bitsize uint8) uint64 {
+ if x.Uint(v, bitsize) {
+ panicv.errorf("uint64 overflow: %v", v)
+ }
+ return v
+}
+func (x checkOverflow) IntV(v int64, bitsize uint8) int64 {
+ if x.Int(v, bitsize) {
+ panicv.errorf("int64 overflow: %v", v)
+ }
+ return v
+}
+func (x checkOverflow) SignedIntV(v uint64) int64 {
+ if x.SignedInt(v) {
+ panicv.errorf("uint64 to int64 overflow: %v", v)
+ }
+ return int64(v)
+}
+
+// ------------------ SORT -----------------
+
+func isNaN(f float64) bool { return f != f }
+
+// -----------------------
+
+type ioFlusher interface {
+ Flush() error
+}
+
+type ioPeeker interface {
+ Peek(int) ([]byte, error)
+}
+
+type ioBuffered interface {
+ Buffered() int
+}
+
+// -----------------------
+
+type intSlice []int64
+type uintSlice []uint64
+
+// type uintptrSlice []uintptr
+type floatSlice []float64
+type boolSlice []bool
+type stringSlice []string
+
+// type bytesSlice [][]byte
+
+func (p intSlice) Len() int { return len(p) }
+func (p intSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] }
+func (p intSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+func (p uintSlice) Len() int { return len(p) }
+func (p uintSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] }
+func (p uintSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+// func (p uintptrSlice) Len() int { return len(p) }
+// func (p uintptrSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] }
+// func (p uintptrSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+func (p floatSlice) Len() int { return len(p) }
+func (p floatSlice) Less(i, j int) bool {
+ return p[uint(i)] < p[uint(j)] || isNaN(p[uint(i)]) && !isNaN(p[uint(j)])
+}
+func (p floatSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+func (p stringSlice) Len() int { return len(p) }
+func (p stringSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] }
+func (p stringSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+// func (p bytesSlice) Len() int { return len(p) }
+// func (p bytesSlice) Less(i, j int) bool { return bytes.Compare(p[uint(i)], p[uint(j)]) == -1 }
+// func (p bytesSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+func (p boolSlice) Len() int { return len(p) }
+func (p boolSlice) Less(i, j int) bool { return !p[uint(i)] && p[uint(j)] }
+func (p boolSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+// ---------------------
+
+type sfiRv struct {
+ v *structFieldInfo
+ r reflect.Value
+}
+
+type intRv struct {
+ v int64
+ r reflect.Value
+}
+type intRvSlice []intRv
+type uintRv struct {
+ v uint64
+ r reflect.Value
+}
+type uintRvSlice []uintRv
+type floatRv struct {
+ v float64
+ r reflect.Value
+}
+type floatRvSlice []floatRv
+type boolRv struct {
+ v bool
+ r reflect.Value
+}
+type boolRvSlice []boolRv
+type stringRv struct {
+ v string
+ r reflect.Value
+}
+type stringRvSlice []stringRv
+type bytesRv struct {
+ v []byte
+ r reflect.Value
+}
+type bytesRvSlice []bytesRv
+type timeRv struct {
+ v time.Time
+ r reflect.Value
+}
+type timeRvSlice []timeRv
+
+func (p intRvSlice) Len() int { return len(p) }
+func (p intRvSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v }
+func (p intRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+func (p uintRvSlice) Len() int { return len(p) }
+func (p uintRvSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v }
+func (p uintRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+func (p floatRvSlice) Len() int { return len(p) }
+func (p floatRvSlice) Less(i, j int) bool {
+ return p[uint(i)].v < p[uint(j)].v || isNaN(p[uint(i)].v) && !isNaN(p[uint(j)].v)
+}
+func (p floatRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+func (p stringRvSlice) Len() int { return len(p) }
+func (p stringRvSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v }
+func (p stringRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+func (p bytesRvSlice) Len() int { return len(p) }
+func (p bytesRvSlice) Less(i, j int) bool { return bytes.Compare(p[uint(i)].v, p[uint(j)].v) == -1 }
+func (p bytesRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+func (p boolRvSlice) Len() int { return len(p) }
+func (p boolRvSlice) Less(i, j int) bool { return !p[uint(i)].v && p[uint(j)].v }
+func (p boolRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+func (p timeRvSlice) Len() int { return len(p) }
+func (p timeRvSlice) Less(i, j int) bool { return p[uint(i)].v.Before(p[uint(j)].v) }
+func (p timeRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+// -----------------
+
+type bytesI struct {
+ v []byte
+ i interface{}
+}
+
+type bytesISlice []bytesI
+
+func (p bytesISlice) Len() int { return len(p) }
+func (p bytesISlice) Less(i, j int) bool { return bytes.Compare(p[uint(i)].v, p[uint(j)].v) == -1 }
+func (p bytesISlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }
+
+// -----------------
+
+type set []uintptr
+
+func (s *set) add(v uintptr) (exists bool) {
+ // e.ci is always nil, or len >= 1
+ x := *s
+ if x == nil {
+ x = make([]uintptr, 1, 8)
+ x[0] = v
+ *s = x
+ return
+ }
+ // typically, length will be 1. make this perform.
+ if len(x) == 1 {
+ if j := x[0]; j == 0 {
+ x[0] = v
+ } else if j == v {
+ exists = true
+ } else {
+ x = append(x, v)
+ *s = x
+ }
+ return
+ }
+ // check if it exists
+ for _, j := range x {
+ if j == v {
+ exists = true
+ return
+ }
+ }
+ // try to replace a "deleted" slot
+ for i, j := range x {
+ if j == 0 {
+ x[i] = v
+ return
+ }
+ }
+ // if unable to replace deleted slot, just append it.
+ x = append(x, v)
+ *s = x
+ return
+}
+
+func (s *set) remove(v uintptr) (exists bool) {
+ x := *s
+ if len(x) == 0 {
+ return
+ }
+ if len(x) == 1 {
+ if x[0] == v {
+ x[0] = 0
+ }
+ return
+ }
+ for i, j := range x {
+ if j == v {
+ exists = true
+ x[i] = 0 // set it to 0, as way to delete it.
+ // copy(x[i:], x[i+1:])
+ // x = x[:len(x)-1]
+ return
+ }
+ }
+ return
+}
+
+// ------
+
+// bitset types are better than [256]bool, because they permit the whole
+// bitset array being on a single cache line and use less memory.
+//
+// Also, since pos is a byte (0-255), there's no bounds checks on indexing (cheap).
+//
+// We previously had bitset128 [16]byte, and bitset32 [4]byte, but those introduces
+// bounds checking, so we discarded them, and everyone uses bitset256.
+//
+// given x > 0 and n > 0 and x is exactly 2^n, then pos/x === pos>>n AND pos%x === pos&(x-1).
+// consequently, pos/32 === pos>>5, pos/16 === pos>>4, pos/8 === pos>>3, pos%8 == pos&7
+
+type bitset256 [32]byte
+
+func (x *bitset256) isset(pos byte) bool {
+ return x[pos>>3]&(1<<(pos&7)) != 0
+}
+
+// func (x *bitset256) issetv(pos byte) byte {
+// return x[pos>>3] & (1 << (pos & 7))
+// }
+
+func (x *bitset256) set(pos byte) {
+ x[pos>>3] |= (1 << (pos & 7))
+}
+
+// func (x *bitset256) unset(pos byte) {
+// x[pos>>3] &^= (1 << (pos & 7))
+// }
+
+// type bit2set256 [64]byte
+
+// func (x *bit2set256) set(pos byte, v1, v2 bool) {
+// var pos2 uint8 = (pos & 3) << 1 // returning 0, 2, 4 or 6
+// if v1 {
+// x[pos>>2] |= 1 << (pos2 + 1)
+// }
+// if v2 {
+// x[pos>>2] |= 1 << pos2
+// }
+// }
+// func (x *bit2set256) get(pos byte) uint8 {
+// var pos2 uint8 = (pos & 3) << 1 // returning 0, 2, 4 or 6
+// return x[pos>>2] << (6 - pos2) >> 6 // 11000000 -> 00000011
+// }
+
+// ------------
+
+type pooler struct {
+ // function-scoped pooled resources
+ tiload sync.Pool // for type info loading
+ sfiRv8, sfiRv16, sfiRv32, sfiRv64, sfiRv128 sync.Pool // for struct encoding
+
+ // lifetime-scoped pooled resources
+ // dn sync.Pool // for decNaked
+ buf1k, buf2k, buf4k, buf8k, buf16k, buf32k, buf64k sync.Pool // for [N]byte
+}
+
+func (p *pooler) init() {
+ p.tiload.New = func() interface{} { return new(typeInfoLoadArray) }
+
+ p.sfiRv8.New = func() interface{} { return new([8]sfiRv) }
+ p.sfiRv16.New = func() interface{} { return new([16]sfiRv) }
+ p.sfiRv32.New = func() interface{} { return new([32]sfiRv) }
+ p.sfiRv64.New = func() interface{} { return new([64]sfiRv) }
+ p.sfiRv128.New = func() interface{} { return new([128]sfiRv) }
+
+ // p.dn.New = func() interface{} { x := new(decNaked); x.init(); return x }
+
+ p.buf1k.New = func() interface{} { return new([1 * 1024]byte) }
+ p.buf2k.New = func() interface{} { return new([2 * 1024]byte) }
+ p.buf4k.New = func() interface{} { return new([4 * 1024]byte) }
+ p.buf8k.New = func() interface{} { return new([8 * 1024]byte) }
+ p.buf16k.New = func() interface{} { return new([16 * 1024]byte) }
+ p.buf32k.New = func() interface{} { return new([32 * 1024]byte) }
+ p.buf64k.New = func() interface{} { return new([64 * 1024]byte) }
+
+}
+
+// func (p *pooler) sfiRv8() (sp *sync.Pool, v interface{}) {
+// return &p.strRv8, p.strRv8.Get()
+// }
+// func (p *pooler) sfiRv16() (sp *sync.Pool, v interface{}) {
+// return &p.strRv16, p.strRv16.Get()
+// }
+// func (p *pooler) sfiRv32() (sp *sync.Pool, v interface{}) {
+// return &p.strRv32, p.strRv32.Get()
+// }
+// func (p *pooler) sfiRv64() (sp *sync.Pool, v interface{}) {
+// return &p.strRv64, p.strRv64.Get()
+// }
+// func (p *pooler) sfiRv128() (sp *sync.Pool, v interface{}) {
+// return &p.strRv128, p.strRv128.Get()
+// }
+
+// func (p *pooler) bytes1k() (sp *sync.Pool, v interface{}) {
+// return &p.buf1k, p.buf1k.Get()
+// }
+// func (p *pooler) bytes2k() (sp *sync.Pool, v interface{}) {
+// return &p.buf2k, p.buf2k.Get()
+// }
+// func (p *pooler) bytes4k() (sp *sync.Pool, v interface{}) {
+// return &p.buf4k, p.buf4k.Get()
+// }
+// func (p *pooler) bytes8k() (sp *sync.Pool, v interface{}) {
+// return &p.buf8k, p.buf8k.Get()
+// }
+// func (p *pooler) bytes16k() (sp *sync.Pool, v interface{}) {
+// return &p.buf16k, p.buf16k.Get()
+// }
+// func (p *pooler) bytes32k() (sp *sync.Pool, v interface{}) {
+// return &p.buf32k, p.buf32k.Get()
+// }
+// func (p *pooler) bytes64k() (sp *sync.Pool, v interface{}) {
+// return &p.buf64k, p.buf64k.Get()
+// }
+
+// func (p *pooler) tiLoad() (sp *sync.Pool, v interface{}) {
+// return &p.tiload, p.tiload.Get()
+// }
+
+// func (p *pooler) decNaked() (sp *sync.Pool, v interface{}) {
+// return &p.dn, p.dn.Get()
+// }
+
+// func (p *pooler) decNaked() (v *decNaked, f func(*decNaked) ) {
+// sp := &(p.dn)
+// vv := sp.Get()
+// return vv.(*decNaked), func(x *decNaked) { sp.Put(vv) }
+// }
+// func (p *pooler) decNakedGet() (v interface{}) {
+// return p.dn.Get()
+// }
+// func (p *pooler) tiLoadGet() (v interface{}) {
+// return p.tiload.Get()
+// }
+// func (p *pooler) decNakedPut(v interface{}) {
+// p.dn.Put(v)
+// }
+// func (p *pooler) tiLoadPut(v interface{}) {
+// p.tiload.Put(v)
+// }
+
+// ----------------------------------------------------
+
+type panicHdl struct{}
+
+func (panicHdl) errorv(err error) {
+ if err != nil {
+ panic(err)
+ }
+}
+
+func (panicHdl) errorstr(message string) {
+ if message != "" {
+ panic(message)
+ }
+}
+
+func (panicHdl) errorf(format string, params ...interface{}) {
+ if format == "" {
+ } else if len(params) == 0 {
+ panic(format)
+ } else {
+ panic(fmt.Sprintf(format, params...))
+ }
+}
+
+// ----------------------------------------------------
+
+type errDecorator interface {
+ wrapErr(in interface{}, out *error)
+}
+
+type errDecoratorDef struct{}
+
+func (errDecoratorDef) wrapErr(v interface{}, e *error) { *e = fmt.Errorf("%v", v) }
+
+// ----------------------------------------------------
+
+type must struct{}
+
+func (must) String(s string, err error) string {
+ if err != nil {
+ panicv.errorv(err)
+ }
+ return s
+}
+func (must) Int(s int64, err error) int64 {
+ if err != nil {
+ panicv.errorv(err)
+ }
+ return s
+}
+func (must) Uint(s uint64, err error) uint64 {
+ if err != nil {
+ panicv.errorv(err)
+ }
+ return s
+}
+func (must) Float(s float64, err error) float64 {
+ if err != nil {
+ panicv.errorv(err)
+ }
+ return s
+}
+
+// -------------------
+
+type bytesBufPooler struct {
+ pool *sync.Pool
+ poolbuf interface{}
+}
+
+func (z *bytesBufPooler) end() {
+ if z.pool != nil {
+ z.pool.Put(z.poolbuf)
+ z.pool, z.poolbuf = nil, nil
+ }
+}
+
+func (z *bytesBufPooler) get(bufsize int) (buf []byte) {
+ // ensure an end is called first (if necessary)
+ if z.pool != nil {
+ z.pool.Put(z.poolbuf)
+ z.pool, z.poolbuf = nil, nil
+ }
+
+ if bufsize <= 1*1024 {
+ z.pool, z.poolbuf = &pool.buf1k, pool.buf1k.Get() // pool.bytes1k()
+ buf = z.poolbuf.(*[1 * 1024]byte)[:]
+ } else if bufsize <= 2*1024 {
+ z.pool, z.poolbuf = &pool.buf2k, pool.buf2k.Get() // pool.bytes2k()
+ buf = z.poolbuf.(*[2 * 1024]byte)[:]
+ } else if bufsize <= 4*1024 {
+ z.pool, z.poolbuf = &pool.buf4k, pool.buf4k.Get() // pool.bytes4k()
+ buf = z.poolbuf.(*[4 * 1024]byte)[:]
+ } else if bufsize <= 8*1024 {
+ z.pool, z.poolbuf = &pool.buf8k, pool.buf8k.Get() // pool.bytes8k()
+ buf = z.poolbuf.(*[8 * 1024]byte)[:]
+ } else if bufsize <= 16*1024 {
+ z.pool, z.poolbuf = &pool.buf16k, pool.buf16k.Get() // pool.bytes16k()
+ buf = z.poolbuf.(*[16 * 1024]byte)[:]
+ } else if bufsize <= 32*1024 {
+ z.pool, z.poolbuf = &pool.buf32k, pool.buf32k.Get() // pool.bytes32k()
+ buf = z.poolbuf.(*[32 * 1024]byte)[:]
+ } else {
+ z.pool, z.poolbuf = &pool.buf64k, pool.buf64k.Get() // pool.bytes64k()
+ buf = z.poolbuf.(*[64 * 1024]byte)[:]
+ }
+ return
+}
+
+// ----------------
+
+type sfiRvPooler struct {
+ pool *sync.Pool
+ poolv interface{}
+}
+
+func (z *sfiRvPooler) end() {
+ if z.pool != nil {
+ z.pool.Put(z.poolv)
+ z.pool, z.poolv = nil, nil
+ }
+}
+
+func (z *sfiRvPooler) get(newlen int) (fkvs []sfiRv) {
+ if newlen < 0 { // bounds-check-elimination
+ // cannot happen // here for bounds-check-elimination
+ } else if newlen <= 8 {
+ z.pool, z.poolv = &pool.sfiRv8, pool.sfiRv8.Get() // pool.sfiRv8()
+ fkvs = z.poolv.(*[8]sfiRv)[:newlen]
+ } else if newlen <= 16 {
+ z.pool, z.poolv = &pool.sfiRv16, pool.sfiRv16.Get() // pool.sfiRv16()
+ fkvs = z.poolv.(*[16]sfiRv)[:newlen]
+ } else if newlen <= 32 {
+ z.pool, z.poolv = &pool.sfiRv32, pool.sfiRv32.Get() // pool.sfiRv32()
+ fkvs = z.poolv.(*[32]sfiRv)[:newlen]
+ } else if newlen <= 64 {
+ z.pool, z.poolv = &pool.sfiRv64, pool.sfiRv64.Get() // pool.sfiRv64()
+ fkvs = z.poolv.(*[64]sfiRv)[:newlen]
+ } else if newlen <= 128 {
+ z.pool, z.poolv = &pool.sfiRv128, pool.sfiRv128.Get() // pool.sfiRv128()
+ fkvs = z.poolv.(*[128]sfiRv)[:newlen]
+ } else {
+ fkvs = make([]sfiRv, newlen)
+ }
+ return
+}
+
+// safe-mod optimizations
+
+const safeMode = true
+
+// stringView returns a view of the []byte as a string.
+// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
+// In regular safe mode, it is an allocation and copy.
+//
+// Usage: Always maintain a reference to v while result of this call is in use,
+//
+// and call keepAlive4BytesView(v) at point where done with view.
+func stringView(v []byte) string {
+ return string(v)
+}
+
+// bytesView returns a view of the string as a []byte.
+// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
+// In regular safe mode, it is an allocation and copy.
+//
+// Usage: Always maintain a reference to v while result of this call is in use,
+//
+// and call keepAlive4BytesView(v) at point where done with view.
+func bytesView(v string) []byte {
+ return []byte(v)
+}
+
+func definitelyNil(v interface{}) bool {
+ // this is a best-effort option.
+ // We just return false, so we don't unnecessarily incur the cost of reflection this early.
+ return false
+}
+
+func rv2i(rv reflect.Value) interface{} {
+ return rv.Interface()
+}
+
+func rt2id(rt reflect.Type) uintptr {
+ return reflect.ValueOf(rt).Pointer()
+}
+
+func i2rtid(i interface{}) uintptr {
+ return reflect.ValueOf(reflect.TypeOf(i)).Pointer()
+}
+
+// --------------------------
+
+func isEmptyValue(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool) bool {
+ switch v.Kind() {
+ case reflect.Invalid:
+ return true
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ return v.Len() == 0
+ case reflect.Bool:
+ return !v.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return v.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return v.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return v.Float() == 0
+ case reflect.Interface, reflect.Ptr:
+ if deref {
+ if v.IsNil() {
+ return true
+ }
+ return isEmptyValue(v.Elem(), tinfos, deref, checkStruct)
+ }
+ return v.IsNil()
+ case reflect.Struct:
+ return isEmptyStruct(v, tinfos, deref, checkStruct)
+ }
+ return false
+}
+
+// --------------------------
+type atomicClsErr struct {
+ v atomic.Value
+}
+
+func (x *atomicClsErr) load() (e clsErr) {
+ if i := x.v.Load(); i != nil {
+ e = i.(clsErr)
+ }
+ return
+}
+
+func (x *atomicClsErr) store(p clsErr) {
+ x.v.Store(p)
+}
+
+// --------------------------
+type atomicTypeInfoSlice struct { // expected to be 2 words
+ v atomic.Value
+}
+
+func (x *atomicTypeInfoSlice) load() (e []rtid2ti) {
+ if i := x.v.Load(); i != nil {
+ e = i.([]rtid2ti)
+ }
+ return
+}
+
+func (x *atomicTypeInfoSlice) store(p []rtid2ti) {
+ x.v.Store(p)
+}
+
+// --------------------------
+type atomicRtidFnSlice struct { // expected to be 2 words
+ v atomic.Value
+}
+
+func (x *atomicRtidFnSlice) load() (e []codecRtidFn) {
+ if i := x.v.Load(); i != nil {
+ e = i.([]codecRtidFn)
+ }
+ return
+}
+
+func (x *atomicRtidFnSlice) store(p []codecRtidFn) {
+ x.v.Store(p)
+}
+
+// --------------------------
+func (n *decNaked) ru() reflect.Value {
+ return reflect.ValueOf(&n.u).Elem()
+}
+func (n *decNaked) ri() reflect.Value {
+ return reflect.ValueOf(&n.i).Elem()
+}
+func (n *decNaked) rf() reflect.Value {
+ return reflect.ValueOf(&n.f).Elem()
+}
+func (n *decNaked) rl() reflect.Value {
+ return reflect.ValueOf(&n.l).Elem()
+}
+func (n *decNaked) rs() reflect.Value {
+ return reflect.ValueOf(&n.s).Elem()
+}
+func (n *decNaked) rt() reflect.Value {
+ return reflect.ValueOf(&n.t).Elem()
+}
+func (n *decNaked) rb() reflect.Value {
+ return reflect.ValueOf(&n.b).Elem()
+}
+
+// --------------------------
+func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) {
+ rv.SetBytes(d.rawBytes())
+}
+
+func (d *Decoder) kString(f *codecFnInfo, rv reflect.Value) {
+ rv.SetString(d.d.DecodeString())
+}
+
+func (d *Decoder) kBool(f *codecFnInfo, rv reflect.Value) {
+ rv.SetBool(d.d.DecodeBool())
+}
+
+func (d *Decoder) kTime(f *codecFnInfo, rv reflect.Value) {
+ rv.Set(reflect.ValueOf(d.d.DecodeTime()))
+}
+
+func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
+ fv := d.d.DecodeFloat64()
+ if chkOvf.Float32(fv) {
+ d.errorf("float32 overflow: %v", fv)
+ }
+ rv.SetFloat(fv)
+}
+
+func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
+ rv.SetFloat(d.d.DecodeFloat64())
+}
+
+func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) {
+ rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), intBitsize))
+}
+
+func (d *Decoder) kInt8(f *codecFnInfo, rv reflect.Value) {
+ rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 8))
+}
+
+func (d *Decoder) kInt16(f *codecFnInfo, rv reflect.Value) {
+ rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 16))
+}
+
+func (d *Decoder) kInt32(f *codecFnInfo, rv reflect.Value) {
+ rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 32))
+}
+
+func (d *Decoder) kInt64(f *codecFnInfo, rv reflect.Value) {
+ rv.SetInt(d.d.DecodeInt64())
+}
+
+func (d *Decoder) kUint(f *codecFnInfo, rv reflect.Value) {
+ rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))
+}
+
+func (d *Decoder) kUintptr(f *codecFnInfo, rv reflect.Value) {
+ rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))
+}
+
+func (d *Decoder) kUint8(f *codecFnInfo, rv reflect.Value) {
+ rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 8))
+}
+
+func (d *Decoder) kUint16(f *codecFnInfo, rv reflect.Value) {
+ rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 16))
+}
+
+func (d *Decoder) kUint32(f *codecFnInfo, rv reflect.Value) {
+ rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 32))
+}
+
+func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) {
+ rv.SetUint(d.d.DecodeUint64())
+}
+
+// ----------------
+
+func (e *Encoder) kBool(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeBool(rv.Bool())
+}
+
+func (e *Encoder) kTime(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeTime(rv2i(rv).(time.Time))
+}
+
+func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) {
+ s := rv.String()
+ if e.h.StringToRaw {
+ e.e.EncodeStringBytesRaw(bytesView(s))
+ } else {
+ e.e.EncodeStringEnc(cUTF8, s)
+ }
+}
+
+func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeFloat64(rv.Float())
+}
+
+func (e *Encoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeFloat32(float32(rv.Float()))
+}
+
+func (e *Encoder) kInt(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeInt(rv.Int())
+}
+
+func (e *Encoder) kInt8(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeInt(rv.Int())
+}
+
+func (e *Encoder) kInt16(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeInt(rv.Int())
+}
+
+func (e *Encoder) kInt32(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeInt(rv.Int())
+}
+
+func (e *Encoder) kInt64(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeInt(rv.Int())
+}
+
+func (e *Encoder) kUint(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeUint(rv.Uint())
+}
+
+func (e *Encoder) kUint8(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeUint(rv.Uint())
+}
+
+func (e *Encoder) kUint16(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeUint(rv.Uint())
+}
+
+func (e *Encoder) kUint32(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeUint(rv.Uint())
+}
+
+func (e *Encoder) kUint64(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeUint(rv.Uint())
+}
+
+func (e *Encoder) kUintptr(f *codecFnInfo, rv reflect.Value) {
+ e.e.EncodeUint(rv.Uint())
+}
+
+func makeMapReflect(t reflect.Type, size int) reflect.Value {
+ if size < 0 {
+ return reflect.MakeMapWithSize(t, 4)
+ }
+ return reflect.MakeMapWithSize(t, size)
+}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/helper_internal.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/helper_internal.go
new file mode 100644
index 00000000000..4f5eb84362e
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/helper_internal.go
@@ -0,0 +1,89 @@
+// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+package codec
+
+// All non-std package dependencies live in this file,
+// so porting to different environment is easy (just update functions).
+
+func pruneSignExt(v []byte, pos bool) (n int) {
+ if len(v) < 2 {
+ } else if pos && v[0] == 0 {
+ for ; v[n] == 0 && n+1 < len(v) && (v[n+1]&(1<<7) == 0); n++ {
+ }
+ } else if !pos && v[0] == 0xff {
+ for ; v[n] == 0xff && n+1 < len(v) && (v[n+1]&(1<<7) != 0); n++ {
+ }
+ }
+ return
+}
+
+// GrowCap will return a new capacity for a slice, given the following:
+// - oldCap: current capacity
+// - unit: in-memory size of an element
+// - num: number of elements to add
+func growCap(oldCap, unit, num int) (newCap int) {
+ // appendslice logic (if cap < 1024, *2, else *1.25):
+ // leads to many copy calls, especially when copying bytes.
+ // bytes.Buffer model (2*cap + n): much better for bytes.
+ // smarter way is to take the byte-size of the appended element(type) into account
+
+ // maintain 3 thresholds:
+ // t1: if cap <= t1, newcap = 2x
+ // t2: if cap <= t2, newcap = 1.75x
+ // t3: if cap <= t3, newcap = 1.5x
+ // else newcap = 1.25x
+ //
+ // t1, t2, t3 >= 1024 always.
+ // i.e. if unit size >= 16, then always do 2x or 1.25x (ie t1, t2, t3 are all same)
+ //
+ // With this, appending for bytes increase by:
+ // 100% up to 4K
+ // 75% up to 8K
+ // 50% up to 16K
+ // 25% beyond that
+
+ // unit can be 0 e.g. for struct{}{}; handle that appropriately
+ var t1, t2, t3 int // thresholds
+ if unit <= 1 {
+ t1, t2, t3 = 4*1024, 8*1024, 16*1024
+ } else if unit < 16 {
+ t3 = 16 / unit * 1024
+ t1 = t3 * 1 / 4
+ t2 = t3 * 2 / 4
+ } else {
+ t1, t2, t3 = 1024, 1024, 1024
+ }
+
+ var x int // temporary variable
+
+ // x is multiplier here: one of 5, 6, 7 or 8; incr of 25%, 50%, 75% or 100% respectively
+ if oldCap <= t1 { // [0,t1]
+ x = 8
+ } else if oldCap > t3 { // (t3,infinity]
+ x = 5
+ } else if oldCap <= t2 { // (t1,t2]
+ x = 7
+ } else { // (t2,t3]
+ x = 6
+ }
+ newCap = x * oldCap / 4
+
+ if num > 0 {
+ newCap += num
+ }
+
+ // ensure newCap is a multiple of 64 (if it is > 64) or 16.
+ if newCap > 64 {
+ if x = newCap % 64; x != 0 {
+ x = newCap / 64
+ newCap = 64 * (x + 1)
+ }
+ } else {
+ if x = newCap % 16; x != 0 {
+ x = newCap / 16
+ newCap = 16 * (x + 1)
+ }
+ }
+ return
+}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/json.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/json.go
new file mode 100644
index 00000000000..5fc375f9286
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/json.go
@@ -0,0 +1,1491 @@
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+package codec
+
+// By default, this json support uses base64 encoding for bytes, because you cannot
+// store and read any arbitrary string in json (only unicode).
+// However, the user can configre how to encode/decode bytes.
+//
+// This library specifically supports UTF-8 for encoding and decoding only.
+//
+// Note that the library will happily encode/decode things which are not valid
+// json e.g. a map[int64]string. We do it for consistency. With valid json,
+// we will encode and decode appropriately.
+// Users can specify their map type if necessary to force it.
+//
+// Note:
+// - we cannot use strconv.Quote and strconv.Unquote because json quotes/unquotes differently.
+// We implement it here.
+
+// Top-level methods of json(End|Dec)Driver (which are implementations of (en|de)cDriver
+// MUST not call one-another.
+
+import (
+ "bytes"
+ "encoding/base64"
+ "math"
+ "reflect"
+ "strconv"
+ "time"
+ "unicode"
+ "unicode/utf16"
+ "unicode/utf8"
+)
+
+//--------------------------------
+
+var jsonLiterals = [...]byte{
+ '"', 't', 'r', 'u', 'e', '"',
+ '"', 'f', 'a', 'l', 's', 'e', '"',
+ '"', 'n', 'u', 'l', 'l', '"',
+}
+
+const (
+ jsonLitTrueQ = 0
+ jsonLitTrue = 1
+ jsonLitFalseQ = 6
+ jsonLitFalse = 7
+ // jsonLitNullQ = 13
+ jsonLitNull = 14
+)
+
+var (
+ jsonLiteral4True = jsonLiterals[jsonLitTrue+1 : jsonLitTrue+4]
+ jsonLiteral4False = jsonLiterals[jsonLitFalse+1 : jsonLitFalse+5]
+ jsonLiteral4Null = jsonLiterals[jsonLitNull+1 : jsonLitNull+4]
+)
+
+const (
+ jsonU4Chk2 = '0'
+ jsonU4Chk1 = 'a' - 10
+ jsonU4Chk0 = 'A' - 10
+
+ jsonScratchArrayLen = 64
+)
+
+const (
+ // If !jsonValidateSymbols, decoding will be faster, by skipping some checks:
+ // - If we see first character of null, false or true,
+ // do not validate subsequent characters.
+ // - e.g. if we see a n, assume null and skip next 3 characters,
+ // and do not validate they are ull.
+ // P.S. Do not expect a significant decoding boost from this.
+ jsonValidateSymbols = true
+
+ jsonSpacesOrTabsLen = 128
+
+ jsonAlwaysReturnInternString = false
+)
+
+var (
+ // jsonTabs and jsonSpaces are used as caches for indents
+ jsonTabs, jsonSpaces [jsonSpacesOrTabsLen]byte
+
+ jsonCharHtmlSafeSet bitset256
+ jsonCharSafeSet bitset256
+ jsonCharWhitespaceSet bitset256
+ jsonNumSet bitset256
+)
+
+func init() {
+ var i byte
+ for i = 0; i < jsonSpacesOrTabsLen; i++ {
+ jsonSpaces[i] = ' '
+ jsonTabs[i] = '\t'
+ }
+
+ // populate the safe values as true: note: ASCII control characters are (0-31)
+ // jsonCharSafeSet: all true except (0-31) " \
+ // jsonCharHtmlSafeSet: all true except (0-31) " \ < > &
+ for i = 32; i < utf8.RuneSelf; i++ {
+ switch i {
+ case '"', '\\':
+ case '<', '>', '&':
+ jsonCharSafeSet.set(i) // = true
+ default:
+ jsonCharSafeSet.set(i)
+ jsonCharHtmlSafeSet.set(i)
+ }
+ }
+ for i = 0; i <= utf8.RuneSelf; i++ {
+ switch i {
+ case ' ', '\t', '\r', '\n':
+ jsonCharWhitespaceSet.set(i)
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'e', 'E', '.', '+', '-':
+ jsonNumSet.set(i)
+ }
+ }
+}
+
+// ----------------
+
+type jsonEncDriverTypical struct {
+ jsonEncDriver
+}
+
+func (e *jsonEncDriverTypical) typical() {}
+
+func (e *jsonEncDriverTypical) WriteArrayStart(length int) {
+ e.w.writen1('[')
+ e.c = containerArrayStart
+}
+
+func (e *jsonEncDriverTypical) WriteArrayElem() {
+ if e.c != containerArrayStart {
+ e.w.writen1(',')
+ }
+ e.c = containerArrayElem
+}
+
+func (e *jsonEncDriverTypical) WriteArrayEnd() {
+ e.w.writen1(']')
+ e.c = containerArrayEnd
+}
+
+func (e *jsonEncDriverTypical) WriteMapStart(length int) {
+ e.w.writen1('{')
+ e.c = containerMapStart
+}
+
+func (e *jsonEncDriverTypical) WriteMapElemKey() {
+ if e.c != containerMapStart {
+ e.w.writen1(',')
+ }
+ e.c = containerMapKey
+}
+
+func (e *jsonEncDriverTypical) WriteMapElemValue() {
+ e.w.writen1(':')
+ e.c = containerMapValue
+}
+
+func (e *jsonEncDriverTypical) WriteMapEnd() {
+ e.w.writen1('}')
+ e.c = containerMapEnd
+}
+
+func (e *jsonEncDriverTypical) EncodeBool(b bool) {
+ if b {
+ e.w.writeb(jsonLiterals[jsonLitTrue : jsonLitTrue+4])
+ } else {
+ e.w.writeb(jsonLiterals[jsonLitFalse : jsonLitFalse+5])
+ }
+}
+
+func (e *jsonEncDriverTypical) EncodeFloat64(f float64) {
+ fmt, prec := jsonFloatStrconvFmtPrec(f)
+ e.w.writeb(strconv.AppendFloat(e.b[:0], f, fmt, prec, 64))
+}
+
+func (e *jsonEncDriverTypical) EncodeInt(v int64) {
+ e.w.writeb(strconv.AppendInt(e.b[:0], v, 10))
+}
+
+func (e *jsonEncDriverTypical) EncodeUint(v uint64) {
+ e.w.writeb(strconv.AppendUint(e.b[:0], v, 10))
+}
+
+func (e *jsonEncDriverTypical) EncodeFloat32(f float32) {
+ e.EncodeFloat64(float64(f))
+}
+
+// func (e *jsonEncDriverTypical) atEndOfEncode() {
+// if e.tw {
+// e.w.writen1(' ')
+// }
+// }
+
+// ----------------
+
+type jsonEncDriverGeneric struct {
+ jsonEncDriver
+ // ds string // indent string
+ di int8 // indent per
+ d bool // indenting?
+ dt bool // indent using tabs
+ dl uint16 // indent level
+ ks bool // map key as string
+ is byte // integer as string
+ _ byte // padding
+ _ [2]uint64 // padding
+}
+
+// indent is done as below:
+// - newline and indent are added before each mapKey or arrayElem
+// - newline and indent are added before each ending,
+// except there was no entry (so we can have {} or [])
+
+func (e *jsonEncDriverGeneric) reset() {
+ e.jsonEncDriver.reset()
+ e.d, e.dt, e.dl, e.di = false, false, 0, 0
+ if e.h.Indent > 0 {
+ e.d = true
+ e.di = int8(e.h.Indent)
+ } else if e.h.Indent < 0 {
+ e.d = true
+ e.dt = true
+ e.di = int8(-e.h.Indent)
+ }
+ e.ks = e.h.MapKeyAsString
+ e.is = e.h.IntegerAsString
+}
+
+func (e *jsonEncDriverGeneric) WriteArrayStart(length int) {
+ if e.d {
+ e.dl++
+ }
+ e.w.writen1('[')
+ e.c = containerArrayStart
+}
+
+func (e *jsonEncDriverGeneric) WriteArrayElem() {
+ if e.c != containerArrayStart {
+ e.w.writen1(',')
+ }
+ if e.d {
+ e.writeIndent()
+ }
+ e.c = containerArrayElem
+}
+
+func (e *jsonEncDriverGeneric) WriteArrayEnd() {
+ if e.d {
+ e.dl--
+ if e.c != containerArrayStart {
+ e.writeIndent()
+ }
+ }
+ e.w.writen1(']')
+ e.c = containerArrayEnd
+}
+
+func (e *jsonEncDriverGeneric) WriteMapStart(length int) {
+ if e.d {
+ e.dl++
+ }
+ e.w.writen1('{')
+ e.c = containerMapStart
+}
+
+func (e *jsonEncDriverGeneric) WriteMapElemKey() {
+ if e.c != containerMapStart {
+ e.w.writen1(',')
+ }
+ if e.d {
+ e.writeIndent()
+ }
+ e.c = containerMapKey
+}
+
+func (e *jsonEncDriverGeneric) WriteMapElemValue() {
+ if e.d {
+ e.w.writen2(':', ' ')
+ } else {
+ e.w.writen1(':')
+ }
+ e.c = containerMapValue
+}
+
+func (e *jsonEncDriverGeneric) WriteMapEnd() {
+ if e.d {
+ e.dl--
+ if e.c != containerMapStart {
+ e.writeIndent()
+ }
+ }
+ e.w.writen1('}')
+ e.c = containerMapEnd
+}
+
+func (e *jsonEncDriverGeneric) writeIndent() {
+ e.w.writen1('\n')
+ x := int(e.di) * int(e.dl)
+ if e.dt {
+ for x > jsonSpacesOrTabsLen {
+ e.w.writeb(jsonTabs[:])
+ x -= jsonSpacesOrTabsLen
+ }
+ e.w.writeb(jsonTabs[:x])
+ } else {
+ for x > jsonSpacesOrTabsLen {
+ e.w.writeb(jsonSpaces[:])
+ x -= jsonSpacesOrTabsLen
+ }
+ e.w.writeb(jsonSpaces[:x])
+ }
+}
+
+func (e *jsonEncDriverGeneric) EncodeBool(b bool) {
+ if e.ks && e.c == containerMapKey {
+ if b {
+ e.w.writeb(jsonLiterals[jsonLitTrueQ : jsonLitTrueQ+6])
+ } else {
+ e.w.writeb(jsonLiterals[jsonLitFalseQ : jsonLitFalseQ+7])
+ }
+ } else {
+ if b {
+ e.w.writeb(jsonLiterals[jsonLitTrue : jsonLitTrue+4])
+ } else {
+ e.w.writeb(jsonLiterals[jsonLitFalse : jsonLitFalse+5])
+ }
+ }
+}
+
+func (e *jsonEncDriverGeneric) EncodeFloat64(f float64) {
+ // instead of using 'g', specify whether to use 'e' or 'f'
+ fmt, prec := jsonFloatStrconvFmtPrec(f)
+
+ var blen int
+ if e.ks && e.c == containerMapKey {
+ blen = 2 + len(strconv.AppendFloat(e.b[1:1], f, fmt, prec, 64))
+ e.b[0] = '"'
+ e.b[blen-1] = '"'
+ } else {
+ blen = len(strconv.AppendFloat(e.b[:0], f, fmt, prec, 64))
+ }
+ e.w.writeb(e.b[:blen])
+}
+
+func (e *jsonEncDriverGeneric) EncodeInt(v int64) {
+ x := e.is
+ if x == 'A' || x == 'L' && (v > 1<<53 || v < -(1<<53)) || (e.ks && e.c == containerMapKey) {
+ blen := 2 + len(strconv.AppendInt(e.b[1:1], v, 10))
+ e.b[0] = '"'
+ e.b[blen-1] = '"'
+ e.w.writeb(e.b[:blen])
+ return
+ }
+ e.w.writeb(strconv.AppendInt(e.b[:0], v, 10))
+}
+
+func (e *jsonEncDriverGeneric) EncodeUint(v uint64) {
+ x := e.is
+ if x == 'A' || x == 'L' && v > 1<<53 || (e.ks && e.c == containerMapKey) {
+ blen := 2 + len(strconv.AppendUint(e.b[1:1], v, 10))
+ e.b[0] = '"'
+ e.b[blen-1] = '"'
+ e.w.writeb(e.b[:blen])
+ return
+ }
+ e.w.writeb(strconv.AppendUint(e.b[:0], v, 10))
+}
+
+func (e *jsonEncDriverGeneric) EncodeFloat32(f float32) {
+ // e.encodeFloat(float64(f), 32)
+ // always encode all floats as IEEE 64-bit floating point.
+ // It also ensures that we can decode in full precision even if into a float32,
+ // as what is written is always to float64 precision.
+ e.EncodeFloat64(float64(f))
+}
+
+// func (e *jsonEncDriverGeneric) atEndOfEncode() {
+// if e.tw {
+// if e.d {
+// e.w.writen1('\n')
+// } else {
+// e.w.writen1(' ')
+// }
+// }
+// }
+
+// --------------------
+
+type jsonEncDriver struct {
+ noBuiltInTypes
+ e *Encoder
+ h *JsonHandle
+ w *encWriterSwitch
+ se extWrapper
+ // ---- cpu cache line boundary?
+ bs []byte // scratch
+ // ---- cpu cache line boundary?
+ // scratch: encode time, etc.
+ // include scratch buffer and padding, but leave space for containerstate
+ b [jsonScratchArrayLen + 8 + 8 - 1]byte
+ c containerState
+ // _ [2]uint64 // padding
+}
+
+func (e *jsonEncDriver) EncodeNil() {
+ // We always encode nil as just null (never in quotes)
+ // This allows us to easily decode if a nil in the json stream
+ // ie if initial token is n.
+ e.w.writeb(jsonLiterals[jsonLitNull : jsonLitNull+4])
+
+ // if e.h.MapKeyAsString && e.c == containerMapKey {
+ // e.w.writeb(jsonLiterals[jsonLitNullQ : jsonLitNullQ+6])
+ // } else {
+ // e.w.writeb(jsonLiterals[jsonLitNull : jsonLitNull+4])
+ // }
+}
+
+func (e *jsonEncDriver) EncodeTime(t time.Time) {
+ // Do NOT use MarshalJSON, as it allocates internally.
+ // instead, we call AppendFormat directly, using our scratch buffer (e.b)
+ if t.IsZero() {
+ e.EncodeNil()
+ } else {
+ e.b[0] = '"'
+ b := t.AppendFormat(e.b[1:1], time.RFC3339Nano)
+ e.b[len(b)+1] = '"'
+ e.w.writeb(e.b[:len(b)+2])
+ }
+ // v, err := t.MarshalJSON(); if err != nil { e.e.error(err) } e.w.writeb(v)
+}
+
+func (e *jsonEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Encoder) {
+ if v := ext.ConvertExt(rv); v == nil {
+ e.EncodeNil()
+ } else {
+ en.encode(v)
+ }
+}
+
+func (e *jsonEncDriver) EncodeRawExt(re *RawExt, en *Encoder) {
+ // only encodes re.Value (never re.Data)
+ if re.Value == nil {
+ e.EncodeNil()
+ } else {
+ en.encode(re.Value)
+ }
+}
+
+func (e *jsonEncDriver) EncodeString(c charEncoding, v string) {
+ e.quoteStr(v)
+}
+
+func (e *jsonEncDriver) EncodeStringEnc(c charEncoding, v string) {
+ e.quoteStr(v)
+}
+
+func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
+ // if encoding raw bytes and RawBytesExt is configured, use it to encode
+ if v == nil {
+ e.EncodeNil()
+ return
+ }
+ if c == cRAW {
+ if e.se.InterfaceExt != nil {
+ e.EncodeExt(v, 0, &e.se, e.e)
+ return
+ }
+
+ slen := base64.StdEncoding.EncodedLen(len(v)) + 2
+ if cap(e.bs) >= slen {
+ e.bs = e.bs[:slen]
+ } else {
+ e.bs = make([]byte, slen)
+ }
+ e.bs[0] = '"'
+ base64.StdEncoding.Encode(e.bs[1:], v)
+ e.bs[slen-1] = '"'
+ e.w.writeb(e.bs)
+ } else {
+ e.quoteStr(stringView(v))
+ }
+}
+
+func (e *jsonEncDriver) EncodeStringBytesRaw(v []byte) {
+ // if encoding raw bytes and RawBytesExt is configured, use it to encode
+ if v == nil {
+ e.EncodeNil()
+ return
+ }
+ if e.se.InterfaceExt != nil {
+ e.EncodeExt(v, 0, &e.se, e.e)
+ return
+ }
+
+ slen := base64.StdEncoding.EncodedLen(len(v)) + 2
+ if cap(e.bs) >= slen {
+ e.bs = e.bs[:slen]
+ } else {
+ e.bs = make([]byte, slen)
+ }
+ e.bs[0] = '"'
+ base64.StdEncoding.Encode(e.bs[1:], v)
+ e.bs[slen-1] = '"'
+ e.w.writeb(e.bs)
+}
+
+func (e *jsonEncDriver) EncodeAsis(v []byte) {
+ e.w.writeb(v)
+}
+
+func (e *jsonEncDriver) quoteStr(s string) {
+ // adapted from std pkg encoding/json
+ const hex = "0123456789abcdef"
+ w := e.w
+ htmlasis := e.h.HTMLCharsAsIs
+ w.writen1('"')
+ var start int
+ for i, slen := 0, len(s); i < slen; {
+ // encode all bytes < 0x20 (except \r, \n).
+ // also encode < > & to prevent security holes when served to some browsers.
+ if b := s[i]; b < utf8.RuneSelf {
+ // if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
+ // if (htmlasis && jsonCharSafeSet.isset(b)) || jsonCharHtmlSafeSet.isset(b) {
+ if jsonCharHtmlSafeSet.isset(b) || (htmlasis && jsonCharSafeSet.isset(b)) {
+ i++
+ continue
+ }
+ if start < i {
+ w.writestr(s[start:i])
+ }
+ switch b {
+ case '\\', '"':
+ w.writen2('\\', b)
+ case '\n':
+ w.writen2('\\', 'n')
+ case '\r':
+ w.writen2('\\', 'r')
+ case '\b':
+ w.writen2('\\', 'b')
+ case '\f':
+ w.writen2('\\', 'f')
+ case '\t':
+ w.writen2('\\', 't')
+ default:
+ w.writestr(`\u00`)
+ w.writen2(hex[b>>4], hex[b&0xF])
+ }
+ i++
+ start = i
+ continue
+ }
+ c, size := utf8.DecodeRuneInString(s[i:])
+ if c == utf8.RuneError && size == 1 {
+ if start < i {
+ w.writestr(s[start:i])
+ }
+ w.writestr(`\ufffd`)
+ i += size
+ start = i
+ continue
+ }
+ // U+2028 is LINE SEPARATOR. U+2029 is PARAGRAPH SEPARATOR.
+ // Both technically valid JSON, but bomb on JSONP, so fix here unconditionally.
+ if c == '\u2028' || c == '\u2029' {
+ if start < i {
+ w.writestr(s[start:i])
+ }
+ w.writestr(`\u202`)
+ w.writen1(hex[c&0xF])
+ i += size
+ start = i
+ continue
+ }
+ i += size
+ }
+ if start < len(s) {
+ w.writestr(s[start:])
+ }
+ w.writen1('"')
+}
+
+func (e *jsonEncDriver) atEndOfEncode() {
+ // if e.c == 0 { // scalar written, output space
+ // e.w.writen1(' ')
+ // } else if e.h.TermWhitespace { // container written, output new-line
+ // e.w.writen1('\n')
+ // }
+ if e.h.TermWhitespace {
+ if e.c == 0 { // scalar written, output space
+ e.w.writen1(' ')
+ } else { // container written, output new-line
+ e.w.writen1('\n')
+ }
+ }
+
+ // e.c = 0
+}
+
+type jsonDecDriver struct {
+ noBuiltInTypes
+ d *Decoder
+ h *JsonHandle
+ r *decReaderSwitch
+ se extWrapper
+
+ // ---- writable fields during execution --- *try* to keep in sep cache line
+
+ c containerState
+ // tok is used to store the token read right after skipWhiteSpace.
+ tok uint8
+ fnull bool // found null from appendStringAsBytes
+ bs []byte // scratch. Initialized from b. Used for parsing strings or numbers.
+ bstr [8]byte // scratch used for string \UXXX parsing
+ // ---- cpu cache line boundary?
+ b [jsonScratchArrayLen]byte // scratch 1, used for parsing strings or numbers or time.Time
+ b2 [jsonScratchArrayLen]byte // scratch 2, used only for readUntil, decNumBytes
+
+ // _ [3]uint64 // padding
+ // n jsonNum
+}
+
+// func jsonIsWS(b byte) bool {
+// // return b == ' ' || b == '\t' || b == '\r' || b == '\n'
+// return jsonCharWhitespaceSet.isset(b)
+// }
+
+func (d *jsonDecDriver) uncacheRead() {
+ if d.tok != 0 {
+ d.r.unreadn1()
+ d.tok = 0
+ }
+}
+
+func (d *jsonDecDriver) ReadMapStart() int {
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ const xc uint8 = '{'
+ if d.tok != xc {
+ d.d.errorf("read map - expect char '%c' but got char '%c'", xc, d.tok)
+ }
+ d.tok = 0
+ d.c = containerMapStart
+ return -1
+}
+
+func (d *jsonDecDriver) ReadArrayStart() int {
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ const xc uint8 = '['
+ if d.tok != xc {
+ d.d.errorf("read array - expect char '%c' but got char '%c'", xc, d.tok)
+ }
+ d.tok = 0
+ d.c = containerArrayStart
+ return -1
+}
+
+func (d *jsonDecDriver) CheckBreak() bool {
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ return d.tok == '}' || d.tok == ']'
+}
+
+// For the ReadXXX methods below, we could just delegate to helper functions
+// readContainerState(c containerState, xc uint8, check bool)
+// - ReadArrayElem would become:
+// readContainerState(containerArrayElem, ',', d.c != containerArrayStart)
+//
+// However, until mid-stack inlining comes in go1.11 which supports inlining of
+// one-liners, we explicitly write them all 5 out to elide the extra func call.
+//
+// TODO: For Go 1.11, if inlined, consider consolidating these.
+
+func (d *jsonDecDriver) ReadArrayElem() {
+ const xc uint8 = ','
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ if d.c != containerArrayStart {
+ if d.tok != xc {
+ d.d.errorf("read array element - expect char '%c' but got char '%c'", xc, d.tok)
+ }
+ d.tok = 0
+ }
+ d.c = containerArrayElem
+}
+
+func (d *jsonDecDriver) ReadArrayEnd() {
+ const xc uint8 = ']'
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ if d.tok != xc {
+ d.d.errorf("read array end - expect char '%c' but got char '%c'", xc, d.tok)
+ }
+ d.tok = 0
+ d.c = containerArrayEnd
+}
+
+func (d *jsonDecDriver) ReadMapElemKey() {
+ const xc uint8 = ','
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ if d.c != containerMapStart {
+ if d.tok != xc {
+ d.d.errorf("read map key - expect char '%c' but got char '%c'", xc, d.tok)
+ }
+ d.tok = 0
+ }
+ d.c = containerMapKey
+}
+
+func (d *jsonDecDriver) ReadMapElemValue() {
+ const xc uint8 = ':'
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ if d.tok != xc {
+ d.d.errorf("read map value - expect char '%c' but got char '%c'", xc, d.tok)
+ }
+ d.tok = 0
+ d.c = containerMapValue
+}
+
+func (d *jsonDecDriver) ReadMapEnd() {
+ const xc uint8 = '}'
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ if d.tok != xc {
+ d.d.errorf("read map end - expect char '%c' but got char '%c'", xc, d.tok)
+ }
+ d.tok = 0
+ d.c = containerMapEnd
+}
+
+// func (d *jsonDecDriver) readLit(length, fromIdx uint8) {
+// // length here is always less than 8 (literals are: null, true, false)
+// bs := d.r.readx(int(length))
+// d.tok = 0
+// if jsonValidateSymbols && !bytes.Equal(bs, jsonLiterals[fromIdx:fromIdx+length]) {
+// d.d.errorf("expecting %s: got %s", jsonLiterals[fromIdx:fromIdx+length], bs)
+// }
+// }
+
+func (d *jsonDecDriver) readLit4True() {
+ bs := d.r.readx(3)
+ d.tok = 0
+ if jsonValidateSymbols && !bytes.Equal(bs, jsonLiteral4True) {
+ d.d.errorf("expecting %s: got %s", jsonLiteral4True, bs)
+ }
+}
+
+func (d *jsonDecDriver) readLit4False() {
+ bs := d.r.readx(4)
+ d.tok = 0
+ if jsonValidateSymbols && !bytes.Equal(bs, jsonLiteral4False) {
+ d.d.errorf("expecting %s: got %s", jsonLiteral4False, bs)
+ }
+}
+
+func (d *jsonDecDriver) readLit4Null() {
+ bs := d.r.readx(3)
+ d.tok = 0
+ if jsonValidateSymbols && !bytes.Equal(bs, jsonLiteral4Null) {
+ d.d.errorf("expecting %s: got %s", jsonLiteral4Null, bs)
+ }
+}
+
+func (d *jsonDecDriver) TryDecodeAsNil() bool {
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ // we shouldn't try to see if "null" was here, right?
+ // only the plain string: `null` denotes a nil (ie not quotes)
+ if d.tok == 'n' {
+ d.readLit4Null()
+ return true
+ }
+ return false
+}
+
+func (d *jsonDecDriver) DecodeBool() (v bool) {
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ fquot := d.c == containerMapKey && d.tok == '"'
+ if fquot {
+ d.tok = d.r.readn1()
+ }
+ switch d.tok {
+ case 'f':
+ d.readLit4False()
+ // v = false
+ case 't':
+ d.readLit4True()
+ v = true
+ default:
+ d.d.errorf("decode bool: got first char %c", d.tok)
+ // v = false // "unreachable"
+ }
+ if fquot {
+ d.r.readn1()
+ }
+ return
+}
+
+func (d *jsonDecDriver) DecodeTime() (t time.Time) {
+ // read string, and pass the string into json.unmarshal
+ d.appendStringAsBytes()
+ if d.fnull {
+ return
+ }
+ t, err := time.Parse(time.RFC3339, stringView(d.bs))
+ if err != nil {
+ d.d.errorv(err)
+ }
+ return
+}
+
+func (d *jsonDecDriver) ContainerType() (vt valueType) {
+ // check container type by checking the first char
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+
+ // optimize this, so we don't do 4 checks but do one computation.
+ // return jsonContainerSet[d.tok]
+
+ // ContainerType is mostly called for Map and Array,
+ // so this conditional is good enough (max 2 checks typically)
+ if b := d.tok; b == '{' {
+ return valueTypeMap
+ } else if b == '[' {
+ return valueTypeArray
+ } else if b == 'n' {
+ return valueTypeNil
+ } else if b == '"' {
+ return valueTypeString
+ }
+ return valueTypeUnset
+}
+
+func (d *jsonDecDriver) decNumBytes() (bs []byte) {
+ // stores num bytes in d.bs
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ if d.tok == '"' {
+ bs = d.r.readUntil(d.b2[:0], '"')
+ bs = bs[:len(bs)-1]
+ } else {
+ d.r.unreadn1()
+ bs = d.r.readTo(d.bs[:0], &jsonNumSet)
+ }
+ d.tok = 0
+ return bs
+}
+
+func (d *jsonDecDriver) DecodeUint64() (u uint64) {
+ bs := d.decNumBytes()
+ if len(bs) == 0 {
+ return
+ }
+ n, neg, badsyntax, overflow := jsonParseInteger(bs)
+ if overflow {
+ d.d.errorf("overflow parsing unsigned integer: %s", bs)
+ } else if neg {
+ d.d.errorf("minus found parsing unsigned integer: %s", bs)
+ } else if badsyntax {
+ // fallback: try to decode as float, and cast
+ n = d.decUint64ViaFloat(stringView(bs))
+ }
+ return n
+}
+
+func (d *jsonDecDriver) DecodeInt64() (i int64) {
+ const cutoff = uint64(1 << uint(64-1))
+ bs := d.decNumBytes()
+ if len(bs) == 0 {
+ return
+ }
+ n, neg, badsyntax, overflow := jsonParseInteger(bs)
+ if overflow {
+ d.d.errorf("overflow parsing integer: %s", bs)
+ } else if badsyntax {
+ // d.d.errorf("invalid syntax for integer: %s", bs)
+ // fallback: try to decode as float, and cast
+ if neg {
+ n = d.decUint64ViaFloat(stringView(bs[1:]))
+ } else {
+ n = d.decUint64ViaFloat(stringView(bs))
+ }
+ }
+ if neg {
+ if n > cutoff {
+ d.d.errorf("overflow parsing integer: %s", bs)
+ }
+ i = -(int64(n))
+ } else {
+ if n >= cutoff {
+ d.d.errorf("overflow parsing integer: %s", bs)
+ }
+ i = int64(n)
+ }
+ return
+}
+
+func (d *jsonDecDriver) decUint64ViaFloat(s string) (u uint64) {
+ if len(s) == 0 {
+ return
+ }
+ f, err := strconv.ParseFloat(s, 64)
+ if err != nil {
+ d.d.errorf("invalid syntax for integer: %s", s)
+ // d.d.errorv(err)
+ }
+ fi, ff := math.Modf(f)
+ if ff > 0 {
+ d.d.errorf("fractional part found parsing integer: %s", s)
+ } else if fi > float64(math.MaxUint64) {
+ d.d.errorf("overflow parsing integer: %s", s)
+ }
+ return uint64(fi)
+}
+
+func (d *jsonDecDriver) DecodeFloat64() (f float64) {
+ bs := d.decNumBytes()
+ if len(bs) == 0 {
+ return
+ }
+ f, err := strconv.ParseFloat(stringView(bs), 64)
+ if err != nil {
+ d.d.errorv(err)
+ }
+ return
+}
+
+func (d *jsonDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
+ if ext == nil {
+ re := rv.(*RawExt)
+ re.Tag = xtag
+ d.d.decode(&re.Value)
+ } else {
+ var v interface{}
+ d.d.decode(&v)
+ ext.UpdateExt(rv, v)
+ }
+ return
+}
+
+func (d *jsonDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) {
+ // if decoding into raw bytes, and the RawBytesExt is configured, use it to decode.
+ if d.se.InterfaceExt != nil {
+ bsOut = bs
+ d.DecodeExt(&bsOut, 0, &d.se)
+ return
+ }
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ // check if an "array" of uint8's (see ContainerType for how to infer if an array)
+ if d.tok == '[' {
+ bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d)
+ return
+ }
+ d.appendStringAsBytes()
+ // base64 encodes []byte{} as "", and we encode nil []byte as null.
+ // Consequently, base64 should decode null as a nil []byte, and "" as an empty []byte{}.
+ // appendStringAsBytes returns a zero-len slice for both, so as not to reset d.bs.
+ // However, it sets a fnull field to true, so we can check if a null was found.
+ if len(d.bs) == 0 {
+ if d.fnull {
+ return nil
+ }
+ return []byte{}
+ }
+ bs0 := d.bs
+ slen := base64.StdEncoding.DecodedLen(len(bs0))
+ if slen <= cap(bs) {
+ bsOut = bs[:slen]
+ } else if zerocopy && slen <= cap(d.b2) {
+ bsOut = d.b2[:slen]
+ } else {
+ bsOut = make([]byte, slen)
+ }
+ slen2, err := base64.StdEncoding.Decode(bsOut, bs0)
+ if err != nil {
+ d.d.errorf("error decoding base64 binary '%s': %v", bs0, err)
+ return nil
+ }
+ if slen != slen2 {
+ bsOut = bsOut[:slen2]
+ }
+ return
+}
+
+func (d *jsonDecDriver) DecodeString() (s string) {
+ d.appendStringAsBytes()
+ return d.bsToString()
+}
+
+func (d *jsonDecDriver) DecodeStringAsBytes() (s []byte) {
+ d.appendStringAsBytes()
+ return d.bs
+}
+
+func (d *jsonDecDriver) appendStringAsBytes() {
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+
+ d.fnull = false
+ if d.tok != '"' {
+ // d.d.errorf("expect char '%c' but got char '%c'", '"', d.tok)
+ // handle non-string scalar: null, true, false or a number
+ switch d.tok {
+ case 'n':
+ d.readLit4Null()
+ d.bs = d.bs[:0]
+ d.fnull = true
+ case 'f':
+ d.readLit4False()
+ d.bs = d.bs[:5]
+ copy(d.bs, "false")
+ case 't':
+ d.readLit4True()
+ d.bs = d.bs[:4]
+ copy(d.bs, "true")
+ default:
+ // try to parse a valid number
+ bs := d.decNumBytes()
+ if len(bs) <= cap(d.bs) {
+ d.bs = d.bs[:len(bs)]
+ } else {
+ d.bs = make([]byte, len(bs))
+ }
+ copy(d.bs, bs)
+ }
+ return
+ }
+
+ d.tok = 0
+ r := d.r
+ var cs = r.readUntil(d.b2[:0], '"')
+ var cslen = uint(len(cs))
+ var c uint8
+ v := d.bs[:0]
+ // append on each byte seen can be expensive, so we just
+ // keep track of where we last read a contiguous set of
+ // non-special bytes (using cursor variable),
+ // and when we see a special byte
+ // e.g. end-of-slice, " or \,
+ // we will append the full range into the v slice before proceeding
+ var i, cursor uint
+ for {
+ if i == cslen {
+ v = append(v, cs[cursor:]...)
+ cs = r.readUntil(d.b2[:0], '"')
+ cslen = uint(len(cs))
+ i, cursor = 0, 0
+ }
+ c = cs[i]
+ if c == '"' {
+ v = append(v, cs[cursor:i]...)
+ break
+ }
+ if c != '\\' {
+ i++
+ continue
+ }
+ v = append(v, cs[cursor:i]...)
+ i++
+ c = cs[i]
+ switch c {
+ case '"', '\\', '/', '\'':
+ v = append(v, c)
+ case 'b':
+ v = append(v, '\b')
+ case 'f':
+ v = append(v, '\f')
+ case 'n':
+ v = append(v, '\n')
+ case 'r':
+ v = append(v, '\r')
+ case 't':
+ v = append(v, '\t')
+ case 'u':
+ var r rune
+ var rr uint32
+ if cslen < i+4 {
+ d.d.errorf("need at least 4 more bytes for unicode sequence")
+ }
+ var j uint
+ for _, c = range cs[i+1 : i+5] { // bounds-check-elimination
+ // best to use explicit if-else
+ // - not a table, etc which involve memory loads, array lookup with bounds checks, etc
+ if c >= '0' && c <= '9' {
+ rr = rr*16 + uint32(c-jsonU4Chk2)
+ } else if c >= 'a' && c <= 'f' {
+ rr = rr*16 + uint32(c-jsonU4Chk1)
+ } else if c >= 'A' && c <= 'F' {
+ rr = rr*16 + uint32(c-jsonU4Chk0)
+ } else {
+ r = unicode.ReplacementChar
+ i += 4
+ goto encode_rune
+ }
+ }
+ r = rune(rr)
+ i += 4
+ if utf16.IsSurrogate(r) {
+ if len(cs) >= int(i+6) {
+ var cx = cs[i+1:][:6:6] // [:6] affords bounds-check-elimination
+ if cx[0] == '\\' && cx[1] == 'u' {
+ i += 2
+ var rr1 uint32
+ for j = 2; j < 6; j++ {
+ c = cx[j]
+ if c >= '0' && c <= '9' {
+ rr = rr*16 + uint32(c-jsonU4Chk2)
+ } else if c >= 'a' && c <= 'f' {
+ rr = rr*16 + uint32(c-jsonU4Chk1)
+ } else if c >= 'A' && c <= 'F' {
+ rr = rr*16 + uint32(c-jsonU4Chk0)
+ } else {
+ r = unicode.ReplacementChar
+ i += 4
+ goto encode_rune
+ }
+ }
+ r = utf16.DecodeRune(r, rune(rr1))
+ i += 4
+ goto encode_rune
+ }
+ }
+ r = unicode.ReplacementChar
+ }
+ encode_rune:
+ w2 := utf8.EncodeRune(d.bstr[:], r)
+ v = append(v, d.bstr[:w2]...)
+ default:
+ d.d.errorf("unsupported escaped value: %c", c)
+ }
+ i++
+ cursor = i
+ }
+ d.bs = v
+}
+
+func (d *jsonDecDriver) nakedNum(z *decNaked, bs []byte) (err error) {
+ const cutoff = uint64(1 << uint(64-1))
+
+ var n uint64
+ var neg, badsyntax, overflow bool
+
+ if len(bs) == 0 {
+ if d.h.PreferFloat {
+ z.v = valueTypeFloat
+ z.f = 0
+ } else if d.h.SignedInteger {
+ z.v = valueTypeInt
+ z.i = 0
+ } else {
+ z.v = valueTypeUint
+ z.u = 0
+ }
+ return
+ }
+ if d.h.PreferFloat {
+ goto F
+ }
+ n, neg, badsyntax, overflow = jsonParseInteger(bs)
+ if badsyntax || overflow {
+ goto F
+ }
+ if neg {
+ if n > cutoff {
+ goto F
+ }
+ z.v = valueTypeInt
+ z.i = -(int64(n))
+ } else if d.h.SignedInteger {
+ if n >= cutoff {
+ goto F
+ }
+ z.v = valueTypeInt
+ z.i = int64(n)
+ } else {
+ z.v = valueTypeUint
+ z.u = n
+ }
+ return
+F:
+ z.v = valueTypeFloat
+ z.f, err = strconv.ParseFloat(stringView(bs), 64)
+ return
+}
+
+func (d *jsonDecDriver) bsToString() string {
+ // if x := d.s.sc; x != nil && x.so && x.st == '}' { // map key
+ if jsonAlwaysReturnInternString || d.c == containerMapKey {
+ return d.d.string(d.bs)
+ }
+ return string(d.bs)
+}
+
+func (d *jsonDecDriver) DecodeNaked() {
+ z := d.d.naked()
+ // var decodeFurther bool
+
+ if d.tok == 0 {
+ d.tok = d.r.skip(&jsonCharWhitespaceSet)
+ }
+ switch d.tok {
+ case 'n':
+ d.readLit4Null()
+ z.v = valueTypeNil
+ case 'f':
+ d.readLit4False()
+ z.v = valueTypeBool
+ z.b = false
+ case 't':
+ d.readLit4True()
+ z.v = valueTypeBool
+ z.b = true
+ case '{':
+ z.v = valueTypeMap // don't consume. kInterfaceNaked will call ReadMapStart
+ case '[':
+ z.v = valueTypeArray // don't consume. kInterfaceNaked will call ReadArrayStart
+ case '"':
+ // if a string, and MapKeyAsString, then try to decode it as a nil, bool or number first
+ d.appendStringAsBytes()
+ if len(d.bs) > 0 && d.c == containerMapKey && d.h.MapKeyAsString {
+ switch stringView(d.bs) {
+ case "null":
+ z.v = valueTypeNil
+ case "true":
+ z.v = valueTypeBool
+ z.b = true
+ case "false":
+ z.v = valueTypeBool
+ z.b = false
+ default:
+ // check if a number: float, int or uint
+ if err := d.nakedNum(z, d.bs); err != nil {
+ z.v = valueTypeString
+ z.s = d.bsToString()
+ }
+ }
+ } else {
+ z.v = valueTypeString
+ z.s = d.bsToString()
+ }
+ default: // number
+ bs := d.decNumBytes()
+ if len(bs) == 0 {
+ d.d.errorf("decode number from empty string")
+ return
+ }
+ if err := d.nakedNum(z, bs); err != nil {
+ d.d.errorf("decode number from %s: %v", bs, err)
+ return
+ }
+ }
+ // if decodeFurther {
+ // d.s.sc.retryRead()
+ // }
+}
+
+//----------------------
+
+// JsonHandle is a handle for JSON encoding format.
+//
+// Json is comprehensively supported:
+// - decodes numbers into interface{} as int, uint or float64
+// based on how the number looks and some config parameters e.g. PreferFloat, SignedInt, etc.
+// - decode integers from float formatted numbers e.g. 1.27e+8
+// - decode any json value (numbers, bool, etc) from quoted strings
+// - configurable way to encode/decode []byte .
+// by default, encodes and decodes []byte using base64 Std Encoding
+// - UTF-8 support for encoding and decoding
+//
+// It has better performance than the json library in the standard library,
+// by leveraging the performance improvements of the codec library.
+//
+// In addition, it doesn't read more bytes than necessary during a decode, which allows
+// reading multiple values from a stream containing json and non-json content.
+// For example, a user can read a json value, then a cbor value, then a msgpack value,
+// all from the same stream in sequence.
+//
+// Note that, when decoding quoted strings, invalid UTF-8 or invalid UTF-16 surrogate pairs are
+// not treated as an error. Instead, they are replaced by the Unicode replacement character U+FFFD.
+type JsonHandle struct {
+ textEncodingType
+ BasicHandle
+
+ // Indent indicates how a value is encoded.
+ // - If positive, indent by that number of spaces.
+ // - If negative, indent by that number of tabs.
+ Indent int8
+
+ // IntegerAsString controls how integers (signed and unsigned) are encoded.
+ //
+ // Per the JSON Spec, JSON numbers are 64-bit floating point numbers.
+ // Consequently, integers > 2^53 cannot be represented as a JSON number without losing precision.
+ // This can be mitigated by configuring how to encode integers.
+ //
+ // IntegerAsString interpretes the following values:
+ // - if 'L', then encode integers > 2^53 as a json string.
+ // - if 'A', then encode all integers as a json string
+ // containing the exact integer representation as a decimal.
+ // - else encode all integers as a json number (default)
+ IntegerAsString byte
+
+ // HTMLCharsAsIs controls how to encode some special characters to html: < > &
+ //
+ // By default, we encode them as \uXXX
+ // to prevent security holes when served from some browsers.
+ HTMLCharsAsIs bool
+
+ // PreferFloat says that we will default to decoding a number as a float.
+ // If not set, we will examine the characters of the number and decode as an
+ // integer type if it doesn't have any of the characters [.eE].
+ PreferFloat bool
+
+ // TermWhitespace says that we add a whitespace character
+ // at the end of an encoding.
+ //
+ // The whitespace is important, especially if using numbers in a context
+ // where multiple items are written to a stream.
+ TermWhitespace bool
+
+ // MapKeyAsString says to encode all map keys as strings.
+ //
+ // Use this to enforce strict json output.
+ // The only caveat is that nil value is ALWAYS written as null (never as "null")
+ MapKeyAsString bool
+
+ // _ [2]byte // padding
+
+ // Note: below, we store hardly-used items e.g. RawBytesExt is cached in the (en|de)cDriver.
+
+ // RawBytesExt, if configured, is used to encode and decode raw bytes in a custom way.
+ // If not configured, raw bytes are encoded to/from base64 text.
+ RawBytesExt InterfaceExt
+
+ _ [2]uint64 // padding
+}
+
+// Name returns the name of the handle: json
+func (h *JsonHandle) Name() string { return "json" }
+func (h *JsonHandle) hasElemSeparators() bool { return true }
+func (h *JsonHandle) typical() bool {
+ return h.Indent == 0 && !h.MapKeyAsString && h.IntegerAsString != 'A' && h.IntegerAsString != 'L'
+}
+
+type jsonTypical interface {
+ typical()
+}
+
+func (h *JsonHandle) recreateEncDriver(ed encDriver) (v bool) {
+ _, v = ed.(jsonTypical)
+ return v != h.typical()
+}
+
+// SetInterfaceExt sets an extension
+func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
+ return h.SetExt(rt, tag, &extWrapper{bytesExtFailer{}, ext})
+}
+
+func (h *JsonHandle) newEncDriver(e *Encoder) (ee encDriver) {
+ var hd *jsonEncDriver
+ if h.typical() {
+ var v jsonEncDriverTypical
+ ee = &v
+ hd = &v.jsonEncDriver
+ } else {
+ var v jsonEncDriverGeneric
+ ee = &v
+ hd = &v.jsonEncDriver
+ }
+ hd.e, hd.h, hd.bs = e, h, hd.b[:0]
+ hd.se.BytesExt = bytesExtFailer{}
+ ee.reset()
+ return
+}
+
+func (h *JsonHandle) newDecDriver(d *Decoder) decDriver {
+ // d := jsonDecDriver{r: r.(*bytesDecReader), h: h}
+ hd := jsonDecDriver{d: d, h: h}
+ hd.se.BytesExt = bytesExtFailer{}
+ hd.bs = hd.b[:0]
+ hd.reset()
+ return &hd
+}
+
+func (e *jsonEncDriver) reset() {
+ e.w = e.e.w
+ e.se.InterfaceExt = e.h.RawBytesExt
+ if e.bs != nil {
+ e.bs = e.bs[:0]
+ }
+ e.c = 0
+}
+
+func (d *jsonDecDriver) reset() {
+ d.r = d.d.r
+ d.se.InterfaceExt = d.h.RawBytesExt
+ if d.bs != nil {
+ d.bs = d.bs[:0]
+ }
+ d.c, d.tok = 0, 0
+ // d.n.reset()
+}
+
+func jsonFloatStrconvFmtPrec(f float64) (fmt byte, prec int) {
+ prec = -1
+ var abs = math.Abs(f)
+ if abs != 0 && (abs < 1e-6 || abs >= 1e21) {
+ fmt = 'e'
+ } else {
+ fmt = 'f'
+ // set prec to 1 iff mod is 0.
+ // better than using jsonIsFloatBytesB2 to check if a . or E in the float bytes.
+ // this ensures that every float has an e or .0 in it.
+ if abs <= 1 {
+ if abs == 0 || abs == 1 {
+ prec = 1
+ }
+ } else if _, mod := math.Modf(abs); mod == 0 {
+ prec = 1
+ }
+ }
+ return
+}
+
+// custom-fitted version of strconv.Parse(Ui|I)nt.
+// Also ensures we don't have to search for .eE to determine if a float or not.
+// Note: s CANNOT be a zero-length slice.
+func jsonParseInteger(s []byte) (n uint64, neg, badSyntax, overflow bool) {
+ const maxUint64 = (1<<64 - 1)
+ const cutoff = maxUint64/10 + 1
+
+ if len(s) == 0 { // bounds-check-elimination
+ // treat empty string as zero value
+ // badSyntax = true
+ return
+ }
+ switch s[0] {
+ case '+':
+ s = s[1:]
+ case '-':
+ s = s[1:]
+ neg = true
+ }
+ for _, c := range s {
+ if c < '0' || c > '9' {
+ badSyntax = true
+ return
+ }
+ // unsigned integers don't overflow well on multiplication, so check cutoff here
+ // e.g. (maxUint64-5)*10 doesn't overflow well ...
+ if n >= cutoff {
+ overflow = true
+ return
+ }
+ n *= 10
+ n1 := n + uint64(c-'0')
+ if n1 < n || n1 > maxUint64 {
+ overflow = true
+ return
+ }
+ n = n1
+ }
+ return
+}
+
+var _ decDriver = (*jsonDecDriver)(nil)
+var _ encDriver = (*jsonEncDriverGeneric)(nil)
+var _ encDriver = (*jsonEncDriverTypical)(nil)
+var _ jsonTypical = (*jsonEncDriverTypical)(nil)
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/mammoth-test.go.tmpl b/vendor/github.com/hashicorp/go-msgpack/v2/codec/mammoth-test.go.tmpl
new file mode 100644
index 00000000000..c598cc73a5e
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/mammoth-test.go.tmpl
@@ -0,0 +1,154 @@
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+// Code generated from mammoth-test.go.tmpl - DO NOT EDIT.
+
+package codec
+
+import "testing"
+import "fmt"
+import "reflect"
+
+// TestMammoth has all the different paths optimized in fast-path
+// It has all the primitives, slices and maps.
+//
+// For each of those types, it has a pointer and a non-pointer field.
+
+func init() { _ = fmt.Printf } // so we can include fmt as needed
+
+type TestMammoth struct {
+
+{{range .Values }}{{if .Primitive }}{{/*
+*/}}{{ .MethodNamePfx "F" true }} {{ .Primitive }}
+{{ .MethodNamePfx "Fptr" true }} *{{ .Primitive }}
+{{end}}{{end}}
+
+{{range .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/*
+*/}}{{ .MethodNamePfx "F" false }} []{{ .Elem }}
+{{ .MethodNamePfx "Fptr" false }} *[]{{ .Elem }}
+{{end}}{{end}}{{end}}
+
+{{range .Values }}{{if not .Primitive }}{{if .MapKey }}{{/*
+*/}}{{ .MethodNamePfx "F" false }} map[{{ .MapKey }}]{{ .Elem }}
+{{ .MethodNamePfx "Fptr" false }} *map[{{ .MapKey }}]{{ .Elem }}
+{{end}}{{end}}{{end}}
+
+}
+
+{{range .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/*
+*/}} type {{ .MethodNamePfx "typMbs" false }} []{{ .Elem }}
+func (_ {{ .MethodNamePfx "typMbs" false }}) MapBySlice() { }
+{{end}}{{end}}{{end}}
+
+{{range .Values }}{{if not .Primitive }}{{if .MapKey }}{{/*
+*/}} type {{ .MethodNamePfx "typMap" false }} map[{{ .MapKey }}]{{ .Elem }}
+{{end}}{{end}}{{end}}
+
+func doTestMammothSlices(t *testing.T, h Handle) {
+{{range $i, $e := .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/*
+*/}}
+ var v{{$i}}va [8]{{ .Elem }}
+ for _, v := range [][]{{ .Elem }}{ nil, {}, { {{ nonzerocmd .Elem }}, {{ zerocmd .Elem }}, {{ zerocmd .Elem }}, {{ nonzerocmd .Elem }} } } { {{/*
+ // fmt.Printf(">>>> running mammoth slice v{{$i}}: %v\n", v)
+ // - encode value to some []byte
+ // - decode into a length-wise-equal []byte
+ // - check if equal to initial slice
+ // - encode ptr to the value
+ // - check if encode bytes are same
+ // - decode into ptrs to: nil, then 1-elem slice, equal-length, then large len slice
+ // - decode into non-addressable slice of equal length, then larger len
+ // - for each decode, compare elem-by-elem to the original slice
+ // -
+ // - rinse and repeat for a MapBySlice version
+ // -
+ */}}
+ var v{{$i}}v1, v{{$i}}v2 []{{ .Elem }}
+ v{{$i}}v1 = v
+ bs{{$i}} := testMarshalErr(v{{$i}}v1, h, t, "enc-slice-v{{$i}}")
+ if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make([]{{ .Elem }}, len(v)) }
+ testUnmarshalErr(v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}")
+ testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}")
+ if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make([]{{ .Elem }}, len(v)) }
+ testUnmarshalErr(reflect.ValueOf(v{{$i}}v2), bs{{$i}}, h, t, "dec-slice-v{{$i}}-noaddr") // non-addressable value
+ testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-noaddr")
+ // ...
+ bs{{$i}} = testMarshalErr(&v{{$i}}v1, h, t, "enc-slice-v{{$i}}-p")
+ v{{$i}}v2 = nil
+ testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p")
+ testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p")
+ v{{$i}}va = [8]{{ .Elem }}{} // clear the array
+ v{{$i}}v2 = v{{$i}}va[:1:1]
+ testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-1")
+ testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p-1")
+ v{{$i}}va = [8]{{ .Elem }}{} // clear the array
+ v{{$i}}v2 = v{{$i}}va[:len(v{{$i}}v1):len(v{{$i}}v1)]
+ testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-len")
+ testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p-len")
+ v{{$i}}va = [8]{{ .Elem }}{} // clear the array
+ v{{$i}}v2 = v{{$i}}va[:]
+ testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-cap")
+ testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p-cap")
+ if len(v{{$i}}v1) > 1 {
+ v{{$i}}va = [8]{{ .Elem }}{} // clear the array
+ testUnmarshalErr((&v{{$i}}va)[:len(v{{$i}}v1)], bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-len-noaddr")
+ testDeepEqualErr(v{{$i}}v1, v{{$i}}va[:len(v{{$i}}v1)], t, "equal-slice-v{{$i}}-p-len-noaddr")
+ v{{$i}}va = [8]{{ .Elem }}{} // clear the array
+ testUnmarshalErr((&v{{$i}}va)[:], bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-cap-noaddr")
+ testDeepEqualErr(v{{$i}}v1, v{{$i}}va[:len(v{{$i}}v1)], t, "equal-slice-v{{$i}}-p-cap-noaddr")
+ }
+ // ...
+ var v{{$i}}v3, v{{$i}}v4 {{ .MethodNamePfx "typMbs" false }}
+ v{{$i}}v2 = nil
+ if v != nil { v{{$i}}v2 = make([]{{ .Elem }}, len(v)) }
+ v{{$i}}v3 = {{ .MethodNamePfx "typMbs" false }}(v{{$i}}v1)
+ v{{$i}}v4 = {{ .MethodNamePfx "typMbs" false }}(v{{$i}}v2)
+ bs{{$i}} = testMarshalErr(v{{$i}}v3, h, t, "enc-slice-v{{$i}}-custom")
+ testUnmarshalErr(v{{$i}}v4, bs{{$i}}, h, t, "dec-slice-v{{$i}}-custom")
+ testDeepEqualErr(v{{$i}}v3, v{{$i}}v4, t, "equal-slice-v{{$i}}-custom")
+ bs{{$i}} = testMarshalErr(&v{{$i}}v3, h, t, "enc-slice-v{{$i}}-custom-p")
+ v{{$i}}v2 = nil
+ v{{$i}}v4 = {{ .MethodNamePfx "typMbs" false }}(v{{$i}}v2)
+ testUnmarshalErr(&v{{$i}}v4, bs{{$i}}, h, t, "dec-slice-v{{$i}}-custom-p")
+ testDeepEqualErr(v{{$i}}v3, v{{$i}}v4, t, "equal-slice-v{{$i}}-custom-p")
+ }
+{{end}}{{end}}{{end}}
+}
+
+func doTestMammothMaps(t *testing.T, h Handle) {
+{{range $i, $e := .Values }}{{if not .Primitive }}{{if .MapKey }}{{/*
+*/}}
+ for _, v := range []map[{{ .MapKey }}]{{ .Elem }}{ nil, {}, { {{ nonzerocmd .MapKey }}:{{ zerocmd .Elem }} {{if ne "bool" .MapKey}}, {{ nonzerocmd .MapKey }}:{{ nonzerocmd .Elem }} {{end}} } } {
+ // fmt.Printf(">>>> running mammoth map v{{$i}}: %v\n", v)
+ var v{{$i}}v1, v{{$i}}v2 map[{{ .MapKey }}]{{ .Elem }}
+ v{{$i}}v1 = v
+ bs{{$i}} := testMarshalErr(v{{$i}}v1, h, t, "enc-map-v{{$i}}")
+ if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) } // reset map
+ testUnmarshalErr(v{{$i}}v2, bs{{$i}}, h, t, "dec-map-v{{$i}}")
+ testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}")
+ if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) } // reset map
+ testUnmarshalErr(reflect.ValueOf(v{{$i}}v2), bs{{$i}}, h, t, "dec-map-v{{$i}}-noaddr") // decode into non-addressable map value
+ testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}-noaddr")
+ if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) } // reset map
+ testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-map-v{{$i}}-p-len")
+ testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}-p-len")
+ bs{{$i}} = testMarshalErr(&v{{$i}}v1, h, t, "enc-map-v{{$i}}-p")
+ v{{$i}}v2 = nil
+ testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-map-v{{$i}}-p-nil")
+ testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}-p-nil")
+ // ...
+ if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) } // reset map
+ var v{{$i}}v3, v{{$i}}v4 {{ .MethodNamePfx "typMap" false }}
+ v{{$i}}v3 = {{ .MethodNamePfx "typMap" false }}(v{{$i}}v1)
+ v{{$i}}v4 = {{ .MethodNamePfx "typMap" false }}(v{{$i}}v2)
+ bs{{$i}} = testMarshalErr(v{{$i}}v3, h, t, "enc-map-v{{$i}}-custom")
+ testUnmarshalErr(v{{$i}}v4, bs{{$i}}, h, t, "dec-map-v{{$i}}-p-len")
+ testDeepEqualErr(v{{$i}}v3, v{{$i}}v4, t, "equal-map-v{{$i}}-p-len")
+ }
+{{end}}{{end}}{{end}}
+
+}
+
+func doTestMammothMapsAndSlices(t *testing.T, h Handle) {
+ doTestMammothSlices(t, h)
+ doTestMammothMaps(t, h)
+}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/mammoth2-test.go.tmpl b/vendor/github.com/hashicorp/go-msgpack/v2/codec/mammoth2-test.go.tmpl
new file mode 100644
index 00000000000..3b546f3e40b
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/mammoth2-test.go.tmpl
@@ -0,0 +1,92 @@
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+// Code generated from mammoth2-test.go.tmpl - DO NOT EDIT.
+
+package codec
+
+// Increase codecoverage by covering all the codecgen paths, in fast-path and gen-helper.go....
+//
+// Add:
+// - test file for creating a mammoth generated file as _mammoth_generated.go
+// - generate a second mammoth files in a different file: mammoth2_generated_test.go
+// - mammoth-test.go.tmpl will do this
+// - run codecgen on it, into mammoth2_codecgen_generated_test.go (no build tags)
+// - as part of TestMammoth, run it also
+// - this will cover all the codecgen, gen-helper, etc in one full run
+// - check in mammoth* files into github also
+// - then
+//
+// Now, add some types:
+// - some that implement BinaryMarshal, TextMarshal, JSONMarshal, and one that implements none of it
+// - create a wrapper type that includes TestMammoth2, with it in slices, and maps, and the custom types
+// - this wrapper object is what we work encode/decode (so that the codecgen methods are called)
+
+
+// import "encoding/binary"
+import "fmt"
+
+type TestMammoth2 struct {
+
+{{range .Values }}{{if .Primitive }}{{/*
+*/}}{{ .MethodNamePfx "F" true }} {{ .Primitive }}
+{{ .MethodNamePfx "Fptr" true }} *{{ .Primitive }}
+{{end}}{{end}}
+
+{{range .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/*
+*/}}{{ .MethodNamePfx "F" false }} []{{ .Elem }}
+{{ .MethodNamePfx "Fptr" false }} *[]{{ .Elem }}
+{{end}}{{end}}{{end}}
+
+{{range .Values }}{{if not .Primitive }}{{if .MapKey }}{{/*
+*/}}{{ .MethodNamePfx "F" false }} map[{{ .MapKey }}]{{ .Elem }}
+{{ .MethodNamePfx "Fptr" false }} *map[{{ .MapKey }}]{{ .Elem }}
+{{end}}{{end}}{{end}}
+
+}
+
+// -----------
+
+type testMammoth2Binary uint64
+func (x testMammoth2Binary) MarshalBinary() (data []byte, err error) {
+data = make([]byte, 8)
+bigen.PutUint64(data, uint64(x))
+return
+}
+func (x *testMammoth2Binary) UnmarshalBinary(data []byte) (err error) {
+*x = testMammoth2Binary(bigen.Uint64(data))
+return
+}
+
+type testMammoth2Text uint64
+func (x testMammoth2Text) MarshalText() (data []byte, err error) {
+data = []byte(fmt.Sprintf("%b", uint64(x)))
+return
+}
+func (x *testMammoth2Text) UnmarshalText(data []byte) (err error) {
+_, err = fmt.Sscanf(string(data), "%b", (*uint64)(x))
+return
+}
+
+type testMammoth2Json uint64
+func (x testMammoth2Json) MarshalJSON() (data []byte, err error) {
+data = []byte(fmt.Sprintf("%v", uint64(x)))
+return
+}
+func (x *testMammoth2Json) UnmarshalJSON(data []byte) (err error) {
+_, err = fmt.Sscanf(string(data), "%v", (*uint64)(x))
+return
+}
+
+type testMammoth2Basic [4]uint64
+
+type TestMammoth2Wrapper struct {
+ V TestMammoth2
+ T testMammoth2Text
+ B testMammoth2Binary
+ J testMammoth2Json
+ C testMammoth2Basic
+ M map[testMammoth2Basic]TestMammoth2
+ L []TestMammoth2
+ A [4]int64
+}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/msgpack.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/msgpack.go
new file mode 100644
index 00000000000..99c8a13fd85
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/msgpack.go
@@ -0,0 +1,1150 @@
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+/*
+MSGPACK
+
+Msgpack-c implementation powers the c, c++, python, ruby, etc libraries.
+We need to maintain compatibility with it and how it encodes integer values
+without caring about the type.
+
+For compatibility with behaviour of msgpack-c reference implementation:
+ - Go intX (>0) and uintX
+ IS ENCODED AS
+ msgpack +ve fixnum, unsigned
+ - Go intX (<0)
+ IS ENCODED AS
+ msgpack -ve fixnum, signed
+*/
+
+package codec
+
+import (
+ "fmt"
+ "io"
+ "math"
+ "net/rpc"
+ "reflect"
+ "time"
+)
+
+const (
+ mpPosFixNumMin byte = 0x00
+ mpPosFixNumMax byte = 0x7f
+ mpFixMapMin byte = 0x80
+ mpFixMapMax byte = 0x8f
+ mpFixArrayMin byte = 0x90
+ mpFixArrayMax byte = 0x9f
+ mpFixStrMin byte = 0xa0
+ mpFixStrMax byte = 0xbf
+ mpNil byte = 0xc0
+ _ byte = 0xc1
+ mpFalse byte = 0xc2
+ mpTrue byte = 0xc3
+ mpFloat byte = 0xca
+ mpDouble byte = 0xcb
+ mpUint8 byte = 0xcc
+ mpUint16 byte = 0xcd
+ mpUint32 byte = 0xce
+ mpUint64 byte = 0xcf
+ mpInt8 byte = 0xd0
+ mpInt16 byte = 0xd1
+ mpInt32 byte = 0xd2
+ mpInt64 byte = 0xd3
+
+ // extensions below
+ mpBin8 byte = 0xc4
+ mpBin16 byte = 0xc5
+ mpBin32 byte = 0xc6
+ mpExt8 byte = 0xc7
+ mpExt16 byte = 0xc8
+ mpExt32 byte = 0xc9
+ mpFixExt1 byte = 0xd4
+ mpFixExt2 byte = 0xd5
+ mpFixExt4 byte = 0xd6
+ mpFixExt8 byte = 0xd7
+ mpFixExt16 byte = 0xd8
+
+ mpStr8 byte = 0xd9 // new
+ mpStr16 byte = 0xda
+ mpStr32 byte = 0xdb
+
+ mpArray16 byte = 0xdc
+ mpArray32 byte = 0xdd
+
+ mpMap16 byte = 0xde
+ mpMap32 byte = 0xdf
+
+ mpNegFixNumMin byte = 0xe0
+ mpNegFixNumMax byte = 0xff
+)
+
+var mpTimeExtTag int8 = -1
+var mpTimeExtTagU = uint8(mpTimeExtTag)
+
+// var mpdesc = map[byte]string{
+// mpPosFixNumMin: "PosFixNumMin",
+// mpPosFixNumMax: "PosFixNumMax",
+// mpFixMapMin: "FixMapMin",
+// mpFixMapMax: "FixMapMax",
+// mpFixArrayMin: "FixArrayMin",
+// mpFixArrayMax: "FixArrayMax",
+// mpFixStrMin: "FixStrMin",
+// mpFixStrMax: "FixStrMax",
+// mpNil: "Nil",
+// mpFalse: "False",
+// mpTrue: "True",
+// mpFloat: "Float",
+// mpDouble: "Double",
+// mpUint8: "Uint8",
+// mpUint16: "Uint16",
+// mpUint32: "Uint32",
+// mpUint64: "Uint64",
+// mpInt8: "Int8",
+// mpInt16: "Int16",
+// mpInt32: "Int32",
+// mpInt64: "Int64",
+// mpBin8: "Bin8",
+// mpBin16: "Bin16",
+// mpBin32: "Bin32",
+// mpExt8: "Ext8",
+// mpExt16: "Ext16",
+// mpExt32: "Ext32",
+// mpFixExt1: "FixExt1",
+// mpFixExt2: "FixExt2",
+// mpFixExt4: "FixExt4",
+// mpFixExt8: "FixExt8",
+// mpFixExt16: "FixExt16",
+// mpStr8: "Str8",
+// mpStr16: "Str16",
+// mpStr32: "Str32",
+// mpArray16: "Array16",
+// mpArray32: "Array32",
+// mpMap16: "Map16",
+// mpMap32: "Map32",
+// mpNegFixNumMin: "NegFixNumMin",
+// mpNegFixNumMax: "NegFixNumMax",
+// }
+
+func mpdesc(bd byte) string {
+ switch bd {
+ case mpNil:
+ return "nil"
+ case mpFalse:
+ return "false"
+ case mpTrue:
+ return "true"
+ case mpFloat, mpDouble:
+ return "float"
+ case mpUint8, mpUint16, mpUint32, mpUint64:
+ return "uint"
+ case mpInt8, mpInt16, mpInt32, mpInt64:
+ return "int"
+ default:
+ switch {
+ case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax:
+ return "int"
+ case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax:
+ return "int"
+ case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax:
+ return "string|bytes"
+ case bd == mpBin8, bd == mpBin16, bd == mpBin32:
+ return "bytes"
+ case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax:
+ return "array"
+ case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax:
+ return "map"
+ case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32:
+ return "ext"
+ default:
+ return "unknown"
+ }
+ }
+}
+
+// MsgpackSpecRpcMultiArgs is a special type which signifies to the MsgpackSpecRpcCodec
+// that the backend RPC service takes multiple arguments, which have been arranged
+// in sequence in the slice.
+//
+// The Codec then passes it AS-IS to the rpc service (without wrapping it in an
+// array of 1 element).
+type MsgpackSpecRpcMultiArgs []interface{}
+
+// A MsgpackContainer type specifies the different types of msgpackContainers.
+type msgpackContainerType struct {
+ fixCutoff uint8
+ bFixMin, b8, b16, b32 byte
+ // hasFixMin, has8, has8Always bool
+}
+
+var (
+ msgpackContainerRawLegacy = msgpackContainerType{
+ 32, mpFixStrMin, 0, mpStr16, mpStr32,
+ }
+ msgpackContainerStr = msgpackContainerType{
+ 32, mpFixStrMin, mpStr8, mpStr16, mpStr32, // true, true, false,
+ }
+ msgpackContainerBin = msgpackContainerType{
+ 0, 0, mpBin8, mpBin16, mpBin32, // false, true, true,
+ }
+ msgpackContainerList = msgpackContainerType{
+ 16, mpFixArrayMin, 0, mpArray16, mpArray32, // true, false, false,
+ }
+ msgpackContainerMap = msgpackContainerType{
+ 16, mpFixMapMin, 0, mpMap16, mpMap32, // true, false, false,
+ }
+)
+
+//---------------------------------------------
+
+type msgpackEncDriver struct {
+ noBuiltInTypes
+ encDriverNoopContainerWriter
+ // encNoSeparator
+ e *Encoder
+ w *encWriterSwitch
+ h *MsgpackHandle
+ x [8]byte
+ // _ [3]uint64 // padding
+}
+
+func (e *msgpackEncDriver) EncodeNil() {
+ e.w.writen1(mpNil)
+}
+
+func (e *msgpackEncDriver) EncodeInt(i int64) {
+ if e.h.PositiveIntUnsigned && i >= 0 {
+ e.EncodeUint(uint64(i))
+ } else if i > math.MaxInt8 {
+ if i <= math.MaxInt16 {
+ e.w.writen1(mpInt16)
+ bigenHelper{e.x[:2], e.w}.writeUint16(uint16(i))
+ } else if i <= math.MaxInt32 {
+ e.w.writen1(mpInt32)
+ bigenHelper{e.x[:4], e.w}.writeUint32(uint32(i))
+ } else {
+ e.w.writen1(mpInt64)
+ bigenHelper{e.x[:8], e.w}.writeUint64(uint64(i))
+ }
+ } else if i >= -32 {
+ if e.h.NoFixedNum {
+ e.w.writen2(mpInt8, byte(i))
+ } else {
+ e.w.writen1(byte(i))
+ }
+ } else if i >= math.MinInt8 {
+ e.w.writen2(mpInt8, byte(i))
+ } else if i >= math.MinInt16 {
+ e.w.writen1(mpInt16)
+ bigenHelper{e.x[:2], e.w}.writeUint16(uint16(i))
+ } else if i >= math.MinInt32 {
+ e.w.writen1(mpInt32)
+ bigenHelper{e.x[:4], e.w}.writeUint32(uint32(i))
+ } else {
+ e.w.writen1(mpInt64)
+ bigenHelper{e.x[:8], e.w}.writeUint64(uint64(i))
+ }
+}
+
+func (e *msgpackEncDriver) EncodeUint(i uint64) {
+ if i <= math.MaxInt8 {
+ if e.h.NoFixedNum {
+ e.w.writen2(mpUint8, byte(i))
+ } else {
+ e.w.writen1(byte(i))
+ }
+ } else if i <= math.MaxUint8 {
+ e.w.writen2(mpUint8, byte(i))
+ } else if i <= math.MaxUint16 {
+ e.w.writen1(mpUint16)
+ bigenHelper{e.x[:2], e.w}.writeUint16(uint16(i))
+ } else if i <= math.MaxUint32 {
+ e.w.writen1(mpUint32)
+ bigenHelper{e.x[:4], e.w}.writeUint32(uint32(i))
+ } else {
+ e.w.writen1(mpUint64)
+ bigenHelper{e.x[:8], e.w}.writeUint64(uint64(i))
+ }
+}
+
+func (e *msgpackEncDriver) EncodeBool(b bool) {
+ if b {
+ e.w.writen1(mpTrue)
+ } else {
+ e.w.writen1(mpFalse)
+ }
+}
+
+func (e *msgpackEncDriver) EncodeFloat32(f float32) {
+ e.w.writen1(mpFloat)
+ bigenHelper{e.x[:4], e.w}.writeUint32(math.Float32bits(f))
+}
+
+func (e *msgpackEncDriver) EncodeFloat64(f float64) {
+ e.w.writen1(mpDouble)
+ bigenHelper{e.x[:8], e.w}.writeUint64(math.Float64bits(f))
+}
+
+func (e *msgpackEncDriver) EncodeTime(t time.Time) {
+ // use the MarshalBinary format if requested
+ if e.h.TimeNotBuiltin {
+ bin, err := t.MarshalBinary()
+ if err != nil {
+ return
+ }
+ e.EncodeStringBytesRaw(bin)
+ return
+ }
+ if t.IsZero() {
+ e.EncodeNil()
+ return
+ }
+ t = t.UTC()
+ sec, nsec := t.Unix(), uint64(t.Nanosecond())
+ var data64 uint64
+ var l = 4
+ if sec >= 0 && sec>>34 == 0 {
+ data64 = (nsec << 34) | uint64(sec)
+ if data64&0xffffffff00000000 != 0 {
+ l = 8
+ }
+ } else {
+ l = 12
+ }
+ if e.h.WriteExt {
+ e.encodeExtPreamble(mpTimeExtTagU, l)
+ } else {
+ e.writeContainerLen(msgpackContainerRawLegacy, l)
+ }
+ switch l {
+ case 4:
+ bigenHelper{e.x[:4], e.w}.writeUint32(uint32(data64))
+ case 8:
+ bigenHelper{e.x[:8], e.w}.writeUint64(data64)
+ case 12:
+ bigenHelper{e.x[:4], e.w}.writeUint32(uint32(nsec))
+ bigenHelper{e.x[:8], e.w}.writeUint64(uint64(sec))
+ }
+}
+
+func (e *msgpackEncDriver) EncodeExt(v interface{}, xtag uint64, ext Ext, _ *Encoder) {
+ bs := ext.WriteExt(v)
+ if bs == nil {
+ e.EncodeNil()
+ return
+ }
+ if e.h.WriteExt {
+ e.encodeExtPreamble(uint8(xtag), len(bs))
+ e.w.writeb(bs)
+ } else {
+ e.EncodeStringBytesRaw(bs)
+ }
+}
+
+func (e *msgpackEncDriver) EncodeRawExt(re *RawExt, _ *Encoder) {
+ e.encodeExtPreamble(uint8(re.Tag), len(re.Data))
+ e.w.writeb(re.Data)
+}
+
+func (e *msgpackEncDriver) encodeExtPreamble(xtag byte, l int) {
+ if l == 1 {
+ e.w.writen2(mpFixExt1, xtag)
+ } else if l == 2 {
+ e.w.writen2(mpFixExt2, xtag)
+ } else if l == 4 {
+ e.w.writen2(mpFixExt4, xtag)
+ } else if l == 8 {
+ e.w.writen2(mpFixExt8, xtag)
+ } else if l == 16 {
+ e.w.writen2(mpFixExt16, xtag)
+ } else if l < 256 {
+ e.w.writen2(mpExt8, byte(l))
+ e.w.writen1(xtag)
+ } else if l < 65536 {
+ e.w.writen1(mpExt16)
+ bigenHelper{e.x[:2], e.w}.writeUint16(uint16(l))
+ e.w.writen1(xtag)
+ } else {
+ e.w.writen1(mpExt32)
+ bigenHelper{e.x[:4], e.w}.writeUint32(uint32(l))
+ e.w.writen1(xtag)
+ }
+}
+
+func (e *msgpackEncDriver) WriteArrayStart(length int) {
+ e.writeContainerLen(msgpackContainerList, length)
+}
+
+func (e *msgpackEncDriver) WriteMapStart(length int) {
+ e.writeContainerLen(msgpackContainerMap, length)
+}
+
+func (e *msgpackEncDriver) EncodeString(c charEncoding, s string) {
+ slen := len(s)
+ if c == cRAW && e.h.WriteExt {
+ e.writeContainerLen(msgpackContainerBin, slen)
+ } else {
+ e.writeContainerLen(msgpackContainerRawLegacy, slen)
+ }
+ if slen > 0 {
+ e.w.writestr(s)
+ }
+}
+
+func (e *msgpackEncDriver) EncodeStringEnc(c charEncoding, s string) {
+ slen := len(s)
+ if e.h.WriteExt {
+ e.writeContainerLen(msgpackContainerStr, slen)
+ } else {
+ e.writeContainerLen(msgpackContainerRawLegacy, slen)
+ }
+ if slen > 0 {
+ e.w.writestr(s)
+ }
+}
+
+func (e *msgpackEncDriver) EncodeStringBytes(c charEncoding, bs []byte) {
+ if bs == nil {
+ e.EncodeNil()
+ return
+ }
+ slen := len(bs)
+ if c == cRAW && e.h.WriteExt {
+ e.writeContainerLen(msgpackContainerBin, slen)
+ } else {
+ e.writeContainerLen(msgpackContainerRawLegacy, slen)
+ }
+ if slen > 0 {
+ e.w.writeb(bs)
+ }
+}
+
+func (e *msgpackEncDriver) EncodeStringBytesRaw(bs []byte) {
+ if bs == nil {
+ e.EncodeNil()
+ return
+ }
+ slen := len(bs)
+ if e.h.WriteExt {
+ e.writeContainerLen(msgpackContainerBin, slen)
+ } else {
+ e.writeContainerLen(msgpackContainerRawLegacy, slen)
+ }
+ if slen > 0 {
+ e.w.writeb(bs)
+ }
+}
+
+func (e *msgpackEncDriver) writeContainerLen(ct msgpackContainerType, l int) {
+ if ct.fixCutoff > 0 && l < int(ct.fixCutoff) {
+ e.w.writen1(ct.bFixMin | byte(l))
+ } else if ct.b8 > 0 && l < 256 {
+ e.w.writen2(ct.b8, uint8(l))
+ } else if l < 65536 {
+ e.w.writen1(ct.b16)
+ bigenHelper{e.x[:2], e.w}.writeUint16(uint16(l))
+ } else {
+ e.w.writen1(ct.b32)
+ bigenHelper{e.x[:4], e.w}.writeUint32(uint32(l))
+ }
+}
+
+//---------------------------------------------
+
+type msgpackDecDriver struct {
+ d *Decoder
+ r *decReaderSwitch
+ h *MsgpackHandle
+ // b [scratchByteArrayLen]byte
+ bd byte
+ bdRead bool
+ br bool // bytes reader
+ noBuiltInTypes
+ // noStreamingCodec
+ // decNoSeparator
+ decDriverNoopContainerReader
+ // _ [3]uint64 // padding
+}
+
+// Note: This returns either a primitive (int, bool, etc) for non-containers,
+// or a containerType, or a specific type denoting nil or extension.
+// It is called when a nil interface{} is passed, leaving it up to the DecDriver
+// to introspect the stream and decide how best to decode.
+// It deciphers the value by looking at the stream first.
+func (d *msgpackDecDriver) DecodeNaked() {
+ if !d.bdRead {
+ d.readNextBd()
+ }
+ bd := d.bd
+ n := d.d.naked()
+ var decodeFurther bool
+
+ switch bd {
+ case mpNil:
+ n.v = valueTypeNil
+ d.bdRead = false
+ case mpFalse:
+ n.v = valueTypeBool
+ n.b = false
+ case mpTrue:
+ n.v = valueTypeBool
+ n.b = true
+
+ case mpFloat:
+ n.v = valueTypeFloat
+ n.f = float64(math.Float32frombits(bigen.Uint32(d.r.readx(4))))
+ case mpDouble:
+ n.v = valueTypeFloat
+ n.f = math.Float64frombits(bigen.Uint64(d.r.readx(8)))
+
+ case mpUint8:
+ n.v = valueTypeUint
+ n.u = uint64(d.r.readn1())
+ case mpUint16:
+ n.v = valueTypeUint
+ n.u = uint64(bigen.Uint16(d.r.readx(2)))
+ case mpUint32:
+ n.v = valueTypeUint
+ n.u = uint64(bigen.Uint32(d.r.readx(4)))
+ case mpUint64:
+ n.v = valueTypeUint
+ n.u = uint64(bigen.Uint64(d.r.readx(8)))
+
+ case mpInt8:
+ n.v = valueTypeInt
+ n.i = int64(int8(d.r.readn1()))
+ case mpInt16:
+ n.v = valueTypeInt
+ n.i = int64(int16(bigen.Uint16(d.r.readx(2))))
+ case mpInt32:
+ n.v = valueTypeInt
+ n.i = int64(int32(bigen.Uint32(d.r.readx(4))))
+ case mpInt64:
+ n.v = valueTypeInt
+ n.i = int64(int64(bigen.Uint64(d.r.readx(8))))
+
+ default:
+ switch {
+ case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax:
+ // positive fixnum (always signed)
+ n.v = valueTypeInt
+ n.i = int64(int8(bd))
+ case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax:
+ // negative fixnum
+ n.v = valueTypeInt
+ n.i = int64(int8(bd))
+ case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax:
+ if d.h.WriteExt || d.h.RawToString {
+ n.v = valueTypeString
+ n.s = d.DecodeString()
+ } else {
+ n.v = valueTypeBytes
+ n.l = d.DecodeBytes(nil, false)
+ }
+ case bd == mpBin8, bd == mpBin16, bd == mpBin32:
+ decNakedReadRawBytes(d, d.d, n, d.h.RawToString)
+ case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax:
+ n.v = valueTypeArray
+ decodeFurther = true
+ case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax:
+ n.v = valueTypeMap
+ decodeFurther = true
+ case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32:
+ n.v = valueTypeExt
+ clen := d.readExtLen()
+ n.u = uint64(d.r.readn1())
+ if n.u == uint64(mpTimeExtTagU) {
+ n.v = valueTypeTime
+ n.t = d.decodeTime(clen)
+ } else if d.br {
+ n.l = d.r.readx(uint(clen))
+ } else {
+ n.l = decByteSlice(d.r, clen, d.d.h.MaxInitLen, d.d.b[:])
+ }
+ default:
+ d.d.errorf("cannot infer value: %s: Ox%x/%d/%s", msgBadDesc, bd, bd, mpdesc(bd))
+ }
+ }
+ if !decodeFurther {
+ d.bdRead = false
+ }
+ if n.v == valueTypeUint && d.h.SignedInteger {
+ n.v = valueTypeInt
+ n.i = int64(n.u)
+ }
+}
+
+// int can be decoded from msgpack type: intXXX or uintXXX
+func (d *msgpackDecDriver) DecodeInt64() (i int64) {
+ if !d.bdRead {
+ d.readNextBd()
+ }
+ switch d.bd {
+ case mpUint8:
+ i = int64(uint64(d.r.readn1()))
+ case mpUint16:
+ i = int64(uint64(bigen.Uint16(d.r.readx(2))))
+ case mpUint32:
+ i = int64(uint64(bigen.Uint32(d.r.readx(4))))
+ case mpUint64:
+ i = int64(bigen.Uint64(d.r.readx(8)))
+ case mpInt8:
+ i = int64(int8(d.r.readn1()))
+ case mpInt16:
+ i = int64(int16(bigen.Uint16(d.r.readx(2))))
+ case mpInt32:
+ i = int64(int32(bigen.Uint32(d.r.readx(4))))
+ case mpInt64:
+ i = int64(bigen.Uint64(d.r.readx(8)))
+ default:
+ switch {
+ case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax:
+ i = int64(int8(d.bd))
+ case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax:
+ i = int64(int8(d.bd))
+ default:
+ d.d.errorf("cannot decode signed integer: %s: %x/%s", msgBadDesc, d.bd, mpdesc(d.bd))
+ return
+ }
+ }
+ d.bdRead = false
+ return
+}
+
+// uint can be decoded from msgpack type: intXXX or uintXXX
+func (d *msgpackDecDriver) DecodeUint64() (ui uint64) {
+ if !d.bdRead {
+ d.readNextBd()
+ }
+ switch d.bd {
+ case mpUint8:
+ ui = uint64(d.r.readn1())
+ case mpUint16:
+ ui = uint64(bigen.Uint16(d.r.readx(2)))
+ case mpUint32:
+ ui = uint64(bigen.Uint32(d.r.readx(4)))
+ case mpUint64:
+ ui = bigen.Uint64(d.r.readx(8))
+ case mpInt8:
+ if i := int64(int8(d.r.readn1())); i >= 0 {
+ ui = uint64(i)
+ } else {
+ d.d.errorf("assigning negative signed value: %v, to unsigned type", i)
+ return
+ }
+ case mpInt16:
+ if i := int64(int16(bigen.Uint16(d.r.readx(2)))); i >= 0 {
+ ui = uint64(i)
+ } else {
+ d.d.errorf("assigning negative signed value: %v, to unsigned type", i)
+ return
+ }
+ case mpInt32:
+ if i := int64(int32(bigen.Uint32(d.r.readx(4)))); i >= 0 {
+ ui = uint64(i)
+ } else {
+ d.d.errorf("assigning negative signed value: %v, to unsigned type", i)
+ return
+ }
+ case mpInt64:
+ if i := int64(bigen.Uint64(d.r.readx(8))); i >= 0 {
+ ui = uint64(i)
+ } else {
+ d.d.errorf("assigning negative signed value: %v, to unsigned type", i)
+ return
+ }
+ default:
+ switch {
+ case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax:
+ ui = uint64(d.bd)
+ case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax:
+ d.d.errorf("assigning negative signed value: %v, to unsigned type", int(d.bd))
+ return
+ default:
+ d.d.errorf("cannot decode unsigned integer: %s: %x/%s", msgBadDesc, d.bd, mpdesc(d.bd))
+ return
+ }
+ }
+ d.bdRead = false
+ return
+}
+
+// float can either be decoded from msgpack type: float, double or intX
+func (d *msgpackDecDriver) DecodeFloat64() (f float64) {
+ if !d.bdRead {
+ d.readNextBd()
+ }
+ if d.bd == mpFloat {
+ f = float64(math.Float32frombits(bigen.Uint32(d.r.readx(4))))
+ } else if d.bd == mpDouble {
+ f = math.Float64frombits(bigen.Uint64(d.r.readx(8)))
+ } else {
+ f = float64(d.DecodeInt64())
+ }
+ d.bdRead = false
+ return
+}
+
+// bool can be decoded from bool, fixnum 0 or 1.
+func (d *msgpackDecDriver) DecodeBool() (b bool) {
+ if !d.bdRead {
+ d.readNextBd()
+ }
+ if d.bd == mpFalse || d.bd == 0 {
+ // b = false
+ } else if d.bd == mpTrue || d.bd == 1 {
+ b = true
+ } else {
+ d.d.errorf("cannot decode bool: %s: %x/%s", msgBadDesc, d.bd, mpdesc(d.bd))
+ return
+ }
+ d.bdRead = false
+ return
+}
+
+func (d *msgpackDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) {
+ if !d.bdRead {
+ d.readNextBd()
+ }
+
+ bd := d.bd
+ var clen int
+ if bd == mpNil {
+ d.bdRead = false
+ return
+ } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 {
+ clen = d.readContainerLen(msgpackContainerBin) // binary
+ } else if bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax) {
+ clen = d.readContainerLen(msgpackContainerStr) // string/raw
+ } else if bd == mpArray16 || bd == mpArray32 || (bd >= mpFixArrayMin && bd <= mpFixArrayMax) {
+ // check if an "array" of uint8's
+ if zerocopy && len(bs) == 0 {
+ bs = d.d.b[:]
+ }
+ bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d)
+ return
+ } else {
+ d.d.errorf("invalid byte descriptor for decoding bytes, got: 0x%x", d.bd)
+ return
+ }
+
+ d.bdRead = false
+ if zerocopy {
+ if d.br {
+ return d.r.readx(uint(clen))
+ } else if len(bs) == 0 {
+ bs = d.d.b[:]
+ }
+ }
+ return decByteSlice(d.r, clen, d.h.MaxInitLen, bs)
+}
+
+func (d *msgpackDecDriver) DecodeString() (s string) {
+ return string(d.DecodeBytes(d.d.b[:], true))
+}
+
+func (d *msgpackDecDriver) DecodeStringAsBytes() (s []byte) {
+ return d.DecodeBytes(d.d.b[:], true)
+}
+
+func (d *msgpackDecDriver) readNextBd() {
+ d.bd = d.r.readn1()
+ d.bdRead = true
+}
+
+func (d *msgpackDecDriver) uncacheRead() {
+ if d.bdRead {
+ d.r.unreadn1()
+ d.bdRead = false
+ }
+}
+
+func (d *msgpackDecDriver) ContainerType() (vt valueType) {
+ if !d.bdRead {
+ d.readNextBd()
+ }
+ bd := d.bd
+ // if bd == mpNil {
+ // // nil
+ // } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 {
+ // // binary
+ // } else if bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax) {
+ // // string/raw
+ // } else if bd == mpArray16 || bd == mpArray32 || (bd >= mpFixArrayMin && bd <= mpFixArrayMax) {
+ // // array
+ // } else if bd == mpMap16 || bd == mpMap32 || (bd >= mpFixMapMin && bd <= mpFixMapMax) {
+ // // map
+ // }
+ if bd == mpNil {
+ return valueTypeNil
+ } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 {
+ return valueTypeBytes
+ } else if bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax) {
+ if d.h.WriteExt || d.h.RawToString { // UTF-8 string (new spec)
+ return valueTypeString
+ }
+ return valueTypeBytes // raw (old spec)
+ } else if bd == mpArray16 || bd == mpArray32 || (bd >= mpFixArrayMin && bd <= mpFixArrayMax) {
+ return valueTypeArray
+ } else if bd == mpMap16 || bd == mpMap32 || (bd >= mpFixMapMin && bd <= mpFixMapMax) {
+ return valueTypeMap
+ }
+ // else {
+ // d.d.errorf("isContainerType: unsupported parameter: %v", vt)
+ // }
+ return valueTypeUnset
+}
+
+func (d *msgpackDecDriver) TryDecodeAsNil() (v bool) {
+ if !d.bdRead {
+ d.readNextBd()
+ }
+ if d.bd == mpNil {
+ d.bdRead = false
+ return true
+ }
+ return
+}
+
+func (d *msgpackDecDriver) readContainerLen(ct msgpackContainerType) (clen int) {
+ bd := d.bd
+ if bd == mpNil {
+ clen = -1 // to represent nil
+ } else if bd == ct.b8 {
+ clen = int(d.r.readn1())
+ } else if bd == ct.b16 {
+ clen = int(bigen.Uint16(d.r.readx(2)))
+ } else if bd == ct.b32 {
+ clen = int(bigen.Uint32(d.r.readx(4)))
+ } else if (ct.bFixMin & bd) == ct.bFixMin {
+ clen = int(ct.bFixMin ^ bd)
+ } else {
+ d.d.errorf("cannot read container length: %s: hex: %x, decimal: %d", msgBadDesc, bd, bd)
+ return
+ }
+ d.bdRead = false
+ return
+}
+
+func (d *msgpackDecDriver) ReadMapStart() int {
+ if !d.bdRead {
+ d.readNextBd()
+ }
+ return d.readContainerLen(msgpackContainerMap)
+}
+
+func (d *msgpackDecDriver) ReadArrayStart() int {
+ if !d.bdRead {
+ d.readNextBd()
+ }
+ return d.readContainerLen(msgpackContainerList)
+}
+
+func (d *msgpackDecDriver) readExtLen() (clen int) {
+ switch d.bd {
+ case mpNil:
+ clen = -1 // to represent nil
+ case mpFixExt1:
+ clen = 1
+ case mpFixExt2:
+ clen = 2
+ case mpFixExt4:
+ clen = 4
+ case mpFixExt8:
+ clen = 8
+ case mpFixExt16:
+ clen = 16
+ case mpExt8:
+ clen = int(d.r.readn1())
+ case mpExt16:
+ clen = int(bigen.Uint16(d.r.readx(2)))
+ case mpExt32:
+ clen = int(bigen.Uint32(d.r.readx(4)))
+ default:
+ d.d.errorf("decoding ext bytes: found unexpected byte: %x", d.bd)
+ return
+ }
+ return
+}
+
+func (d *msgpackDecDriver) DecodeTime() (t time.Time) {
+ // decode time from string bytes or ext
+ if !d.bdRead {
+ d.readNextBd()
+ }
+ bd := d.bd
+ var clen int
+ if bd == mpNil {
+ d.bdRead = false
+ return
+ } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 {
+ clen = d.readContainerLen(msgpackContainerBin) // binary
+ } else if bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax) {
+ clen = d.readContainerLen(msgpackContainerStr) // string/raw
+ } else {
+ // expect to see mpFixExt4,-1 OR mpFixExt8,-1 OR mpExt8,12,-1
+ d.bdRead = false
+ b2 := d.r.readn1()
+ if d.bd == mpFixExt4 && b2 == mpTimeExtTagU {
+ clen = 4
+ } else if d.bd == mpFixExt8 && b2 == mpTimeExtTagU {
+ clen = 8
+ } else if d.bd == mpExt8 && b2 == 12 && d.r.readn1() == mpTimeExtTagU {
+ clen = 12
+ } else {
+ d.d.errorf("invalid stream for decoding time as extension: got 0x%x, 0x%x", d.bd, b2)
+ return
+ }
+ }
+ return d.decodeTime(clen)
+}
+
+func (d *msgpackDecDriver) decodeTime(clen int) (t time.Time) {
+ bs := d.r.readx(uint(clen))
+
+ // Decode as a binary marshalled string for compatibility with other versions of go-msgpack.
+ // time.Time should always be encoded as 16 bytes or fewer in the binary marshalling format,
+ // so will always fit within the 32 byte max for fixed strings
+ if d.bd >= mpFixStrMin && d.bd <= mpFixStrMax {
+ err := t.UnmarshalBinary(bs)
+ if err == nil {
+ return
+ }
+ // fallthrough on failure
+ }
+
+ d.bdRead = false
+ switch clen {
+ case 4:
+ t = time.Unix(int64(bigen.Uint32(bs)), 0).UTC()
+ case 8:
+ tv := bigen.Uint64(bs)
+ t = time.Unix(int64(tv&0x00000003ffffffff), int64(tv>>34)).UTC()
+ case 12:
+ nsec := bigen.Uint32(bs[:4])
+ sec := bigen.Uint64(bs[4:])
+ t = time.Unix(int64(sec), int64(nsec)).UTC()
+ default:
+ d.d.errorf("invalid bytes for decoding time - expecting string or 4, 8, or 12 bytes, got %d", clen)
+ }
+ return
+}
+
+func (d *msgpackDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
+ if xtag > 0xff {
+ d.d.errorf("ext: tag must be <= 0xff; got: %v", xtag)
+ return
+ }
+ realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag))
+ realxtag = uint64(realxtag1)
+ if ext == nil {
+ re := rv.(*RawExt)
+ re.Tag = realxtag
+ re.Data = detachZeroCopyBytes(d.br, re.Data, xbs)
+ } else {
+ ext.ReadExt(rv, xbs)
+ }
+ return
+}
+
+func (d *msgpackDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs []byte) {
+ if !d.bdRead {
+ d.readNextBd()
+ }
+ xbd := d.bd
+ if xbd == mpBin8 || xbd == mpBin16 || xbd == mpBin32 {
+ xbs = d.DecodeBytes(nil, true)
+ } else if xbd == mpStr8 || xbd == mpStr16 || xbd == mpStr32 ||
+ (xbd >= mpFixStrMin && xbd <= mpFixStrMax) {
+ xbs = d.DecodeStringAsBytes()
+ } else {
+ clen := d.readExtLen()
+ xtag = d.r.readn1()
+ if verifyTag && xtag != tag {
+ d.d.errorf("wrong extension tag - got %b, expecting %v", xtag, tag)
+ return
+ }
+ if d.br {
+ xbs = d.r.readx(uint(clen))
+ } else {
+ xbs = decByteSlice(d.r, clen, d.d.h.MaxInitLen, d.d.b[:])
+ }
+ }
+ d.bdRead = false
+ return
+}
+
+//--------------------------------------------------
+
+// MsgpackHandle is a Handle for the Msgpack Schema-Free Encoding Format.
+type MsgpackHandle struct {
+ BasicHandle
+
+ // NoFixedNum says to output all signed integers as 2-bytes, never as 1-byte fixednum.
+ NoFixedNum bool
+
+ // WriteExt controls whether the new spec is honored.
+ //
+ // With WriteExt=true, we can encode configured extensions with extension tags
+ // and encode string/[]byte/extensions in a way compatible with the new spec
+ // but incompatible with the old spec.
+ //
+ // For compatibility with the old spec, set WriteExt=false.
+ //
+ // With WriteExt=false:
+ // configured extensions are serialized as raw bytes (not msgpack extensions).
+ // reserved byte descriptors like Str8 and those enabling the new msgpack Binary type
+ // are not encoded.
+ WriteExt bool
+
+ // PositiveIntUnsigned says to encode positive integers as unsigned.
+ PositiveIntUnsigned bool
+
+ binaryEncodingType
+ noElemSeparators
+
+ // _ [1]uint64 // padding
+}
+
+// Name returns the name of the handle: msgpack
+func (h *MsgpackHandle) Name() string { return "msgpack" }
+
+// SetBytesExt sets an extension
+func (h *MsgpackHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
+ return h.SetExt(rt, tag, &extWrapper{ext, interfaceExtFailer{}})
+}
+
+func (h *MsgpackHandle) newEncDriver(e *Encoder) encDriver {
+ return &msgpackEncDriver{e: e, w: e.w, h: h}
+}
+
+func (h *MsgpackHandle) newDecDriver(d *Decoder) decDriver {
+ return &msgpackDecDriver{d: d, h: h, r: d.r, br: d.bytes}
+}
+
+func (e *msgpackEncDriver) reset() {
+ e.w = e.e.w
+}
+
+func (d *msgpackDecDriver) reset() {
+ d.r, d.br = d.d.r, d.d.bytes
+ d.bd, d.bdRead = 0, false
+}
+
+//--------------------------------------------------
+
+type msgpackSpecRpcCodec struct {
+ rpcCodec
+}
+
+// /////////////// Spec RPC Codec ///////////////////
+func (c *msgpackSpecRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error {
+ // WriteRequest can write to both a Go service, and other services that do
+ // not abide by the 1 argument rule of a Go service.
+ // We discriminate based on if the body is a MsgpackSpecRpcMultiArgs
+ var bodyArr []interface{}
+ if m, ok := body.(MsgpackSpecRpcMultiArgs); ok {
+ bodyArr = ([]interface{})(m)
+ } else {
+ bodyArr = []interface{}{body}
+ }
+ r2 := []interface{}{0, uint32(r.Seq), r.ServiceMethod, bodyArr}
+ return c.write(r2, nil, false)
+}
+
+func (c *msgpackSpecRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error {
+ var moe interface{}
+ if r.Error != "" {
+ moe = r.Error
+ }
+ if moe != nil && body != nil {
+ body = nil
+ }
+ r2 := []interface{}{1, uint32(r.Seq), moe, body}
+ return c.write(r2, nil, false)
+}
+
+func (c *msgpackSpecRpcCodec) ReadResponseHeader(r *rpc.Response) error {
+ return c.parseCustomHeader(1, &r.Seq, &r.Error)
+}
+
+func (c *msgpackSpecRpcCodec) ReadRequestHeader(r *rpc.Request) error {
+ return c.parseCustomHeader(0, &r.Seq, &r.ServiceMethod)
+}
+
+func (c *msgpackSpecRpcCodec) ReadRequestBody(body interface{}) error {
+ if body == nil { // read and discard
+ return c.read(nil)
+ }
+ bodyArr := []interface{}{body}
+ return c.read(&bodyArr)
+}
+
+func (c *msgpackSpecRpcCodec) parseCustomHeader(expectTypeByte byte, msgid *uint64, methodOrError *string) (err error) {
+ if cls := c.cls.load(); cls.closed {
+ return io.EOF
+ }
+
+ // We read the response header by hand
+ // so that the body can be decoded on its own from the stream at a later time.
+
+ const fia byte = 0x94 //four item array descriptor value
+ // Not sure why the panic of EOF is swallowed above.
+ // if bs1 := c.dec.r.readn1(); bs1 != fia {
+ // err = fmt.Errorf("Unexpected value for array descriptor: Expecting %v. Received %v", fia, bs1)
+ // return
+ // }
+ var ba [1]byte
+ var n int
+ for {
+ n, err = c.r.Read(ba[:])
+ if err != nil {
+ return
+ }
+ if n == 1 {
+ break
+ }
+ }
+
+ var b = ba[0]
+ if b != fia {
+ err = fmt.Errorf("not array - %s %x/%s", msgBadDesc, b, mpdesc(b))
+ } else {
+ err = c.read(&b)
+ if err == nil {
+ if b != expectTypeByte {
+ err = fmt.Errorf("%s - expecting %v but got %x/%s",
+ msgBadDesc, expectTypeByte, b, mpdesc(b))
+ } else {
+ err = c.read(msgid)
+ if err == nil {
+ err = c.read(methodOrError)
+ }
+ }
+ }
+ }
+ return
+}
+
+//--------------------------------------------------
+
+// msgpackSpecRpc is the implementation of Rpc that uses custom communication protocol
+// as defined in the msgpack spec at https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md
+type msgpackSpecRpc struct{}
+
+// MsgpackSpecRpc implements Rpc using the communication protocol defined in
+// the msgpack spec at https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md .
+//
+// See GoRpc documentation, for information on buffering for better performance.
+var MsgpackSpecRpc msgpackSpecRpc
+
+func (x msgpackSpecRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec {
+ return &msgpackSpecRpcCodec{newRPCCodec(conn, h)}
+}
+
+func (x msgpackSpecRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec {
+ return &msgpackSpecRpcCodec{newRPCCodec(conn, h)}
+}
+
+var _ decDriver = (*msgpackDecDriver)(nil)
+var _ encDriver = (*msgpackEncDriver)(nil)
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/rpc.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/rpc.go
new file mode 100644
index 00000000000..c64d6dca72d
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/rpc.go
@@ -0,0 +1,233 @@
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a MIT license found in the LICENSE file.
+
+package codec
+
+import (
+ "bufio"
+ "errors"
+ "io"
+ "net/rpc"
+)
+
+var errRpcJsonNeedsTermWhitespace = errors.New("rpc requires JsonHandle with TermWhitespace=true")
+
+// Rpc provides a rpc Server or Client Codec for rpc communication.
+type Rpc interface {
+ ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec
+ ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec
+}
+
+// RPCOptions holds options specific to rpc functionality
+type RPCOptions struct {
+ // RPCNoBuffer configures whether we attempt to buffer reads and writes during RPC calls.
+ //
+ // Set RPCNoBuffer=true to turn buffering off.
+ // Buffering can still be done if buffered connections are passed in, or
+ // buffering is configured on the handle.
+ RPCNoBuffer bool
+}
+
+// rpcCodec defines the struct members and common methods.
+type rpcCodec struct {
+ c io.Closer
+ r io.Reader
+ w io.Writer
+ f ioFlusher
+
+ dec *Decoder
+ enc *Encoder
+ // bw *bufio.Writer
+ // br *bufio.Reader
+ h Handle
+
+ cls atomicClsErr
+}
+
+func newRPCCodec(conn io.ReadWriteCloser, h Handle) rpcCodec {
+ // return newRPCCodec2(bufio.NewReader(conn), bufio.NewWriter(conn), conn, h)
+ return newRPCCodec2(conn, conn, conn, h)
+}
+
+func newRPCCodec2(r io.Reader, w io.Writer, c io.Closer, h Handle) rpcCodec {
+ // defensive: ensure that jsonH has TermWhitespace turned on.
+ if jsonH, ok := h.(*JsonHandle); ok && !jsonH.TermWhitespace {
+ panic(errRpcJsonNeedsTermWhitespace)
+ }
+ // always ensure that we use a flusher, and always flush what was written to the connection.
+ // we lose nothing by using a buffered writer internally.
+ f, ok := w.(ioFlusher)
+ bh := basicHandle(h)
+ if !bh.RPCNoBuffer {
+ if bh.WriterBufferSize <= 0 {
+ if !ok {
+ bw := bufio.NewWriter(w)
+ f, w = bw, bw
+ }
+ }
+ if bh.ReaderBufferSize <= 0 {
+ if _, ok = w.(ioPeeker); !ok {
+ if _, ok = w.(ioBuffered); !ok {
+ br := bufio.NewReader(r)
+ r = br
+ }
+ }
+ }
+ }
+ return rpcCodec{
+ c: c,
+ w: w,
+ r: r,
+ f: f,
+ h: h,
+ enc: NewEncoder(w, h),
+ dec: NewDecoder(r, h),
+ }
+}
+
+func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2 bool) (err error) {
+ if c.c != nil {
+ cls := c.cls.load()
+ if cls.closed {
+ return cls.errClosed
+ }
+ }
+ err = c.enc.Encode(obj1)
+ if err == nil {
+ if writeObj2 {
+ err = c.enc.Encode(obj2)
+ }
+ // if err == nil && c.f != nil {
+ // err = c.f.Flush()
+ // }
+ }
+ if c.f != nil {
+ if err == nil {
+ err = c.f.Flush()
+ } else {
+ _ = c.f.Flush() // swallow flush error, so we maintain prior error on write
+ }
+ }
+ return
+}
+
+func (c *rpcCodec) swallow(err *error) {
+ defer panicToErr(c.dec, err)
+ c.dec.swallow()
+}
+
+func (c *rpcCodec) read(obj interface{}) (err error) {
+ if c.c != nil {
+ cls := c.cls.load()
+ if cls.closed {
+ return cls.errClosed
+ }
+ }
+ //If nil is passed in, we should read and discard
+ if obj == nil {
+ // var obj2 interface{}
+ // return c.dec.Decode(&obj2)
+ c.swallow(&err)
+ return
+ }
+ return c.dec.Decode(obj)
+}
+
+func (c *rpcCodec) Close() error {
+ if c.c == nil {
+ return nil
+ }
+ cls := c.cls.load()
+ if cls.closed {
+ return cls.errClosed
+ }
+ cls.errClosed = c.c.Close()
+ cls.closed = true
+ c.cls.store(cls)
+ return cls.errClosed
+}
+
+func (c *rpcCodec) ReadResponseBody(body interface{}) error {
+ return c.read(body)
+}
+
+// -------------------------------------
+
+type goRpcCodec struct {
+ rpcCodec
+}
+
+func (c *goRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error {
+ return c.write(r, body, true)
+}
+
+func (c *goRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error {
+ err := c.write(r, body, true)
+ if err != nil {
+ // If error occurred writing a response, close the underlying connection.
+ // See hashicorp/net-rpc-msgpackrpc#15
+ c.Close()
+ }
+ return err
+}
+
+func (c *goRpcCodec) ReadResponseHeader(r *rpc.Response) error {
+ return c.read(r)
+}
+
+func (c *goRpcCodec) ReadRequestHeader(r *rpc.Request) error {
+ return c.read(r)
+}
+
+func (c *goRpcCodec) ReadRequestBody(body interface{}) error {
+ return c.read(body)
+}
+
+// -------------------------------------
+
+// goRpc is the implementation of Rpc that uses the communication protocol
+// as defined in net/rpc package.
+type goRpc struct{}
+
+// GoRpc implements Rpc using the communication protocol defined in net/rpc package.
+//
+// Note: network connection (from net.Dial, of type io.ReadWriteCloser) is not buffered.
+//
+// For performance, you should configure WriterBufferSize and ReaderBufferSize on the handle.
+// This ensures we use an adequate buffer during reading and writing.
+// If not configured, we will internally initialize and use a buffer during reads and writes.
+// This can be turned off via the RPCNoBuffer option on the Handle.
+//
+// var handle codec.JsonHandle
+// handle.RPCNoBuffer = true // turns off attempt by rpc module to initialize a buffer
+//
+// Example 1: one way of configuring buffering explicitly:
+//
+// var handle codec.JsonHandle // codec handle
+// handle.ReaderBufferSize = 1024
+// handle.WriterBufferSize = 1024
+// var conn io.ReadWriteCloser // connection got from a socket
+// var serverCodec = GoRpc.ServerCodec(conn, handle)
+// var clientCodec = GoRpc.ClientCodec(conn, handle)
+//
+// Example 2: you can also explicitly create a buffered connection yourself,
+// and not worry about configuring the buffer sizes in the Handle.
+//
+// var handle codec.Handle // codec handle
+// var conn io.ReadWriteCloser // connection got from a socket
+// var bufconn = struct { // bufconn here is a buffered io.ReadWriteCloser
+// io.Closer
+// *bufio.Reader
+// *bufio.Writer
+// }{conn, bufio.NewReader(conn), bufio.NewWriter(conn)}
+// var serverCodec = GoRpc.ServerCodec(bufconn, handle)
+// var clientCodec = GoRpc.ClientCodec(bufconn, handle)
+var GoRpc goRpc
+
+func (x goRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec {
+ return &goRpcCodec{newRPCCodec(conn, h)}
+}
+
+func (x goRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec {
+ return &goRpcCodec{newRPCCodec(conn, h)}
+}
diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/test.py b/vendor/github.com/hashicorp/go-msgpack/v2/codec/test.py
new file mode 100644
index 00000000000..8418fee4d1e
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/test.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+
+# This will create golden files in a directory passed to it.
+# A Test calls this internally to create the golden files
+# So it can process them (so we don't have to checkin the files).
+
+# Ensure msgpack-python is installed first, using:
+# sudo apt-get install python-dev
+# sudo apt-get install python-pip
+# pip install --user msgpack-python msgpack-rpc-python
+
+# Ensure all "string" keys are utf strings (else encoded as bytes)
+
+import msgpack, msgpackrpc, sys, os, threading
+
+def get_test_data_list():
+ # get list with all primitive types, and a combo type
+ l0 = [
+ -8,
+ -1616,
+ -32323232,
+ -6464646464646464,
+ 192,
+ 1616,
+ 32323232,
+ 6464646464646464,
+ 192,
+ -3232.0,
+ -6464646464.0,
+ 3232.0,
+ 6464.0,
+ 6464646464.0,
+ False,
+ True,
+ u"null",
+ None,
+ u"some&day>some 0
+ if stopTimeSec > 0:
+ def myStopRpcServer():
+ server.stop()
+ t = threading.Timer(stopTimeSec, myStopRpcServer)
+ t.start()
+ server.start()
+
+def doRpcClientToPythonSvc(port):
+ address = msgpackrpc.Address('127.0.0.1', port)
+ client = msgpackrpc.Client(address, unpack_encoding='utf-8')
+ print(client.call("Echo123", "A1", "B2", "C3"))
+ print(client.call("EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"}))
+
+def doRpcClientToGoSvc(port):
+ # print ">>>> port: ", port, " <<<<<"
+ address = msgpackrpc.Address('127.0.0.1', port)
+ client = msgpackrpc.Client(address, unpack_encoding='utf-8')
+ print(client.call("TestRpcInt.Echo123", ["A1", "B2", "C3"]))
+ print(client.call("TestRpcInt.EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"}))
+
+def doMain(args):
+ if len(args) == 2 and args[0] == "testdata":
+ build_test_data(args[1])
+ elif len(args) == 3 and args[0] == "rpc-server":
+ doRpcServer(int(args[1]), int(args[2]))
+ elif len(args) == 2 and args[0] == "rpc-client-python-service":
+ doRpcClientToPythonSvc(int(args[1]))
+ elif len(args) == 2 and args[0] == "rpc-client-go-service":
+ doRpcClientToGoSvc(int(args[1]))
+ else:
+ print("Usage: test.py " +
+ "[testdata|rpc-server|rpc-client-python-service|rpc-client-go-service] ...")
+
+if __name__ == "__main__":
+ doMain(sys.argv[1:])
+
diff --git a/vendor/github.com/hashicorp/go-multierror/LICENSE b/vendor/github.com/hashicorp/go-multierror/LICENSE
new file mode 100644
index 00000000000..82b4de97c7e
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/LICENSE
@@ -0,0 +1,353 @@
+Mozilla Public License, version 2.0
+
+1. Definitions
+
+1.1. “Contributor”
+
+ means each individual or legal entity that creates, contributes to the
+ creation of, or owns Covered Software.
+
+1.2. “Contributor Version”
+
+ means the combination of the Contributions of others (if any) used by a
+ Contributor and that particular Contributor’s Contribution.
+
+1.3. “Contribution”
+
+ means Covered Software of a particular Contributor.
+
+1.4. “Covered Software”
+
+ means Source Code Form to which the initial Contributor has attached the
+ notice in Exhibit A, the Executable Form of such Source Code Form, and
+ Modifications of such Source Code Form, in each case including portions
+ thereof.
+
+1.5. “Incompatible With Secondary Licenses”
+ means
+
+ a. that the initial Contributor has attached the notice described in
+ Exhibit B to the Covered Software; or
+
+ b. that the Covered Software was made available under the terms of version
+ 1.1 or earlier of the License, but not also under the terms of a
+ Secondary License.
+
+1.6. “Executable Form”
+
+ means any form of the work other than Source Code Form.
+
+1.7. “Larger Work”
+
+ means a work that combines Covered Software with other material, in a separate
+ file or files, that is not Covered Software.
+
+1.8. “License”
+
+ means this document.
+
+1.9. “Licensable”
+
+ means having the right to grant, to the maximum extent possible, whether at the
+ time of the initial grant or subsequently, any and all of the rights conveyed by
+ this License.
+
+1.10. “Modifications”
+
+ means any of the following:
+
+ a. any file in Source Code Form that results from an addition to, deletion
+ from, or modification of the contents of Covered Software; or
+
+ b. any new file in Source Code Form that contains any Covered Software.
+
+1.11. “Patent Claims” of a Contributor
+
+ means any patent claim(s), including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by such Contributor that
+ would be infringed, but for the grant of the License, by the making,
+ using, selling, offering for sale, having made, import, or transfer of
+ either its Contributions or its Contributor Version.
+
+1.12. “Secondary License”
+
+ means either the GNU General Public License, Version 2.0, the GNU Lesser
+ General Public License, Version 2.1, the GNU Affero General Public
+ License, Version 3.0, or any later versions of those licenses.
+
+1.13. “Source Code Form”
+
+ means the form of the work preferred for making modifications.
+
+1.14. “You” (or “Your”)
+
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, “You” includes any entity that controls, is
+ controlled by, or is under common control with You. For purposes of this
+ definition, “control” means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by contract or
+ otherwise, or (b) ownership of more than fifty percent (50%) of the
+ outstanding shares or beneficial ownership of such entity.
+
+
+2. License Grants and Conditions
+
+2.1. Grants
+
+ Each Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ a. under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or as
+ part of a Larger Work; and
+
+ b. under Patent Claims of such Contributor to make, use, sell, offer for
+ sale, have made, import, and otherwise transfer either its Contributions
+ or its Contributor Version.
+
+2.2. Effective Date
+
+ The licenses granted in Section 2.1 with respect to any Contribution become
+ effective for each Contribution on the date the Contributor first distributes
+ such Contribution.
+
+2.3. Limitations on Grant Scope
+
+ The licenses granted in this Section 2 are the only rights granted under this
+ License. No additional rights or licenses will be implied from the distribution
+ or licensing of Covered Software under this License. Notwithstanding Section
+ 2.1(b) above, no patent license is granted by a Contributor:
+
+ a. for any code that a Contributor has removed from Covered Software; or
+
+ b. for infringements caused by: (i) Your and any other third party’s
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+ c. under Patent Claims infringed by Covered Software in the absence of its
+ Contributions.
+
+ This License does not grant any rights in the trademarks, service marks, or
+ logos of any Contributor (except as may be necessary to comply with the
+ notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+ No Contributor makes additional grants as a result of Your choice to
+ distribute the Covered Software under a subsequent version of this License
+ (see Section 10.2) or under the terms of a Secondary License (if permitted
+ under the terms of Section 3.3).
+
+2.5. Representation
+
+ Each Contributor represents that the Contributor believes its Contributions
+ are its original creation(s) or it has sufficient rights to grant the
+ rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+ This License is not intended to limit any rights You have under applicable
+ copyright doctrines of fair use, fair dealing, or other equivalents.
+
+2.7. Conditions
+
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+ Section 2.1.
+
+
+3. Responsibilities
+
+3.1. Distribution of Source Form
+
+ All distribution of Covered Software in Source Code Form, including any
+ Modifications that You create or to which You contribute, must be under the
+ terms of this License. You must inform recipients that the Source Code Form
+ of the Covered Software is governed by the terms of this License, and how
+ they can obtain a copy of this License. You may not attempt to alter or
+ restrict the recipients’ rights in the Source Code Form.
+
+3.2. Distribution of Executable Form
+
+ If You distribute Covered Software in Executable Form then:
+
+ a. such Covered Software must also be made available in Source Code Form,
+ as described in Section 3.1, and You must inform recipients of the
+ Executable Form how they can obtain a copy of such Source Code Form by
+ reasonable means in a timely manner, at a charge no more than the cost
+ of distribution to the recipient; and
+
+ b. You may distribute such Executable Form under the terms of this License,
+ or sublicense it under different terms, provided that the license for
+ the Executable Form does not attempt to limit or alter the recipients’
+ rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+ You may create and distribute a Larger Work under terms of Your choice,
+ provided that You also comply with the requirements of this License for the
+ Covered Software. If the Larger Work is a combination of Covered Software
+ with a work governed by one or more Secondary Licenses, and the Covered
+ Software is not Incompatible With Secondary Licenses, this License permits
+ You to additionally distribute such Covered Software under the terms of
+ such Secondary License(s), so that the recipient of the Larger Work may, at
+ their option, further distribute the Covered Software under the terms of
+ either this License or such Secondary License(s).
+
+3.4. Notices
+
+ You may not remove or alter the substance of any license notices (including
+ copyright notices, patent notices, disclaimers of warranty, or limitations
+ of liability) contained within the Source Code Form of the Covered
+ Software, except that You may alter any license notices to the extent
+ required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+ You may choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of Covered
+ Software. However, You may do so only on Your own behalf, and not on behalf
+ of any Contributor. You must make it absolutely clear that any such
+ warranty, support, indemnity, or liability obligation is offered by You
+ alone, and You hereby agree to indemnify every Contributor for any
+ liability incurred by such Contributor as a result of warranty, support,
+ indemnity or liability terms You offer. You may include additional
+ disclaimers of warranty and limitations of liability specific to any
+ jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+
+ If it is impossible for You to comply with any of the terms of this License
+ with respect to some or all of the Covered Software due to statute, judicial
+ order, or regulation then You must: (a) comply with the terms of this License
+ to the maximum extent possible; and (b) describe the limitations and the code
+ they affect. Such description must be placed in a text file included with all
+ distributions of the Covered Software under this License. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+
+5. Termination
+
+5.1. The rights granted under this License will terminate automatically if You
+ fail to comply with any of its terms. However, if You become compliant,
+ then the rights granted under this License from a particular Contributor
+ are reinstated (a) provisionally, unless and until such Contributor
+ explicitly and finally terminates Your grants, and (b) on an ongoing basis,
+ if such Contributor fails to notify You of the non-compliance by some
+ reasonable means prior to 60 days after You have come back into compliance.
+ Moreover, Your grants from a particular Contributor are reinstated on an
+ ongoing basis if such Contributor notifies You of the non-compliance by
+ some reasonable means, this is the first time You have received notice of
+ non-compliance with this License from such Contributor, and You become
+ compliant prior to 30 days after Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+ infringement claim (excluding declaratory judgment actions, counter-claims,
+ and cross-claims) alleging that a Contributor Version directly or
+ indirectly infringes any patent, then the rights granted to You by any and
+ all Contributors for the Covered Software under Section 2.1 of this License
+ shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
+ license agreements (excluding distributors and resellers) which have been
+ validly granted by You or Your distributors under this License prior to
+ termination shall survive termination.
+
+6. Disclaimer of Warranty
+
+ Covered Software is provided under this License on an “as is” basis, without
+ warranty of any kind, either expressed, implied, or statutory, including,
+ without limitation, warranties that the Covered Software is free of defects,
+ merchantable, fit for a particular purpose or non-infringing. The entire
+ risk as to the quality and performance of the Covered Software is with You.
+ Should any Covered Software prove defective in any respect, You (not any
+ Contributor) assume the cost of any necessary servicing, repair, or
+ correction. This disclaimer of warranty constitutes an essential part of this
+ License. No use of any Covered Software is authorized under this License
+ except under this disclaimer.
+
+7. Limitation of Liability
+
+ Under no circumstances and under no legal theory, whether tort (including
+ negligence), contract, or otherwise, shall any Contributor, or anyone who
+ distributes Covered Software as permitted above, be liable to You for any
+ direct, indirect, special, incidental, or consequential damages of any
+ character including, without limitation, damages for lost profits, loss of
+ goodwill, work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses, even if such party shall have been
+ informed of the possibility of such damages. This limitation of liability
+ shall not apply to liability for death or personal injury resulting from such
+ party’s negligence to the extent applicable law prohibits such limitation.
+ Some jurisdictions do not allow the exclusion or limitation of incidental or
+ consequential damages, so this exclusion and limitation may not apply to You.
+
+8. Litigation
+
+ Any litigation relating to this License may be brought only in the courts of
+ a jurisdiction where the defendant maintains its principal place of business
+ and such litigation shall be governed by laws of that jurisdiction, without
+ reference to its conflict-of-law provisions. Nothing in this Section shall
+ prevent a party’s ability to bring cross-claims or counter-claims.
+
+9. Miscellaneous
+
+ This License represents the complete agreement concerning the subject matter
+ hereof. If any provision of this License is held to be unenforceable, such
+ provision shall be reformed only to the extent necessary to make it
+ enforceable. Any law or regulation which provides that the language of a
+ contract shall be construed against the drafter shall not be used to construe
+ this License against a Contributor.
+
+
+10. Versions of the License
+
+10.1. New Versions
+
+ Mozilla Foundation is the license steward. Except as provided in Section
+ 10.3, no one other than the license steward has the right to modify or
+ publish new versions of this License. Each version will be given a
+ distinguishing version number.
+
+10.2. Effect of New Versions
+
+ You may distribute the Covered Software under the terms of the version of
+ the License under which You originally received the Covered Software, or
+ under the terms of any subsequent version published by the license
+ steward.
+
+10.3. Modified Versions
+
+ If you create software not governed by this License, and you want to
+ create a new license for such software, you may create and use a modified
+ version of this License if you rename the license and remove any
+ references to the name of the license steward (except to note that such
+ modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
+ If You choose to distribute Source Code Form that is Incompatible With
+ Secondary Licenses under the terms of this version of the License, the
+ notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+
+ This Source Code Form is subject to the
+ terms of the Mozilla Public License, v.
+ 2.0. If a copy of the MPL was not
+ distributed with this file, You can
+ obtain one at
+ http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular file, then
+You may include the notice in a location (such as a LICENSE file in a relevant
+directory) where a recipient would be likely to look for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - “Incompatible With Secondary Licenses” Notice
+
+ This Source Code Form is “Incompatible
+ With Secondary Licenses”, as defined by
+ the Mozilla Public License, v. 2.0.
diff --git a/vendor/github.com/hashicorp/go-multierror/Makefile b/vendor/github.com/hashicorp/go-multierror/Makefile
new file mode 100644
index 00000000000..b97cd6ed02b
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/Makefile
@@ -0,0 +1,31 @@
+TEST?=./...
+
+default: test
+
+# test runs the test suite and vets the code.
+test: generate
+ @echo "==> Running tests..."
+ @go list $(TEST) \
+ | grep -v "/vendor/" \
+ | xargs -n1 go test -timeout=60s -parallel=10 ${TESTARGS}
+
+# testrace runs the race checker
+testrace: generate
+ @echo "==> Running tests (race)..."
+ @go list $(TEST) \
+ | grep -v "/vendor/" \
+ | xargs -n1 go test -timeout=60s -race ${TESTARGS}
+
+# updatedeps installs all the dependencies needed to run and build.
+updatedeps:
+ @sh -c "'${CURDIR}/scripts/deps.sh' '${NAME}'"
+
+# generate runs `go generate` to build the dynamically generated source files.
+generate:
+ @echo "==> Generating..."
+ @find . -type f -name '.DS_Store' -delete
+ @go list ./... \
+ | grep -v "/vendor/" \
+ | xargs -n1 go generate
+
+.PHONY: default test testrace updatedeps generate
diff --git a/vendor/github.com/hashicorp/go-multierror/README.md b/vendor/github.com/hashicorp/go-multierror/README.md
new file mode 100644
index 00000000000..71dd308ed81
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/README.md
@@ -0,0 +1,150 @@
+# go-multierror
+
+[](https://circleci.com/gh/hashicorp/go-multierror)
+[](https://pkg.go.dev/github.com/hashicorp/go-multierror)
+
+
+[circleci]: https://app.circleci.com/pipelines/github/hashicorp/go-multierror
+[godocs]: https://pkg.go.dev/github.com/hashicorp/go-multierror
+
+`go-multierror` is a package for Go that provides a mechanism for
+representing a list of `error` values as a single `error`.
+
+This allows a function in Go to return an `error` that might actually
+be a list of errors. If the caller knows this, they can unwrap the
+list and access the errors. If the caller doesn't know, the error
+formats to a nice human-readable format.
+
+`go-multierror` is fully compatible with the Go standard library
+[errors](https://golang.org/pkg/errors/) package, including the
+functions `As`, `Is`, and `Unwrap`. This provides a standardized approach
+for introspecting on error values.
+
+## Installation and Docs
+
+Install using `go get github.com/hashicorp/go-multierror`.
+
+Full documentation is available at
+https://pkg.go.dev/github.com/hashicorp/go-multierror
+
+### Requires go version 1.13 or newer
+
+`go-multierror` requires go version 1.13 or newer. Go 1.13 introduced
+[error wrapping](https://golang.org/doc/go1.13#error_wrapping), which
+this library takes advantage of.
+
+If you need to use an earlier version of go, you can use the
+[v1.0.0](https://github.com/hashicorp/go-multierror/tree/v1.0.0)
+tag, which doesn't rely on features in go 1.13.
+
+If you see compile errors that look like the below, it's likely that
+you're on an older version of go:
+
+```
+/go/src/github.com/hashicorp/go-multierror/multierror.go:112:9: undefined: errors.As
+/go/src/github.com/hashicorp/go-multierror/multierror.go:117:9: undefined: errors.Is
+```
+
+## Usage
+
+go-multierror is easy to use and purposely built to be unobtrusive in
+existing Go applications/libraries that may not be aware of it.
+
+**Building a list of errors**
+
+The `Append` function is used to create a list of errors. This function
+behaves a lot like the Go built-in `append` function: it doesn't matter
+if the first argument is nil, a `multierror.Error`, or any other `error`,
+the function behaves as you would expect.
+
+```go
+var result error
+
+if err := step1(); err != nil {
+ result = multierror.Append(result, err)
+}
+if err := step2(); err != nil {
+ result = multierror.Append(result, err)
+}
+
+return result
+```
+
+**Customizing the formatting of the errors**
+
+By specifying a custom `ErrorFormat`, you can customize the format
+of the `Error() string` function:
+
+```go
+var result *multierror.Error
+
+// ... accumulate errors here, maybe using Append
+
+if result != nil {
+ result.ErrorFormat = func([]error) string {
+ return "errors!"
+ }
+}
+```
+
+**Accessing the list of errors**
+
+`multierror.Error` implements `error` so if the caller doesn't know about
+multierror, it will work just fine. But if you're aware a multierror might
+be returned, you can use type switches to access the list of errors:
+
+```go
+if err := something(); err != nil {
+ if merr, ok := err.(*multierror.Error); ok {
+ // Use merr.Errors
+ }
+}
+```
+
+You can also use the standard [`errors.Unwrap`](https://golang.org/pkg/errors/#Unwrap)
+function. This will continue to unwrap into subsequent errors until none exist.
+
+**Extracting an error**
+
+The standard library [`errors.As`](https://golang.org/pkg/errors/#As)
+function can be used directly with a multierror to extract a specific error:
+
+```go
+// Assume err is a multierror value
+err := somefunc()
+
+// We want to know if "err" has a "RichErrorType" in it and extract it.
+var errRich RichErrorType
+if errors.As(err, &errRich) {
+ // It has it, and now errRich is populated.
+}
+```
+
+**Checking for an exact error value**
+
+Some errors are returned as exact errors such as the [`ErrNotExist`](https://golang.org/pkg/os/#pkg-variables)
+error in the `os` package. You can check if this error is present by using
+the standard [`errors.Is`](https://golang.org/pkg/errors/#Is) function.
+
+```go
+// Assume err is a multierror value
+err := somefunc()
+if errors.Is(err, os.ErrNotExist) {
+ // err contains os.ErrNotExist
+}
+```
+
+**Returning a multierror only if there are errors**
+
+If you build a `multierror.Error`, you can use the `ErrorOrNil` function
+to return an `error` implementation only if there are errors to return:
+
+```go
+var result *multierror.Error
+
+// ... accumulate errors here
+
+// Return the `error` only if errors were added to the multierror, otherwise
+// return nil since there are no errors.
+return result.ErrorOrNil()
+```
diff --git a/vendor/github.com/hashicorp/go-multierror/append.go b/vendor/github.com/hashicorp/go-multierror/append.go
new file mode 100644
index 00000000000..3e2589bfde0
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/append.go
@@ -0,0 +1,43 @@
+package multierror
+
+// Append is a helper function that will append more errors
+// onto an Error in order to create a larger multi-error.
+//
+// If err is not a multierror.Error, then it will be turned into
+// one. If any of the errs are multierr.Error, they will be flattened
+// one level into err.
+// Any nil errors within errs will be ignored. If err is nil, a new
+// *Error will be returned.
+func Append(err error, errs ...error) *Error {
+ switch err := err.(type) {
+ case *Error:
+ // Typed nils can reach here, so initialize if we are nil
+ if err == nil {
+ err = new(Error)
+ }
+
+ // Go through each error and flatten
+ for _, e := range errs {
+ switch e := e.(type) {
+ case *Error:
+ if e != nil {
+ err.Errors = append(err.Errors, e.Errors...)
+ }
+ default:
+ if e != nil {
+ err.Errors = append(err.Errors, e)
+ }
+ }
+ }
+
+ return err
+ default:
+ newErrs := make([]error, 0, len(errs)+1)
+ if err != nil {
+ newErrs = append(newErrs, err)
+ }
+ newErrs = append(newErrs, errs...)
+
+ return Append(&Error{}, newErrs...)
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/flatten.go b/vendor/github.com/hashicorp/go-multierror/flatten.go
new file mode 100644
index 00000000000..aab8e9abec9
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/flatten.go
@@ -0,0 +1,26 @@
+package multierror
+
+// Flatten flattens the given error, merging any *Errors together into
+// a single *Error.
+func Flatten(err error) error {
+ // If it isn't an *Error, just return the error as-is
+ if _, ok := err.(*Error); !ok {
+ return err
+ }
+
+ // Otherwise, make the result and flatten away!
+ flatErr := new(Error)
+ flatten(err, flatErr)
+ return flatErr
+}
+
+func flatten(err error, flatErr *Error) {
+ switch err := err.(type) {
+ case *Error:
+ for _, e := range err.Errors {
+ flatten(e, flatErr)
+ }
+ default:
+ flatErr.Errors = append(flatErr.Errors, err)
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/format.go b/vendor/github.com/hashicorp/go-multierror/format.go
new file mode 100644
index 00000000000..47f13c49a67
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/format.go
@@ -0,0 +1,27 @@
+package multierror
+
+import (
+ "fmt"
+ "strings"
+)
+
+// ErrorFormatFunc is a function callback that is called by Error to
+// turn the list of errors into a string.
+type ErrorFormatFunc func([]error) string
+
+// ListFormatFunc is a basic formatter that outputs the number of errors
+// that occurred along with a bullet point list of the errors.
+func ListFormatFunc(es []error) string {
+ if len(es) == 1 {
+ return fmt.Sprintf("1 error occurred:\n\t* %s\n\n", es[0])
+ }
+
+ points := make([]string, len(es))
+ for i, err := range es {
+ points[i] = fmt.Sprintf("* %s", err)
+ }
+
+ return fmt.Sprintf(
+ "%d errors occurred:\n\t%s\n\n",
+ len(es), strings.Join(points, "\n\t"))
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/group.go b/vendor/github.com/hashicorp/go-multierror/group.go
new file mode 100644
index 00000000000..9c29efb7f87
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/group.go
@@ -0,0 +1,38 @@
+package multierror
+
+import "sync"
+
+// Group is a collection of goroutines which return errors that need to be
+// coalesced.
+type Group struct {
+ mutex sync.Mutex
+ err *Error
+ wg sync.WaitGroup
+}
+
+// Go calls the given function in a new goroutine.
+//
+// If the function returns an error it is added to the group multierror which
+// is returned by Wait.
+func (g *Group) Go(f func() error) {
+ g.wg.Add(1)
+
+ go func() {
+ defer g.wg.Done()
+
+ if err := f(); err != nil {
+ g.mutex.Lock()
+ g.err = Append(g.err, err)
+ g.mutex.Unlock()
+ }
+ }()
+}
+
+// Wait blocks until all function calls from the Go method have returned, then
+// returns the multierror.
+func (g *Group) Wait() *Error {
+ g.wg.Wait()
+ g.mutex.Lock()
+ defer g.mutex.Unlock()
+ return g.err
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/multierror.go b/vendor/github.com/hashicorp/go-multierror/multierror.go
new file mode 100644
index 00000000000..f5457432646
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/multierror.go
@@ -0,0 +1,121 @@
+package multierror
+
+import (
+ "errors"
+ "fmt"
+)
+
+// Error is an error type to track multiple errors. This is used to
+// accumulate errors in cases and return them as a single "error".
+type Error struct {
+ Errors []error
+ ErrorFormat ErrorFormatFunc
+}
+
+func (e *Error) Error() string {
+ fn := e.ErrorFormat
+ if fn == nil {
+ fn = ListFormatFunc
+ }
+
+ return fn(e.Errors)
+}
+
+// ErrorOrNil returns an error interface if this Error represents
+// a list of errors, or returns nil if the list of errors is empty. This
+// function is useful at the end of accumulation to make sure that the value
+// returned represents the existence of errors.
+func (e *Error) ErrorOrNil() error {
+ if e == nil {
+ return nil
+ }
+ if len(e.Errors) == 0 {
+ return nil
+ }
+
+ return e
+}
+
+func (e *Error) GoString() string {
+ return fmt.Sprintf("*%#v", *e)
+}
+
+// WrappedErrors returns the list of errors that this Error is wrapping. It is
+// an implementation of the errwrap.Wrapper interface so that multierror.Error
+// can be used with that library.
+//
+// This method is not safe to be called concurrently. Unlike accessing the
+// Errors field directly, this function also checks if the multierror is nil to
+// prevent a null-pointer panic. It satisfies the errwrap.Wrapper interface.
+func (e *Error) WrappedErrors() []error {
+ if e == nil {
+ return nil
+ }
+ return e.Errors
+}
+
+// Unwrap returns an error from Error (or nil if there are no errors).
+// This error returned will further support Unwrap to get the next error,
+// etc. The order will match the order of Errors in the multierror.Error
+// at the time of calling.
+//
+// The resulting error supports errors.As/Is/Unwrap so you can continue
+// to use the stdlib errors package to introspect further.
+//
+// This will perform a shallow copy of the errors slice. Any errors appended
+// to this error after calling Unwrap will not be available until a new
+// Unwrap is called on the multierror.Error.
+func (e *Error) Unwrap() error {
+ // If we have no errors then we do nothing
+ if e == nil || len(e.Errors) == 0 {
+ return nil
+ }
+
+ // If we have exactly one error, we can just return that directly.
+ if len(e.Errors) == 1 {
+ return e.Errors[0]
+ }
+
+ // Shallow copy the slice
+ errs := make([]error, len(e.Errors))
+ copy(errs, e.Errors)
+ return chain(errs)
+}
+
+// chain implements the interfaces necessary for errors.Is/As/Unwrap to
+// work in a deterministic way with multierror. A chain tracks a list of
+// errors while accounting for the current represented error. This lets
+// Is/As be meaningful.
+//
+// Unwrap returns the next error. In the cleanest form, Unwrap would return
+// the wrapped error here but we can't do that if we want to properly
+// get access to all the errors. Instead, users are recommended to use
+// Is/As to get the correct error type out.
+//
+// Precondition: []error is non-empty (len > 0)
+type chain []error
+
+// Error implements the error interface
+func (e chain) Error() string {
+ return e[0].Error()
+}
+
+// Unwrap implements errors.Unwrap by returning the next error in the
+// chain or nil if there are no more errors.
+func (e chain) Unwrap() error {
+ if len(e) == 1 {
+ return nil
+ }
+
+ return e[1:]
+}
+
+// As implements errors.As by attempting to map to the current value.
+func (e chain) As(target interface{}) bool {
+ return errors.As(e[0], target)
+}
+
+// Is implements errors.Is by comparing the current value directly.
+func (e chain) Is(target error) bool {
+ return errors.Is(e[0], target)
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/prefix.go b/vendor/github.com/hashicorp/go-multierror/prefix.go
new file mode 100644
index 00000000000..5c477abe44f
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/prefix.go
@@ -0,0 +1,37 @@
+package multierror
+
+import (
+ "fmt"
+
+ "github.com/hashicorp/errwrap"
+)
+
+// Prefix is a helper function that will prefix some text
+// to the given error. If the error is a multierror.Error, then
+// it will be prefixed to each wrapped error.
+//
+// This is useful to use when appending multiple multierrors
+// together in order to give better scoping.
+func Prefix(err error, prefix string) error {
+ if err == nil {
+ return nil
+ }
+
+ format := fmt.Sprintf("%s {{err}}", prefix)
+ switch err := err.(type) {
+ case *Error:
+ // Typed nils can reach here, so initialize if we are nil
+ if err == nil {
+ err = new(Error)
+ }
+
+ // Wrap each of the errors
+ for i, e := range err.Errors {
+ err.Errors[i] = errwrap.Wrapf(format, e)
+ }
+
+ return err
+ default:
+ return errwrap.Wrapf(format, err)
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/sort.go b/vendor/github.com/hashicorp/go-multierror/sort.go
new file mode 100644
index 00000000000..fecb14e81c5
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/sort.go
@@ -0,0 +1,16 @@
+package multierror
+
+// Len implements sort.Interface function for length
+func (err Error) Len() int {
+ return len(err.Errors)
+}
+
+// Swap implements sort.Interface function for swapping elements
+func (err Error) Swap(i, j int) {
+ err.Errors[i], err.Errors[j] = err.Errors[j], err.Errors[i]
+}
+
+// Less implements sort.Interface function for determining order
+func (err Error) Less(i, j int) bool {
+ return err.Errors[i].Error() < err.Errors[j].Error()
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/.gitignore b/vendor/github.com/hashicorp/go-sockaddr/.gitignore
new file mode 100644
index 00000000000..41720b86e3e
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/.gitignore
@@ -0,0 +1,26 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+.cover.out*
+coverage.html
diff --git a/vendor/github.com/hashicorp/go-sockaddr/GNUmakefile b/vendor/github.com/hashicorp/go-sockaddr/GNUmakefile
new file mode 100644
index 00000000000..0f3ae1661e2
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/GNUmakefile
@@ -0,0 +1,65 @@
+TOOLS= golang.org/x/tools/cover
+GOCOVER_TMPFILE?= $(GOCOVER_FILE).tmp
+GOCOVER_FILE?= .cover.out
+GOCOVERHTML?= coverage.html
+FIND=`/usr/bin/which 2> /dev/null gfind find | /usr/bin/grep -v ^no | /usr/bin/head -n 1`
+XARGS=`/usr/bin/which 2> /dev/null gxargs xargs | /usr/bin/grep -v ^no | /usr/bin/head -n 1`
+
+test:: $(GOCOVER_FILE)
+ @$(MAKE) -C cmd/sockaddr test
+
+cover:: coverage_report
+
+$(GOCOVER_FILE)::
+ @${FIND} . -type d ! -path '*cmd*' ! -path '*.git*' -print0 | ${XARGS} -0 -I % sh -ec "cd % && rm -f $(GOCOVER_TMPFILE) && go test -coverprofile=$(GOCOVER_TMPFILE)"
+
+ @echo 'mode: set' > $(GOCOVER_FILE)
+ @${FIND} . -type f ! -path '*cmd*' ! -path '*.git*' -name "$(GOCOVER_TMPFILE)" -print0 | ${XARGS} -0 -n1 cat $(GOCOVER_TMPFILE) | grep -v '^mode: ' >> ${PWD}/$(GOCOVER_FILE)
+
+$(GOCOVERHTML): $(GOCOVER_FILE)
+ go tool cover -html=$(GOCOVER_FILE) -o $(GOCOVERHTML)
+
+coverage_report:: $(GOCOVER_FILE)
+ go tool cover -html=$(GOCOVER_FILE)
+
+audit_tools::
+ @go get -u github.com/golang/lint/golint && echo "Installed golint:"
+ @go get -u github.com/fzipp/gocyclo && echo "Installed gocyclo:"
+ @go get -u github.com/remyoudompheng/go-misc/deadcode && echo "Installed deadcode:"
+ @go get -u github.com/client9/misspell/cmd/misspell && echo "Installed misspell:"
+ @go get -u github.com/gordonklaus/ineffassign && echo "Installed ineffassign:"
+
+audit::
+ deadcode
+ go tool vet -all *.go
+ go tool vet -shadow=true *.go
+ golint *.go
+ ineffassign .
+ gocyclo -over 65 *.go
+ misspell *.go
+
+clean::
+ rm -f $(GOCOVER_FILE) $(GOCOVERHTML)
+
+dev::
+ @go build
+ @$(MAKE) -B -C cmd/sockaddr sockaddr
+
+install::
+ @go install
+ @$(MAKE) -C cmd/sockaddr install
+
+doc::
+ @echo Visit: http://127.0.0.1:6161/pkg/github.com/hashicorp/go-sockaddr/
+ godoc -http=:6161 -goroot $GOROOT
+
+world::
+ @set -e; \
+ for os in solaris darwin freebsd linux windows android; do \
+ for arch in amd64; do \
+ printf "Building on %s-%s\n" "$${os}" "$${arch}" ; \
+ env GOOS="$${os}" GOARCH="$${arch}" go build -o /dev/null; \
+ done; \
+ done
+
+ $(MAKE) -C cmd/sockaddr world
diff --git a/vendor/github.com/hashicorp/go-sockaddr/LICENSE b/vendor/github.com/hashicorp/go-sockaddr/LICENSE
new file mode 100644
index 00000000000..be467e386bb
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/LICENSE
@@ -0,0 +1,375 @@
+Copyright (c) 2016 HashiCorp, Inc.
+
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/vendor/github.com/hashicorp/go-sockaddr/README.md b/vendor/github.com/hashicorp/go-sockaddr/README.md
new file mode 100644
index 00000000000..3046031b638
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/README.md
@@ -0,0 +1,118 @@
+# go-sockaddr
+
+## `sockaddr` Library
+
+Socket address convenience functions for Go. `go-sockaddr` is a convenience
+library that makes doing the right thing with IP addresses easy. `go-sockaddr`
+is loosely modeled after the UNIX `sockaddr_t` and creates a union of the family
+of `sockaddr_t` types (see below for an ascii diagram). Library documentation
+is available
+at
+[https://godoc.org/github.com/hashicorp/go-sockaddr](https://godoc.org/github.com/hashicorp/go-sockaddr).
+The primary intent of the library was to make it possible to define heuristics
+for selecting the correct IP addresses when a configuration is evaluated at
+runtime. See
+the
+[docs](https://godoc.org/github.com/hashicorp/go-sockaddr),
+[`template` package](https://godoc.org/github.com/hashicorp/go-sockaddr/template),
+tests,
+and
+[CLI utility](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr)
+for details and hints as to how to use this library.
+
+For example, with this library it is possible to find an IP address that:
+
+* is attached to a default route
+ ([`GetDefaultInterfaces()`](https://godoc.org/github.com/hashicorp/go-sockaddr#GetDefaultInterfaces))
+* is contained within a CIDR block ([`IfByNetwork()`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByNetwork))
+* is an RFC1918 address
+ ([`IfByRFC("1918")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC))
+* is ordered
+ ([`OrderedIfAddrBy(args)`](https://godoc.org/github.com/hashicorp/go-sockaddr#OrderedIfAddrBy) where
+ `args` includes, but is not limited
+ to,
+ [`AscIfType`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscIfType),
+ [`AscNetworkSize`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscNetworkSize))
+* excludes all IPv6 addresses
+ ([`IfByType("^(IPv4)$")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByType))
+* is larger than a `/32`
+ ([`IfByMaskSize(32)`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByMaskSize))
+* is not on a `down` interface
+ ([`ExcludeIfs("flags", "down")`](https://godoc.org/github.com/hashicorp/go-sockaddr#ExcludeIfs))
+* preferences an IPv6 address over an IPv4 address
+ ([`SortIfByType()`](https://godoc.org/github.com/hashicorp/go-sockaddr#SortIfByType) +
+ [`ReverseIfAddrs()`](https://godoc.org/github.com/hashicorp/go-sockaddr#ReverseIfAddrs)); and
+* excludes any IP in RFC6890 address
+ ([`IfByRFC("6890")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC))
+
+Or any combination or variation therein.
+
+There are also a few simple helper functions such as `GetPublicIP` and
+`GetPrivateIP` which both return strings and select the first public or private
+IP address on the default interface, respectively. Similarly, there is also a
+helper function called `GetInterfaceIP` which returns the first usable IP
+address on the named interface.
+
+## `sockaddr` CLI
+
+Given the possible complexity of the `sockaddr` library, there is a CLI utility
+that accompanies the library, also
+called
+[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr).
+The
+[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr)
+utility exposes nearly all of the functionality of the library and can be used
+either as an administrative tool or testing tool. To install
+the
+[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr),
+run:
+
+```text
+$ go install github.com/hashicorp/go-sockaddr/cmd/sockaddr@latest
+```
+
+If you're familiar with UNIX's `sockaddr` struct's, the following diagram
+mapping the C `sockaddr` (top) to `go-sockaddr` structs (bottom) and
+interfaces will be helpful:
+
+```
++-------------------------------------------------------+
+| |
+| sockaddr |
+| SockAddr |
+| |
+| +--------------+ +----------------------------------+ |
+| | sockaddr_un | | | |
+| | SockAddrUnix | | sockaddr_in{,6} | |
+| +--------------+ | IPAddr | |
+| | | |
+| | +-------------+ +--------------+ | |
+| | | sockaddr_in | | sockaddr_in6 | | |
+| | | IPv4Addr | | IPv6Addr | | |
+| | +-------------+ +--------------+ | |
+| | | |
+| +----------------------------------+ |
+| |
++-------------------------------------------------------+
+```
+
+## Inspiration and Design
+
+There were many subtle inspirations that led to this design, but the most direct
+inspiration for the filtering syntax was
+OpenBSD's
+[`pf.conf(5)`](https://www.freebsd.org/cgi/man.cgi?query=pf.conf&apropos=0&sektion=0&arch=default&format=html#PARAMETERS) firewall
+syntax that lets you select the first IP address on a given named interface.
+The original problem stemmed from:
+
+* needing to create immutable images using [Packer](https://www.packer.io) that
+ ran the [Consul](https://www.consul.io) process (Consul can only use one IP
+ address at a time);
+* images that may or may not have multiple interfaces or IP addresses at
+ runtime; and
+* we didn't want to rely on configuration management to render out the correct
+ IP address if the VM image was being used in an auto-scaling group.
+
+Instead we needed some way to codify a heuristic that would correctly select the
+right IP address but the input parameters were not known when the image was
+created.
diff --git a/vendor/github.com/hashicorp/go-sockaddr/doc.go b/vendor/github.com/hashicorp/go-sockaddr/doc.go
new file mode 100644
index 00000000000..90671deb51d
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/doc.go
@@ -0,0 +1,5 @@
+/*
+Package sockaddr is a Go implementation of the UNIX socket family data types and
+related helper functions.
+*/
+package sockaddr
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go
new file mode 100644
index 00000000000..0811b275990
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go
@@ -0,0 +1,254 @@
+package sockaddr
+
+import "strings"
+
+// ifAddrAttrMap is a map of the IfAddr type-specific attributes.
+var ifAddrAttrMap map[AttrName]func(IfAddr) string
+var ifAddrAttrs []AttrName
+
+func init() {
+ ifAddrAttrInit()
+}
+
+// GetPrivateIP returns a string with a single IP address that is part of RFC
+// 6890 and has a default route. If the system can't determine its IP address
+// or find an RFC 6890 IP address, an empty string will be returned instead.
+// This function is the `eval` equivalent of:
+//
+// ```
+// $ sockaddr eval -r '{{GetPrivateInterfaces | attr "address"}}'
+/// ```
+func GetPrivateIP() (string, error) {
+ privateIfs, err := GetPrivateInterfaces()
+ if err != nil {
+ return "", err
+ }
+ if len(privateIfs) < 1 {
+ return "", nil
+ }
+
+ ifAddr := privateIfs[0]
+ ip := *ToIPAddr(ifAddr.SockAddr)
+ return ip.NetIP().String(), nil
+}
+
+// GetPrivateIPs returns a string with all IP addresses that are part of RFC
+// 6890 (regardless of whether or not there is a default route, unlike
+// GetPublicIP). If the system can't find any RFC 6890 IP addresses, an empty
+// string will be returned instead. This function is the `eval` equivalent of:
+//
+// ```
+// $ sockaddr eval -r '{{GetAllInterfaces | include "RFC" "6890" | join "address" " "}}'
+/// ```
+func GetPrivateIPs() (string, error) {
+ ifAddrs, err := GetAllInterfaces()
+ if err != nil {
+ return "", err
+ } else if len(ifAddrs) < 1 {
+ return "", nil
+ }
+
+ ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP)
+ if len(ifAddrs) == 0 {
+ return "", nil
+ }
+
+ OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs)
+
+ ifAddrs, _, err = IfByRFC("6890", ifAddrs)
+ if err != nil {
+ return "", err
+ } else if len(ifAddrs) == 0 {
+ return "", nil
+ }
+
+ _, ifAddrs, err = IfByRFC(ForwardingBlacklistRFC, ifAddrs)
+ if err != nil {
+ return "", err
+ } else if len(ifAddrs) == 0 {
+ return "", nil
+ }
+
+ ips := make([]string, 0, len(ifAddrs))
+ for _, ifAddr := range ifAddrs {
+ ip := *ToIPAddr(ifAddr.SockAddr)
+ s := ip.NetIP().String()
+ ips = append(ips, s)
+ }
+
+ return strings.Join(ips, " "), nil
+}
+
+// GetPublicIP returns a string with a single IP address that is NOT part of RFC
+// 6890 and has a default route. If the system can't determine its IP address
+// or find a non RFC 6890 IP address, an empty string will be returned instead.
+// This function is the `eval` equivalent of:
+//
+// ```
+// $ sockaddr eval -r '{{GetPublicInterfaces | attr "address"}}'
+/// ```
+func GetPublicIP() (string, error) {
+ publicIfs, err := GetPublicInterfaces()
+ if err != nil {
+ return "", err
+ } else if len(publicIfs) < 1 {
+ return "", nil
+ }
+
+ ifAddr := publicIfs[0]
+ ip := *ToIPAddr(ifAddr.SockAddr)
+ return ip.NetIP().String(), nil
+}
+
+// GetPublicIPs returns a string with all IP addresses that are NOT part of RFC
+// 6890 (regardless of whether or not there is a default route, unlike
+// GetPublicIP). If the system can't find any non RFC 6890 IP addresses, an
+// empty string will be returned instead. This function is the `eval`
+// equivalent of:
+//
+// ```
+// $ sockaddr eval -r '{{GetAllInterfaces | exclude "RFC" "6890" | join "address" " "}}'
+/// ```
+func GetPublicIPs() (string, error) {
+ ifAddrs, err := GetAllInterfaces()
+ if err != nil {
+ return "", err
+ } else if len(ifAddrs) < 1 {
+ return "", nil
+ }
+
+ ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP)
+ if len(ifAddrs) == 0 {
+ return "", nil
+ }
+
+ OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs)
+
+ _, ifAddrs, err = IfByRFC("6890", ifAddrs)
+ if err != nil {
+ return "", err
+ } else if len(ifAddrs) == 0 {
+ return "", nil
+ }
+
+ ips := make([]string, 0, len(ifAddrs))
+ for _, ifAddr := range ifAddrs {
+ ip := *ToIPAddr(ifAddr.SockAddr)
+ s := ip.NetIP().String()
+ ips = append(ips, s)
+ }
+
+ return strings.Join(ips, " "), nil
+}
+
+// GetInterfaceIP returns a string with a single IP address sorted by the size
+// of the network (i.e. IP addresses with a smaller netmask, larger network
+// size, are sorted first). This function is the `eval` equivalent of:
+//
+// ```
+// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <> | sort "type,size" | include "flag" "forwardable" | attr "address" }}'
+/// ```
+func GetInterfaceIP(namedIfRE string) (string, error) {
+ ifAddrs, err := GetAllInterfaces()
+ if err != nil {
+ return "", err
+ }
+
+ ifAddrs, _, err = IfByName(namedIfRE, ifAddrs)
+ if err != nil {
+ return "", err
+ }
+
+ ifAddrs, _, err = IfByFlag("forwardable", ifAddrs)
+ if err != nil {
+ return "", err
+ }
+
+ ifAddrs, err = SortIfBy("+type,+size", ifAddrs)
+ if err != nil {
+ return "", err
+ }
+
+ if len(ifAddrs) == 0 {
+ return "", err
+ }
+
+ ip := ToIPAddr(ifAddrs[0].SockAddr)
+ if ip == nil {
+ return "", err
+ }
+
+ return IPAddrAttr(*ip, "address"), nil
+}
+
+// GetInterfaceIPs returns a string with all IPs, sorted by the size of the
+// network (i.e. IP addresses with a smaller netmask, larger network size, are
+// sorted first), on a named interface. This function is the `eval` equivalent
+// of:
+//
+// ```
+// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <> | sort "type,size" | join "address" " "}}'
+/// ```
+func GetInterfaceIPs(namedIfRE string) (string, error) {
+ ifAddrs, err := GetAllInterfaces()
+ if err != nil {
+ return "", err
+ }
+
+ ifAddrs, _, err = IfByName(namedIfRE, ifAddrs)
+ if err != nil {
+ return "", err
+ }
+
+ ifAddrs, err = SortIfBy("+type,+size", ifAddrs)
+ if err != nil {
+ return "", err
+ }
+
+ if len(ifAddrs) == 0 {
+ return "", err
+ }
+
+ ips := make([]string, 0, len(ifAddrs))
+ for _, ifAddr := range ifAddrs {
+ ip := *ToIPAddr(ifAddr.SockAddr)
+ s := ip.NetIP().String()
+ ips = append(ips, s)
+ }
+
+ return strings.Join(ips, " "), nil
+}
+
+// IfAddrAttrs returns a list of attributes supported by the IfAddr type
+func IfAddrAttrs() []AttrName {
+ return ifAddrAttrs
+}
+
+// IfAddrAttr returns a string representation of an attribute for the given
+// IfAddr.
+func IfAddrAttr(ifAddr IfAddr, attrName AttrName) string {
+ fn, found := ifAddrAttrMap[attrName]
+ if !found {
+ return ""
+ }
+
+ return fn(ifAddr)
+}
+
+// ifAddrAttrInit is called once at init()
+func ifAddrAttrInit() {
+ // Sorted for human readability
+ ifAddrAttrs = []AttrName{
+ "flags",
+ "name",
+ }
+
+ ifAddrAttrMap = map[AttrName]func(ifAddr IfAddr) string{
+ "flags": func(ifAddr IfAddr) string {
+ return ifAddr.Interface.Flags.String()
+ },
+ "name": func(ifAddr IfAddr) string {
+ return ifAddr.Interface.Name
+ },
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
new file mode 100644
index 00000000000..d2713afbf7e
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
@@ -0,0 +1,1317 @@
+package sockaddr
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "math/big"
+ "net"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+var (
+ // Centralize all regexps and regexp.Copy() where necessary.
+ signRE *regexp.Regexp = regexp.MustCompile(`^[\s]*[+-]`)
+ whitespaceRE *regexp.Regexp = regexp.MustCompile(`[\s]+`)
+ // These regular expressions enable the deprecated parseDefaultIfNameWindows
+ // and should be removed when those functions are.
+ ifNameRE *regexp.Regexp = regexp.MustCompile(`^(?:Ethernet|Wireless LAN) adapter ([^:]+):`)
+ ipAddrRE *regexp.Regexp = regexp.MustCompile(`^ IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`)
+)
+
+// IfAddrs is a slice of IfAddr
+type IfAddrs []IfAddr
+
+func (ifs IfAddrs) Len() int { return len(ifs) }
+
+// CmpIfFunc is the function signature that must be met to be used in the
+// OrderedIfAddrBy multiIfAddrSorter
+type CmpIfAddrFunc func(p1, p2 *IfAddr) int
+
+// multiIfAddrSorter implements the Sort interface, sorting the IfAddrs within.
+type multiIfAddrSorter struct {
+ ifAddrs IfAddrs
+ cmp []CmpIfAddrFunc
+}
+
+// Sort sorts the argument slice according to the Cmp functions passed to
+// OrderedIfAddrBy.
+func (ms *multiIfAddrSorter) Sort(ifAddrs IfAddrs) {
+ ms.ifAddrs = ifAddrs
+ sort.Sort(ms)
+}
+
+// OrderedIfAddrBy sorts SockAddr by the list of sort function pointers.
+func OrderedIfAddrBy(cmpFuncs ...CmpIfAddrFunc) *multiIfAddrSorter {
+ return &multiIfAddrSorter{
+ cmp: cmpFuncs,
+ }
+}
+
+// Len is part of sort.Interface.
+func (ms *multiIfAddrSorter) Len() int {
+ return len(ms.ifAddrs)
+}
+
+// Less is part of sort.Interface. It is implemented by looping along the Cmp()
+// functions until it finds a comparison that is either less than or greater
+// than. A return value of 0 defers sorting to the next function in the
+// multisorter (which means the results of sorting may leave the resutls in a
+// non-deterministic order).
+func (ms *multiIfAddrSorter) Less(i, j int) bool {
+ p, q := &ms.ifAddrs[i], &ms.ifAddrs[j]
+ // Try all but the last comparison.
+ var k int
+ for k = 0; k < len(ms.cmp)-1; k++ {
+ cmp := ms.cmp[k]
+ x := cmp(p, q)
+ switch x {
+ case -1:
+ // p < q, so we have a decision.
+ return true
+ case 1:
+ // p > q, so we have a decision.
+ return false
+ }
+ // p == q; try the next comparison.
+ }
+ // All comparisons to here said "equal", so just return whatever the
+ // final comparison reports.
+ switch ms.cmp[k](p, q) {
+ case -1:
+ return true
+ case 1:
+ return false
+ default:
+ // Still a tie! Now what?
+ return false
+ panic("undefined sort order for remaining items in the list")
+ }
+}
+
+// Swap is part of sort.Interface.
+func (ms *multiIfAddrSorter) Swap(i, j int) {
+ ms.ifAddrs[i], ms.ifAddrs[j] = ms.ifAddrs[j], ms.ifAddrs[i]
+}
+
+// AscIfAddress is a sorting function to sort IfAddrs by their respective
+// address type. Non-equal types are deferred in the sort.
+func AscIfAddress(p1Ptr, p2Ptr *IfAddr) int {
+ return AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
+}
+
+// AscIfDefault is a sorting function to sort IfAddrs by whether or not they
+// have a default route or not. Non-equal types are deferred in the sort.
+//
+// FIXME: This is a particularly expensive sorting operation because of the
+// non-memoized calls to NewRouteInfo(). In an ideal world the routeInfo data
+// once at the start of the sort and pass it along as a context or by wrapping
+// the IfAddr type with this information (this would also solve the inability to
+// return errors and the possibility of failing silently). Fortunately,
+// N*log(N) where N = 3 is only ~6.2 invocations. Not ideal, but not worth
+// optimizing today. The common case is this gets called once or twice.
+// Patches welcome.
+func AscIfDefault(p1Ptr, p2Ptr *IfAddr) int {
+ ri, err := NewRouteInfo()
+ if err != nil {
+ return sortDeferDecision
+ }
+
+ defaultIfName, err := ri.GetDefaultInterfaceName()
+ if err != nil {
+ return sortDeferDecision
+ }
+
+ switch {
+ case p1Ptr.Interface.Name == defaultIfName && p2Ptr.Interface.Name == defaultIfName:
+ return sortDeferDecision
+ case p1Ptr.Interface.Name == defaultIfName:
+ return sortReceiverBeforeArg
+ case p2Ptr.Interface.Name == defaultIfName:
+ return sortArgBeforeReceiver
+ default:
+ return sortDeferDecision
+ }
+}
+
+// AscIfName is a sorting function to sort IfAddrs by their interface names.
+func AscIfName(p1Ptr, p2Ptr *IfAddr) int {
+ return strings.Compare(p1Ptr.Name, p2Ptr.Name)
+}
+
+// AscIfNetworkSize is a sorting function to sort IfAddrs by their respective
+// network mask size.
+func AscIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int {
+ return AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
+}
+
+// AscIfPort is a sorting function to sort IfAddrs by their respective
+// port type. Non-equal types are deferred in the sort.
+func AscIfPort(p1Ptr, p2Ptr *IfAddr) int {
+ return AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
+}
+
+// AscIfPrivate is a sorting function to sort IfAddrs by "private" values before
+// "public" values. Both IPv4 and IPv6 are compared against RFC6890 (RFC6890
+// includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and IPv6
+// includes RFC4193).
+func AscIfPrivate(p1Ptr, p2Ptr *IfAddr) int {
+ return AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
+}
+
+// AscIfType is a sorting function to sort IfAddrs by their respective address
+// type. Non-equal types are deferred in the sort.
+func AscIfType(p1Ptr, p2Ptr *IfAddr) int {
+ return AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
+}
+
+// DescIfAddress is identical to AscIfAddress but reverse ordered.
+func DescIfAddress(p1Ptr, p2Ptr *IfAddr) int {
+ return -1 * AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
+}
+
+// DescIfDefault is identical to AscIfDefault but reverse ordered.
+func DescIfDefault(p1Ptr, p2Ptr *IfAddr) int {
+ return -1 * AscIfDefault(p1Ptr, p2Ptr)
+}
+
+// DescIfName is identical to AscIfName but reverse ordered.
+func DescIfName(p1Ptr, p2Ptr *IfAddr) int {
+ return -1 * strings.Compare(p1Ptr.Name, p2Ptr.Name)
+}
+
+// DescIfNetworkSize is identical to AscIfNetworkSize but reverse ordered.
+func DescIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int {
+ return -1 * AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
+}
+
+// DescIfPort is identical to AscIfPort but reverse ordered.
+func DescIfPort(p1Ptr, p2Ptr *IfAddr) int {
+ return -1 * AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
+}
+
+// DescIfPrivate is identical to AscIfPrivate but reverse ordered.
+func DescIfPrivate(p1Ptr, p2Ptr *IfAddr) int {
+ return -1 * AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
+}
+
+// DescIfType is identical to AscIfType but reverse ordered.
+func DescIfType(p1Ptr, p2Ptr *IfAddr) int {
+ return -1 * AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
+}
+
+// FilterIfByType filters IfAddrs and returns a list of the matching type
+func FilterIfByType(ifAddrs IfAddrs, type_ SockAddrType) (matchedIfs, excludedIfs IfAddrs) {
+ excludedIfs = make(IfAddrs, 0, len(ifAddrs))
+ matchedIfs = make(IfAddrs, 0, len(ifAddrs))
+
+ for _, ifAddr := range ifAddrs {
+ if ifAddr.SockAddr.Type()&type_ != 0 {
+ matchedIfs = append(matchedIfs, ifAddr)
+ } else {
+ excludedIfs = append(excludedIfs, ifAddr)
+ }
+ }
+ return matchedIfs, excludedIfs
+}
+
+// IfAttr forwards the selector to IfAttr.Attr() for resolution. If there is
+// more than one IfAddr, only the first IfAddr is used.
+func IfAttr(selectorName string, ifAddr IfAddr) (string, error) {
+ attrName := AttrName(strings.ToLower(selectorName))
+ attrVal, err := ifAddr.Attr(attrName)
+ return attrVal, err
+}
+
+// IfAttrs forwards the selector to IfAttrs.Attr() for resolution. If there is
+// more than one IfAddr, only the first IfAddr is used.
+func IfAttrs(selectorName string, ifAddrs IfAddrs) (string, error) {
+ if len(ifAddrs) == 0 {
+ return "", nil
+ }
+
+ attrName := AttrName(strings.ToLower(selectorName))
+ attrVal, err := ifAddrs[0].Attr(attrName)
+ return attrVal, err
+}
+
+// GetAllInterfaces iterates over all available network interfaces and finds all
+// available IP addresses on each interface and converts them to
+// sockaddr.IPAddrs, and returning the result as an array of IfAddr.
+func GetAllInterfaces() (IfAddrs, error) {
+ ifs, err := net.Interfaces()
+ if err != nil {
+ return nil, err
+ }
+
+ ifAddrs := make(IfAddrs, 0, len(ifs))
+ for _, intf := range ifs {
+ addrs, err := intf.Addrs()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, addr := range addrs {
+ var ipAddr IPAddr
+ ipAddr, err = NewIPAddr(addr.String())
+ if err != nil {
+ return IfAddrs{}, fmt.Errorf("unable to create an IP address from %q", addr.String())
+ }
+
+ ifAddr := IfAddr{
+ SockAddr: ipAddr,
+ Interface: intf,
+ }
+ ifAddrs = append(ifAddrs, ifAddr)
+ }
+ }
+
+ return ifAddrs, nil
+}
+
+// GetDefaultInterfaces returns IfAddrs of the addresses attached to the default
+// route.
+func GetDefaultInterfaces() (IfAddrs, error) {
+ ri, err := NewRouteInfo()
+ if err != nil {
+ return nil, err
+ }
+
+ defaultIfName, err := ri.GetDefaultInterfaceName()
+ if err != nil {
+ return nil, err
+ }
+
+ var defaultIfs, ifAddrs IfAddrs
+ ifAddrs, err = GetAllInterfaces()
+ for _, ifAddr := range ifAddrs {
+ if ifAddr.Name == defaultIfName {
+ defaultIfs = append(defaultIfs, ifAddr)
+ }
+ }
+
+ return defaultIfs, nil
+}
+
+// GetPrivateInterfaces returns an IfAddrs that are part of RFC 6890 and have a
+// default route. If the system can't determine its IP address or find an RFC
+// 6890 IP address, an empty IfAddrs will be returned instead. This function is
+// the `eval` equivalent of:
+//
+// ```
+// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | include "RFC" "6890" }}'
+/// ```
+func GetPrivateInterfaces() (IfAddrs, error) {
+ privateIfs, err := GetAllInterfaces()
+ if err != nil {
+ return IfAddrs{}, err
+ }
+ if len(privateIfs) == 0 {
+ return IfAddrs{}, nil
+ }
+
+ privateIfs, _ = FilterIfByType(privateIfs, TypeIP)
+ if len(privateIfs) == 0 {
+ return IfAddrs{}, nil
+ }
+
+ privateIfs, _, err = IfByFlag("forwardable", privateIfs)
+ if err != nil {
+ return IfAddrs{}, err
+ }
+
+ privateIfs, _, err = IfByFlag("up", privateIfs)
+ if err != nil {
+ return IfAddrs{}, err
+ }
+
+ if len(privateIfs) == 0 {
+ return IfAddrs{}, nil
+ }
+
+ OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(privateIfs)
+
+ privateIfs, _, err = IfByRFC("6890", privateIfs)
+ if err != nil {
+ return IfAddrs{}, err
+ } else if len(privateIfs) == 0 {
+ return IfAddrs{}, nil
+ }
+
+ return privateIfs, nil
+}
+
+// GetPublicInterfaces returns an IfAddrs that are NOT part of RFC 6890 and has a
+// default route. If the system can't determine its IP address or find a non
+// RFC 6890 IP address, an empty IfAddrs will be returned instead. This
+// function is the `eval` equivalent of:
+//
+// ```
+// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | exclude "RFC" "6890" }}'
+/// ```
+func GetPublicInterfaces() (IfAddrs, error) {
+ publicIfs, err := GetAllInterfaces()
+ if err != nil {
+ return IfAddrs{}, err
+ }
+ if len(publicIfs) == 0 {
+ return IfAddrs{}, nil
+ }
+
+ publicIfs, _ = FilterIfByType(publicIfs, TypeIP)
+ if len(publicIfs) == 0 {
+ return IfAddrs{}, nil
+ }
+
+ publicIfs, _, err = IfByFlag("forwardable", publicIfs)
+ if err != nil {
+ return IfAddrs{}, err
+ }
+
+ publicIfs, _, err = IfByFlag("up", publicIfs)
+ if err != nil {
+ return IfAddrs{}, err
+ }
+
+ if len(publicIfs) == 0 {
+ return IfAddrs{}, nil
+ }
+
+ OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(publicIfs)
+
+ _, publicIfs, err = IfByRFC("6890", publicIfs)
+ if err != nil {
+ return IfAddrs{}, err
+ } else if len(publicIfs) == 0 {
+ return IfAddrs{}, nil
+ }
+
+ return publicIfs, nil
+}
+
+// IfByAddress returns a list of matched and non-matched IfAddrs, or an error if
+// the regexp fails to compile.
+func IfByAddress(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
+ re, err := regexp.Compile(inputRe)
+ if err != nil {
+ return nil, nil, fmt.Errorf("Unable to compile address regexp %+q: %v", inputRe, err)
+ }
+
+ matchedAddrs := make(IfAddrs, 0, len(ifAddrs))
+ excludedAddrs := make(IfAddrs, 0, len(ifAddrs))
+ for _, addr := range ifAddrs {
+ if re.MatchString(addr.SockAddr.String()) {
+ matchedAddrs = append(matchedAddrs, addr)
+ } else {
+ excludedAddrs = append(excludedAddrs, addr)
+ }
+ }
+
+ return matchedAddrs, excludedAddrs, nil
+}
+
+// IfByName returns a list of matched and non-matched IfAddrs, or an error if
+// the regexp fails to compile.
+func IfByName(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
+ re, err := regexp.Compile(inputRe)
+ if err != nil {
+ return nil, nil, fmt.Errorf("Unable to compile name regexp %+q: %v", inputRe, err)
+ }
+
+ matchedAddrs := make(IfAddrs, 0, len(ifAddrs))
+ excludedAddrs := make(IfAddrs, 0, len(ifAddrs))
+ for _, addr := range ifAddrs {
+ if re.MatchString(addr.Name) {
+ matchedAddrs = append(matchedAddrs, addr)
+ } else {
+ excludedAddrs = append(excludedAddrs, addr)
+ }
+ }
+
+ return matchedAddrs, excludedAddrs, nil
+}
+
+// IfByPort returns a list of matched and non-matched IfAddrs, or an error if
+// the regexp fails to compile.
+func IfByPort(inputRe string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) {
+ re, err := regexp.Compile(inputRe)
+ if err != nil {
+ return nil, nil, fmt.Errorf("Unable to compile port regexp %+q: %v", inputRe, err)
+ }
+
+ ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP)
+ matchedIfs = make(IfAddrs, 0, len(ipIfs))
+ excludedIfs = append(IfAddrs(nil), nonIfs...)
+ for _, addr := range ipIfs {
+ ipAddr := ToIPAddr(addr.SockAddr)
+ if ipAddr == nil {
+ continue
+ }
+
+ port := strconv.FormatInt(int64((*ipAddr).IPPort()), 10)
+ if re.MatchString(port) {
+ matchedIfs = append(matchedIfs, addr)
+ } else {
+ excludedIfs = append(excludedIfs, addr)
+ }
+ }
+
+ return matchedIfs, excludedIfs, nil
+}
+
+// IfByRFC returns a list of matched and non-matched IfAddrs that contain the
+// relevant RFC-specified traits.
+func IfByRFC(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
+ inputRFC, err := strconv.ParseUint(selectorParam, 10, 64)
+ if err != nil {
+ return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to parse RFC number %q: %v", selectorParam, err)
+ }
+
+ matchedIfAddrs := make(IfAddrs, 0, len(ifAddrs))
+ remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs))
+
+ rfcNetMap := KnownRFCs()
+ rfcNets, ok := rfcNetMap[uint(inputRFC)]
+ if !ok {
+ return nil, nil, fmt.Errorf("unsupported RFC %d", inputRFC)
+ }
+
+ for _, ifAddr := range ifAddrs {
+ var contained bool
+ for _, rfcNet := range rfcNets {
+ if rfcNet.Contains(ifAddr.SockAddr) {
+ matchedIfAddrs = append(matchedIfAddrs, ifAddr)
+ contained = true
+ break
+ }
+ }
+ if !contained {
+ remainingIfAddrs = append(remainingIfAddrs, ifAddr)
+ }
+ }
+
+ return matchedIfAddrs, remainingIfAddrs, nil
+}
+
+// IfByRFCs returns a list of matched and non-matched IfAddrs that contain the
+// relevant RFC-specified traits. Multiple RFCs can be specified and separated
+// by the `|` symbol. No protection is taken to ensure an IfAddr does not end
+// up in both the included and excluded list.
+func IfByRFCs(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
+ var includedIfs, excludedIfs IfAddrs
+ for _, rfcStr := range strings.Split(selectorParam, "|") {
+ includedRFCIfs, excludedRFCIfs, err := IfByRFC(rfcStr, ifAddrs)
+ if err != nil {
+ return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to lookup RFC number %q: %v", rfcStr, err)
+ }
+ includedIfs = append(includedIfs, includedRFCIfs...)
+ excludedIfs = append(excludedIfs, excludedRFCIfs...)
+ }
+
+ return includedIfs, excludedIfs, nil
+}
+
+// IfByMaskSize returns a list of matched and non-matched IfAddrs that have the
+// matching mask size.
+func IfByMaskSize(selectorParam string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) {
+ maskSize, err := strconv.ParseUint(selectorParam, 10, 64)
+ if err != nil {
+ return IfAddrs{}, IfAddrs{}, fmt.Errorf("invalid exclude size argument (%q): %v", selectorParam, err)
+ }
+
+ ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP)
+ matchedIfs = make(IfAddrs, 0, len(ipIfs))
+ excludedIfs = append(IfAddrs(nil), nonIfs...)
+ for _, addr := range ipIfs {
+ ipAddr := ToIPAddr(addr.SockAddr)
+ if ipAddr == nil {
+ return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to filter mask sizes on non-IP type %s: %v", addr.SockAddr.Type().String(), addr.SockAddr.String())
+ }
+
+ switch {
+ case (*ipAddr).Type()&TypeIPv4 != 0 && maskSize > 32:
+ return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv4 address: %d", maskSize)
+ case (*ipAddr).Type()&TypeIPv6 != 0 && maskSize > 128:
+ return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv6 address: %d", maskSize)
+ }
+
+ if (*ipAddr).Maskbits() == int(maskSize) {
+ matchedIfs = append(matchedIfs, addr)
+ } else {
+ excludedIfs = append(excludedIfs, addr)
+ }
+ }
+
+ return matchedIfs, excludedIfs, nil
+}
+
+// IfByType returns a list of matching and non-matching IfAddr that match the
+// specified type. For instance:
+//
+// include "type" "IPv4,IPv6"
+//
+// will include any IfAddrs that is either an IPv4 or IPv6 address. Any
+// addresses on those interfaces that don't match will be included in the
+// remainder results.
+func IfByType(inputTypes string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
+ matchingIfAddrs := make(IfAddrs, 0, len(ifAddrs))
+ remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs))
+
+ ifTypes := strings.Split(strings.ToLower(inputTypes), "|")
+ for _, ifType := range ifTypes {
+ switch ifType {
+ case "ip", "ipv4", "ipv6", "unix":
+ // Valid types
+ default:
+ return nil, nil, fmt.Errorf("unsupported type %q %q", ifType, inputTypes)
+ }
+ }
+
+ for _, ifAddr := range ifAddrs {
+ for _, ifType := range ifTypes {
+ var matched bool
+ switch {
+ case ifType == "ip" && ifAddr.SockAddr.Type()&TypeIP != 0:
+ matched = true
+ case ifType == "ipv4" && ifAddr.SockAddr.Type()&TypeIPv4 != 0:
+ matched = true
+ case ifType == "ipv6" && ifAddr.SockAddr.Type()&TypeIPv6 != 0:
+ matched = true
+ case ifType == "unix" && ifAddr.SockAddr.Type()&TypeUnix != 0:
+ matched = true
+ }
+
+ if matched {
+ matchingIfAddrs = append(matchingIfAddrs, ifAddr)
+ } else {
+ remainingIfAddrs = append(remainingIfAddrs, ifAddr)
+ }
+ }
+ }
+
+ return matchingIfAddrs, remainingIfAddrs, nil
+}
+
+// IfByFlag returns a list of matching and non-matching IfAddrs that match the
+// specified type. For instance:
+//
+// include "flag" "up,broadcast"
+//
+// will include any IfAddrs that have both the "up" and "broadcast" flags set.
+// Any addresses on those interfaces that don't match will be omitted from the
+// results.
+func IfByFlag(inputFlags string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
+ matchedAddrs := make(IfAddrs, 0, len(ifAddrs))
+ excludedAddrs := make(IfAddrs, 0, len(ifAddrs))
+
+ var wantForwardable,
+ wantGlobalUnicast,
+ wantInterfaceLocalMulticast,
+ wantLinkLocalMulticast,
+ wantLinkLocalUnicast,
+ wantLoopback,
+ wantMulticast,
+ wantUnspecified bool
+ var ifFlags net.Flags
+ var checkFlags, checkAttrs bool
+ for _, flagName := range strings.Split(strings.ToLower(inputFlags), "|") {
+ switch flagName {
+ case "broadcast":
+ checkFlags = true
+ ifFlags = ifFlags | net.FlagBroadcast
+ case "down":
+ checkFlags = true
+ ifFlags = (ifFlags &^ net.FlagUp)
+ case "forwardable":
+ checkAttrs = true
+ wantForwardable = true
+ case "global unicast":
+ checkAttrs = true
+ wantGlobalUnicast = true
+ case "interface-local multicast":
+ checkAttrs = true
+ wantInterfaceLocalMulticast = true
+ case "link-local multicast":
+ checkAttrs = true
+ wantLinkLocalMulticast = true
+ case "link-local unicast":
+ checkAttrs = true
+ wantLinkLocalUnicast = true
+ case "loopback":
+ checkAttrs = true
+ checkFlags = true
+ ifFlags = ifFlags | net.FlagLoopback
+ wantLoopback = true
+ case "multicast":
+ checkAttrs = true
+ checkFlags = true
+ ifFlags = ifFlags | net.FlagMulticast
+ wantMulticast = true
+ case "point-to-point":
+ checkFlags = true
+ ifFlags = ifFlags | net.FlagPointToPoint
+ case "unspecified":
+ checkAttrs = true
+ wantUnspecified = true
+ case "up":
+ checkFlags = true
+ ifFlags = ifFlags | net.FlagUp
+ default:
+ return nil, nil, fmt.Errorf("Unknown interface flag: %+q", flagName)
+ }
+ }
+
+ for _, ifAddr := range ifAddrs {
+ var matched bool
+ if checkFlags && ifAddr.Interface.Flags&ifFlags == ifFlags {
+ matched = true
+ }
+ if checkAttrs {
+ if ip := ToIPAddr(ifAddr.SockAddr); ip != nil {
+ netIP := (*ip).NetIP()
+ switch {
+ case wantGlobalUnicast && netIP.IsGlobalUnicast():
+ matched = true
+ case wantInterfaceLocalMulticast && netIP.IsInterfaceLocalMulticast():
+ matched = true
+ case wantLinkLocalMulticast && netIP.IsLinkLocalMulticast():
+ matched = true
+ case wantLinkLocalUnicast && netIP.IsLinkLocalUnicast():
+ matched = true
+ case wantLoopback && netIP.IsLoopback():
+ matched = true
+ case wantMulticast && netIP.IsMulticast():
+ matched = true
+ case wantUnspecified && netIP.IsUnspecified():
+ matched = true
+ case wantForwardable && !IsRFC(ForwardingBlacklist, ifAddr.SockAddr):
+ matched = true
+ }
+ }
+ }
+ if matched {
+ matchedAddrs = append(matchedAddrs, ifAddr)
+ } else {
+ excludedAddrs = append(excludedAddrs, ifAddr)
+ }
+ }
+ return matchedAddrs, excludedAddrs, nil
+}
+
+// IfByNetwork returns an IfAddrs that are equal to or included within the
+// network passed in by selector.
+func IfByNetwork(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, IfAddrs, error) {
+ var includedIfs, excludedIfs IfAddrs
+ for _, netStr := range strings.Split(selectorParam, "|") {
+ netAddr, err := NewIPAddr(netStr)
+ if err != nil {
+ return nil, nil, fmt.Errorf("unable to create an IP address from %+q: %v", netStr, err)
+ }
+
+ for _, ifAddr := range inputIfAddrs {
+ if netAddr.Contains(ifAddr.SockAddr) {
+ includedIfs = append(includedIfs, ifAddr)
+ } else {
+ excludedIfs = append(excludedIfs, ifAddr)
+ }
+ }
+ }
+
+ return includedIfs, excludedIfs, nil
+}
+
+// IfAddrMath will return a new IfAddr struct with a mutated value.
+func IfAddrMath(operation, value string, inputIfAddr IfAddr) (IfAddr, error) {
+ // Regexp used to enforce the sign being a required part of the grammar for
+ // some values.
+ signRe := signRE.Copy()
+
+ switch strings.ToLower(operation) {
+ case "address":
+ // "address" operates on the IP address and is allowed to overflow or
+ // underflow networks, however it will wrap along the underlying address's
+ // underlying type.
+
+ if !signRe.MatchString(value) {
+ return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation)
+ }
+
+ switch sockType := inputIfAddr.SockAddr.Type(); sockType {
+ case TypeIPv4:
+ // 33 == Accept any uint32 value
+ // TODO(seanc@): Add the ability to parse hex
+ i, err := strconv.ParseInt(value, 10, 33)
+ if err != nil {
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+ }
+
+ ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
+ ipv4Uint32 := uint32(ipv4.Address)
+ ipv4Uint32 += uint32(i)
+ return IfAddr{
+ SockAddr: IPv4Addr{
+ Address: IPv4Address(ipv4Uint32),
+ Mask: ipv4.Mask,
+ },
+ Interface: inputIfAddr.Interface,
+ }, nil
+ case TypeIPv6:
+ // 64 == Accept any int32 value
+ // TODO(seanc@): Add the ability to parse hex. Also parse a bignum int.
+ i, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+ }
+
+ ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
+ ipv6BigIntA := new(big.Int)
+ ipv6BigIntA.Set(ipv6.Address)
+ ipv6BigIntB := big.NewInt(i)
+
+ ipv6Addr := ipv6BigIntA.Add(ipv6BigIntA, ipv6BigIntB)
+ ipv6Addr.And(ipv6Addr, ipv6HostMask)
+
+ return IfAddr{
+ SockAddr: IPv6Addr{
+ Address: IPv6Address(ipv6Addr),
+ Mask: ipv6.Mask,
+ },
+ Interface: inputIfAddr.Interface,
+ }, nil
+ default:
+ return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
+ }
+ case "network":
+ // "network" operates on the network address. Positive values start at the
+ // network address and negative values wrap at the network address, which
+ // means a "-1" value on a network will be the broadcast address after
+ // wrapping is applied.
+
+ if !signRe.MatchString(value) {
+ return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation)
+ }
+
+ switch sockType := inputIfAddr.SockAddr.Type(); sockType {
+ case TypeIPv4:
+ // 33 == Accept any uint32 value
+ // TODO(seanc@): Add the ability to parse hex
+ i, err := strconv.ParseInt(value, 10, 33)
+ if err != nil {
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+ }
+
+ ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
+ ipv4Uint32 := uint32(ipv4.NetworkAddress())
+
+ // Wrap along network mask boundaries. EZ-mode wrapping made possible by
+ // use of int64 vs a uint.
+ var wrappedMask int64
+ if i >= 0 {
+ wrappedMask = i
+ } else {
+ wrappedMask = 1 + i + int64(^uint32(ipv4.Mask))
+ }
+
+ ipv4Uint32 = ipv4Uint32 + (uint32(wrappedMask) &^ uint32(ipv4.Mask))
+
+ return IfAddr{
+ SockAddr: IPv4Addr{
+ Address: IPv4Address(ipv4Uint32),
+ Mask: ipv4.Mask,
+ },
+ Interface: inputIfAddr.Interface,
+ }, nil
+ case TypeIPv6:
+ // 64 == Accept any int32 value
+ // TODO(seanc@): Add the ability to parse hex. Also parse a bignum int.
+ i, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+ }
+
+ ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
+ ipv6BigInt := new(big.Int)
+ ipv6BigInt.Set(ipv6.NetworkAddress())
+
+ mask := new(big.Int)
+ mask.Set(ipv6.Mask)
+ if i > 0 {
+ wrappedMask := new(big.Int)
+ wrappedMask.SetInt64(i)
+
+ wrappedMask.AndNot(wrappedMask, mask)
+ ipv6BigInt.Add(ipv6BigInt, wrappedMask)
+ } else {
+ // Mask off any bits that exceed the network size. Subtract the
+ // wrappedMask from the last usable - 1
+ wrappedMask := new(big.Int)
+ wrappedMask.SetInt64(-1 * i)
+ wrappedMask.Sub(wrappedMask, big.NewInt(1))
+
+ wrappedMask.AndNot(wrappedMask, mask)
+
+ lastUsable := new(big.Int)
+ lastUsable.Set(ipv6.LastUsable().(IPv6Addr).Address)
+
+ ipv6BigInt = lastUsable.Sub(lastUsable, wrappedMask)
+ }
+
+ return IfAddr{
+ SockAddr: IPv6Addr{
+ Address: IPv6Address(ipv6BigInt),
+ Mask: ipv6.Mask,
+ },
+ Interface: inputIfAddr.Interface,
+ }, nil
+ default:
+ return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
+ }
+ case "mask":
+ // "mask" operates on the IP address and returns the IP address on
+ // which the given integer mask has been applied. If the applied mask
+ // corresponds to a larger network than the mask of the IP address,
+ // the latter will be replaced by the former.
+ switch sockType := inputIfAddr.SockAddr.Type(); sockType {
+ case TypeIPv4:
+ i, err := strconv.ParseUint(value, 10, 32)
+ if err != nil {
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+ }
+
+ if i > 32 {
+ return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv4 addresses must be between 0 and 32", operation)
+ }
+
+ ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
+
+ ipv4Mask := net.CIDRMask(int(i), 32)
+ ipv4MaskUint32 := binary.BigEndian.Uint32(ipv4Mask)
+
+ maskedIpv4 := ipv4.NetIP().Mask(ipv4Mask)
+ maskedIpv4Uint32 := binary.BigEndian.Uint32(maskedIpv4)
+
+ maskedIpv4MaskUint32 := uint32(ipv4.Mask)
+
+ if ipv4MaskUint32 < maskedIpv4MaskUint32 {
+ maskedIpv4MaskUint32 = ipv4MaskUint32
+ }
+
+ return IfAddr{
+ SockAddr: IPv4Addr{
+ Address: IPv4Address(maskedIpv4Uint32),
+ Mask: IPv4Mask(maskedIpv4MaskUint32),
+ },
+ Interface: inputIfAddr.Interface,
+ }, nil
+ case TypeIPv6:
+ i, err := strconv.ParseUint(value, 10, 32)
+ if err != nil {
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+ }
+
+ if i > 128 {
+ return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv6 addresses must be between 0 and 64", operation)
+ }
+
+ ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
+
+ ipv6Mask := net.CIDRMask(int(i), 128)
+ ipv6MaskBigInt := new(big.Int)
+ ipv6MaskBigInt.SetBytes(ipv6Mask)
+
+ maskedIpv6 := ipv6.NetIP().Mask(ipv6Mask)
+ maskedIpv6BigInt := new(big.Int)
+ maskedIpv6BigInt.SetBytes(maskedIpv6)
+
+ maskedIpv6MaskBigInt := new(big.Int)
+ maskedIpv6MaskBigInt.Set(ipv6.Mask)
+
+ if ipv6MaskBigInt.Cmp(maskedIpv6MaskBigInt) == -1 {
+ maskedIpv6MaskBigInt = ipv6MaskBigInt
+ }
+
+ return IfAddr{
+ SockAddr: IPv6Addr{
+ Address: IPv6Address(maskedIpv6BigInt),
+ Mask: IPv6Mask(maskedIpv6MaskBigInt),
+ },
+ Interface: inputIfAddr.Interface,
+ }, nil
+ default:
+ return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
+ }
+ default:
+ return IfAddr{}, fmt.Errorf("unsupported math operation: %q", operation)
+ }
+}
+
+// IfAddrsMath will apply an IfAddrMath operation each IfAddr struct. Any
+// failure will result in zero results.
+func IfAddrsMath(operation, value string, inputIfAddrs IfAddrs) (IfAddrs, error) {
+ outputAddrs := make(IfAddrs, 0, len(inputIfAddrs))
+ for _, ifAddr := range inputIfAddrs {
+ result, err := IfAddrMath(operation, value, ifAddr)
+ if err != nil {
+ return IfAddrs{}, fmt.Errorf("unable to perform an IPMath operation on %s: %v", ifAddr, err)
+ }
+ outputAddrs = append(outputAddrs, result)
+ }
+ return outputAddrs, nil
+}
+
+// IncludeIfs returns an IfAddrs based on the passed in selector.
+func IncludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
+ var includedIfs IfAddrs
+ var err error
+
+ switch strings.ToLower(selectorName) {
+ case "address":
+ includedIfs, _, err = IfByAddress(selectorParam, inputIfAddrs)
+ case "flag", "flags":
+ includedIfs, _, err = IfByFlag(selectorParam, inputIfAddrs)
+ case "name":
+ includedIfs, _, err = IfByName(selectorParam, inputIfAddrs)
+ case "network":
+ includedIfs, _, err = IfByNetwork(selectorParam, inputIfAddrs)
+ case "port":
+ includedIfs, _, err = IfByPort(selectorParam, inputIfAddrs)
+ case "rfc", "rfcs":
+ includedIfs, _, err = IfByRFCs(selectorParam, inputIfAddrs)
+ case "size":
+ includedIfs, _, err = IfByMaskSize(selectorParam, inputIfAddrs)
+ case "type":
+ includedIfs, _, err = IfByType(selectorParam, inputIfAddrs)
+ default:
+ return IfAddrs{}, fmt.Errorf("invalid include selector %q", selectorName)
+ }
+
+ if err != nil {
+ return IfAddrs{}, err
+ }
+
+ return includedIfs, nil
+}
+
+// ExcludeIfs returns an IfAddrs based on the passed in selector.
+func ExcludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
+ var excludedIfs IfAddrs
+ var err error
+
+ switch strings.ToLower(selectorName) {
+ case "address":
+ _, excludedIfs, err = IfByAddress(selectorParam, inputIfAddrs)
+ case "flag", "flags":
+ _, excludedIfs, err = IfByFlag(selectorParam, inputIfAddrs)
+ case "name":
+ _, excludedIfs, err = IfByName(selectorParam, inputIfAddrs)
+ case "network":
+ _, excludedIfs, err = IfByNetwork(selectorParam, inputIfAddrs)
+ case "port":
+ _, excludedIfs, err = IfByPort(selectorParam, inputIfAddrs)
+ case "rfc", "rfcs":
+ _, excludedIfs, err = IfByRFCs(selectorParam, inputIfAddrs)
+ case "size":
+ _, excludedIfs, err = IfByMaskSize(selectorParam, inputIfAddrs)
+ case "type":
+ _, excludedIfs, err = IfByType(selectorParam, inputIfAddrs)
+ default:
+ return IfAddrs{}, fmt.Errorf("invalid exclude selector %q", selectorName)
+ }
+
+ if err != nil {
+ return IfAddrs{}, err
+ }
+
+ return excludedIfs, nil
+}
+
+// SortIfBy returns an IfAddrs sorted based on the passed in selector. Multiple
+// sort clauses can be passed in as a comma delimited list without whitespace.
+func SortIfBy(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
+ sortedIfs := append(IfAddrs(nil), inputIfAddrs...)
+
+ clauses := strings.Split(selectorParam, ",")
+ sortFuncs := make([]CmpIfAddrFunc, len(clauses))
+
+ for i, clause := range clauses {
+ switch strings.TrimSpace(strings.ToLower(clause)) {
+ case "+address", "address":
+ // The "address" selector returns an array of IfAddrs
+ // ordered by the network address. IfAddrs that are not
+ // comparable will be at the end of the list and in a
+ // non-deterministic order.
+ sortFuncs[i] = AscIfAddress
+ case "-address":
+ sortFuncs[i] = DescIfAddress
+ case "+default", "default":
+ sortFuncs[i] = AscIfDefault
+ case "-default":
+ sortFuncs[i] = DescIfDefault
+ case "+name", "name":
+ // The "name" selector returns an array of IfAddrs
+ // ordered by the interface name.
+ sortFuncs[i] = AscIfName
+ case "-name":
+ sortFuncs[i] = DescIfName
+ case "+port", "port":
+ // The "port" selector returns an array of IfAddrs
+ // ordered by the port, if included in the IfAddr.
+ // IfAddrs that are not comparable will be at the end of
+ // the list and in a non-deterministic order.
+ sortFuncs[i] = AscIfPort
+ case "-port":
+ sortFuncs[i] = DescIfPort
+ case "+private", "private":
+ // The "private" selector returns an array of IfAddrs
+ // ordered by private addresses first. IfAddrs that are
+ // not comparable will be at the end of the list and in
+ // a non-deterministic order.
+ sortFuncs[i] = AscIfPrivate
+ case "-private":
+ sortFuncs[i] = DescIfPrivate
+ case "+size", "size":
+ // The "size" selector returns an array of IfAddrs
+ // ordered by the size of the network mask, smaller mask
+ // (larger number of hosts per network) to largest
+ // (e.g. a /24 sorts before a /32).
+ sortFuncs[i] = AscIfNetworkSize
+ case "-size":
+ sortFuncs[i] = DescIfNetworkSize
+ case "+type", "type":
+ // The "type" selector returns an array of IfAddrs
+ // ordered by the type of the IfAddr. The sort order is
+ // Unix, IPv4, then IPv6.
+ sortFuncs[i] = AscIfType
+ case "-type":
+ sortFuncs[i] = DescIfType
+ default:
+ // Return an empty list for invalid sort types.
+ return IfAddrs{}, fmt.Errorf("unknown sort type: %q", clause)
+ }
+ }
+
+ OrderedIfAddrBy(sortFuncs...).Sort(sortedIfs)
+
+ return sortedIfs, nil
+}
+
+// UniqueIfAddrsBy creates a unique set of IfAddrs based on the matching
+// selector. UniqueIfAddrsBy assumes the input has already been sorted.
+func UniqueIfAddrsBy(selectorName string, inputIfAddrs IfAddrs) (IfAddrs, error) {
+ attrName := strings.ToLower(selectorName)
+
+ ifs := make(IfAddrs, 0, len(inputIfAddrs))
+ var lastMatch string
+ for _, ifAddr := range inputIfAddrs {
+ var out string
+ switch attrName {
+ case "address":
+ out = ifAddr.SockAddr.String()
+ case "name":
+ out = ifAddr.Name
+ default:
+ return nil, fmt.Errorf("unsupported unique constraint %+q", selectorName)
+ }
+
+ switch {
+ case lastMatch == "", lastMatch != out:
+ lastMatch = out
+ ifs = append(ifs, ifAddr)
+ case lastMatch == out:
+ continue
+ }
+ }
+
+ return ifs, nil
+}
+
+// JoinIfAddrs joins an IfAddrs and returns a string
+func JoinIfAddrs(selectorName string, joinStr string, inputIfAddrs IfAddrs) (string, error) {
+ outputs := make([]string, 0, len(inputIfAddrs))
+ attrName := AttrName(strings.ToLower(selectorName))
+
+ for _, ifAddr := range inputIfAddrs {
+ var attrVal string
+ var err error
+ attrVal, err = ifAddr.Attr(attrName)
+ if err != nil {
+ return "", err
+ }
+ outputs = append(outputs, attrVal)
+ }
+ return strings.Join(outputs, joinStr), nil
+}
+
+// LimitIfAddrs returns a slice of IfAddrs based on the specified limit.
+func LimitIfAddrs(lim uint, in IfAddrs) (IfAddrs, error) {
+ // Clamp the limit to the length of the array
+ if int(lim) > len(in) {
+ lim = uint(len(in))
+ }
+
+ return in[0:lim], nil
+}
+
+// OffsetIfAddrs returns a slice of IfAddrs based on the specified offset.
+func OffsetIfAddrs(off int, in IfAddrs) (IfAddrs, error) {
+ var end bool
+ if off < 0 {
+ end = true
+ off = off * -1
+ }
+
+ if off > len(in) {
+ return IfAddrs{}, fmt.Errorf("unable to seek past the end of the interface array: offset (%d) exceeds the number of interfaces (%d)", off, len(in))
+ }
+
+ if end {
+ return in[len(in)-off:], nil
+ }
+ return in[off:], nil
+}
+
+func (ifAddr IfAddr) String() string {
+ return fmt.Sprintf("%s %v", ifAddr.SockAddr, ifAddr.Interface)
+}
+
+// parseDefaultIfNameFromRoute parses standard route(8)'s output for the *BSDs
+// and Solaris.
+func parseDefaultIfNameFromRoute(routeOut string) (string, error) {
+ lines := strings.Split(routeOut, "\n")
+ for _, line := range lines {
+ kvs := strings.SplitN(line, ":", 2)
+ if len(kvs) != 2 {
+ continue
+ }
+
+ if strings.TrimSpace(kvs[0]) == "interface" {
+ ifName := strings.TrimSpace(kvs[1])
+ return ifName, nil
+ }
+ }
+
+ return "", errors.New("No default interface found")
+}
+
+// parseDefaultIfNameFromIPCmd parses the default interface from ip(8) for
+// Linux.
+func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) {
+ parsedLines := parseIfNameFromIPCmd(routeOut)
+ for _, parsedLine := range parsedLines {
+ if parsedLine[0] == "default" &&
+ parsedLine[1] == "via" &&
+ parsedLine[3] == "dev" {
+ ifName := strings.TrimSpace(parsedLine[4])
+ return ifName, nil
+ }
+ }
+
+ return "", errors.New("No default interface found")
+}
+
+// parseDefaultIfNameFromIPCmdAndroid parses the default interface from ip(8) for
+// Android.
+func parseDefaultIfNameFromIPCmdAndroid(routeOut string) (string, error) {
+ parsedLines := parseIfNameFromIPCmd(routeOut)
+ if len(parsedLines) > 0 {
+ ifName := strings.TrimSpace(parsedLines[0][4])
+ return ifName, nil
+ }
+
+ return "", errors.New("No default interface found")
+}
+
+// parseIfNameFromIPCmd parses interfaces from ip(8) for
+// Linux.
+func parseIfNameFromIPCmd(routeOut string) [][]string {
+ lines := strings.Split(routeOut, "\n")
+ re := whitespaceRE.Copy()
+ parsedLines := make([][]string, 0, len(lines))
+ for _, line := range lines {
+ kvs := re.Split(line, -1)
+ if len(kvs) < 5 {
+ continue
+ }
+ parsedLines = append(parsedLines, kvs)
+ }
+ return parsedLines
+}
+
+// parseDefaultIfNameWindows parses the default interface from `netstat -rn` and
+// `ipconfig` on Windows.
+//
+// This has been deprecated in favor of a Powershell-based solution because of
+// issues with localized Windows versions, but is currently retained for backward
+// compatibility
+func parseDefaultIfNameWindows(routeOut, ipconfigOut string) (string, error) {
+ defaultIPAddr, err := parseDefaultIPAddrWindowsRoute(routeOut)
+ if err != nil {
+ return "", err
+ }
+
+ ifName, err := parseDefaultIfNameWindowsIPConfig(defaultIPAddr, ipconfigOut)
+ if err != nil {
+ return "", err
+ }
+
+ return ifName, nil
+}
+
+// parseDefaultIPAddrWindowsRoute parses the IP address on the default interface
+// `netstat -rn`.
+//
+// NOTES(sean): Only IPv4 addresses are parsed at this time. If you have an
+// IPv6 connected host, submit an issue on github.com/hashicorp/go-sockaddr with
+// the output from `netstat -rn`, `ipconfig`, and version of Windows to see IPv6
+// support added.
+//
+// This has been deprecated in favor of a Powershell-based solution because of
+// issues with localized Windows versions, but is currently retained for backward
+// compatibility.
+func parseDefaultIPAddrWindowsRoute(routeOut string) (string, error) {
+ lines := strings.Split(routeOut, "\n")
+ re := whitespaceRE.Copy()
+ for _, line := range lines {
+ kvs := re.Split(strings.TrimSpace(line), -1)
+ if len(kvs) < 3 {
+ continue
+ }
+
+ if kvs[0] == "0.0.0.0" && kvs[1] == "0.0.0.0" {
+ defaultIPAddr := strings.TrimSpace(kvs[3])
+ return defaultIPAddr, nil
+ }
+ }
+
+ return "", errors.New("No IP on default interface found")
+}
+
+// parseDefaultIfNameWindowsIPConfig parses the output of `ipconfig` to find the
+// interface name forwarding traffic to the default gateway.
+//
+// This has been deprecated in favor of a Powershell-based solution because of
+// issues with localized Windows versions, but is currently retained for backward
+// compatibility
+func parseDefaultIfNameWindowsIPConfig(defaultIPAddr, routeOut string) (string, error) {
+ lines := strings.Split(routeOut, "\n")
+ ifNameRe := ifNameRE.Copy()
+ ipAddrRe := ipAddrRE.Copy()
+ var ifName string
+ for _, line := range lines {
+ switch ifNameMatches := ifNameRe.FindStringSubmatch(line); {
+ case len(ifNameMatches) > 1:
+ ifName = ifNameMatches[1]
+ continue
+ }
+
+ switch ipAddrMatches := ipAddrRe.FindStringSubmatch(line); {
+ case len(ipAddrMatches) > 1 && ipAddrMatches[1] == defaultIPAddr:
+ return ifName, nil
+ }
+ }
+
+ return "", errors.New("No default interface found with matching IP")
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifattr.go b/vendor/github.com/hashicorp/go-sockaddr/ifattr.go
new file mode 100644
index 00000000000..6984cb4a354
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/ifattr.go
@@ -0,0 +1,65 @@
+package sockaddr
+
+import (
+ "fmt"
+ "net"
+)
+
+// IfAddr is a union of a SockAddr and a net.Interface.
+type IfAddr struct {
+ SockAddr
+ net.Interface
+}
+
+// Attr returns the named attribute as a string
+func (ifAddr IfAddr) Attr(attrName AttrName) (string, error) {
+ val := IfAddrAttr(ifAddr, attrName)
+ if val != "" {
+ return val, nil
+ }
+
+ return Attr(ifAddr.SockAddr, attrName)
+}
+
+// Attr returns the named attribute as a string
+func Attr(sa SockAddr, attrName AttrName) (string, error) {
+ switch sockType := sa.Type(); {
+ case sockType&TypeIP != 0:
+ ip := *ToIPAddr(sa)
+ attrVal := IPAddrAttr(ip, attrName)
+ if attrVal != "" {
+ return attrVal, nil
+ }
+
+ if sockType == TypeIPv4 {
+ ipv4 := *ToIPv4Addr(sa)
+ attrVal := IPv4AddrAttr(ipv4, attrName)
+ if attrVal != "" {
+ return attrVal, nil
+ }
+ } else if sockType == TypeIPv6 {
+ ipv6 := *ToIPv6Addr(sa)
+ attrVal := IPv6AddrAttr(ipv6, attrName)
+ if attrVal != "" {
+ return attrVal, nil
+ }
+ }
+
+ case sockType == TypeUnix:
+ us := *ToUnixSock(sa)
+ attrVal := UnixSockAttr(us, attrName)
+ if attrVal != "" {
+ return attrVal, nil
+ }
+ }
+
+ // Non type-specific attributes
+ switch attrName {
+ case "string":
+ return sa.String(), nil
+ case "type":
+ return sa.Type().String(), nil
+ }
+
+ return "", fmt.Errorf("unsupported attribute name %q", attrName)
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ipaddr.go b/vendor/github.com/hashicorp/go-sockaddr/ipaddr.go
new file mode 100644
index 00000000000..b47d15c2016
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/ipaddr.go
@@ -0,0 +1,169 @@
+package sockaddr
+
+import (
+ "fmt"
+ "math/big"
+ "net"
+ "strings"
+)
+
+// Constants for the sizes of IPv3, IPv4, and IPv6 address types.
+const (
+ IPv3len = 6
+ IPv4len = 4
+ IPv6len = 16
+)
+
+// IPAddr is a generic IP address interface for IPv4 and IPv6 addresses,
+// networks, and socket endpoints.
+type IPAddr interface {
+ SockAddr
+ AddressBinString() string
+ AddressHexString() string
+ Cmp(SockAddr) int
+ CmpAddress(SockAddr) int
+ CmpPort(SockAddr) int
+ FirstUsable() IPAddr
+ Host() IPAddr
+ IPPort() IPPort
+ LastUsable() IPAddr
+ Maskbits() int
+ NetIP() *net.IP
+ NetIPMask() *net.IPMask
+ NetIPNet() *net.IPNet
+ Network() IPAddr
+ Octets() []int
+}
+
+// IPPort is the type for an IP port number for the TCP and UDP IP transports.
+type IPPort uint16
+
+// IPPrefixLen is a typed integer representing the prefix length for a given
+// IPAddr.
+type IPPrefixLen byte
+
+// ipAddrAttrMap is a map of the IPAddr type-specific attributes.
+var ipAddrAttrMap map[AttrName]func(IPAddr) string
+var ipAddrAttrs []AttrName
+
+func init() {
+ ipAddrInit()
+}
+
+// NewIPAddr creates a new IPAddr from a string. Returns nil if the string is
+// not an IPv4 or an IPv6 address.
+func NewIPAddr(addr string) (IPAddr, error) {
+ ipv4Addr, err := NewIPv4Addr(addr)
+ if err == nil {
+ return ipv4Addr, nil
+ }
+
+ ipv6Addr, err := NewIPv6Addr(addr)
+ if err == nil {
+ return ipv6Addr, nil
+ }
+
+ return nil, fmt.Errorf("invalid IPAddr %v", addr)
+}
+
+// IPAddrAttr returns a string representation of an attribute for the given
+// IPAddr.
+func IPAddrAttr(ip IPAddr, selector AttrName) string {
+ fn, found := ipAddrAttrMap[selector]
+ if !found {
+ return ""
+ }
+
+ return fn(ip)
+}
+
+// IPAttrs returns a list of attributes supported by the IPAddr type
+func IPAttrs() []AttrName {
+ return ipAddrAttrs
+}
+
+// MustIPAddr is a helper method that must return an IPAddr or panic on invalid
+// input.
+func MustIPAddr(addr string) IPAddr {
+ ip, err := NewIPAddr(addr)
+ if err != nil {
+ panic(fmt.Sprintf("Unable to create an IPAddr from %+q: %v", addr, err))
+ }
+ return ip
+}
+
+// ipAddrInit is called once at init()
+func ipAddrInit() {
+ // Sorted for human readability
+ ipAddrAttrs = []AttrName{
+ "host",
+ "address",
+ "port",
+ "netmask",
+ "network",
+ "mask_bits",
+ "binary",
+ "hex",
+ "first_usable",
+ "last_usable",
+ "octets",
+ }
+
+ ipAddrAttrMap = map[AttrName]func(ip IPAddr) string{
+ "address": func(ip IPAddr) string {
+ return ip.NetIP().String()
+ },
+ "binary": func(ip IPAddr) string {
+ return ip.AddressBinString()
+ },
+ "first_usable": func(ip IPAddr) string {
+ return ip.FirstUsable().String()
+ },
+ "hex": func(ip IPAddr) string {
+ return ip.AddressHexString()
+ },
+ "host": func(ip IPAddr) string {
+ return ip.Host().String()
+ },
+ "last_usable": func(ip IPAddr) string {
+ return ip.LastUsable().String()
+ },
+ "mask_bits": func(ip IPAddr) string {
+ return fmt.Sprintf("%d", ip.Maskbits())
+ },
+ "netmask": func(ip IPAddr) string {
+ switch v := ip.(type) {
+ case IPv4Addr:
+ ipv4Mask := IPv4Addr{
+ Address: IPv4Address(v.Mask),
+ Mask: IPv4HostMask,
+ }
+ return ipv4Mask.String()
+ case IPv6Addr:
+ ipv6Mask := new(big.Int)
+ ipv6Mask.Set(v.Mask)
+ ipv6MaskAddr := IPv6Addr{
+ Address: IPv6Address(ipv6Mask),
+ Mask: ipv6HostMask,
+ }
+ return ipv6MaskAddr.String()
+ default:
+ return fmt.Sprintf("", ip)
+ }
+ },
+ "network": func(ip IPAddr) string {
+ return ip.Network().NetIP().String()
+ },
+ "octets": func(ip IPAddr) string {
+ octets := ip.Octets()
+ octetStrs := make([]string, 0, len(octets))
+ for _, octet := range octets {
+ octetStrs = append(octetStrs, fmt.Sprintf("%d", octet))
+ }
+ return strings.Join(octetStrs, " ")
+ },
+ "port": func(ip IPAddr) string {
+ return fmt.Sprintf("%d", ip.IPPort())
+ },
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ipaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/ipaddrs.go
new file mode 100644
index 00000000000..6eeb7ddd2f1
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/ipaddrs.go
@@ -0,0 +1,98 @@
+package sockaddr
+
+import "bytes"
+
+type IPAddrs []IPAddr
+
+func (s IPAddrs) Len() int { return len(s) }
+func (s IPAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// // SortIPAddrsByCmp is a type that satisfies sort.Interface and can be used
+// // by the routines in this package. The SortIPAddrsByCmp type is used to
+// // sort IPAddrs by Cmp()
+// type SortIPAddrsByCmp struct{ IPAddrs }
+
+// // Less reports whether the element with index i should sort before the
+// // element with index j.
+// func (s SortIPAddrsByCmp) Less(i, j int) bool {
+// // Sort by Type, then address, then port number.
+// return Less(s.IPAddrs[i], s.IPAddrs[j])
+// }
+
+// SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and
+// can be used by the routines in this package. The
+// SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest
+// network (most specific to largest network).
+type SortIPAddrsByNetworkSize struct{ IPAddrs }
+
+// Less reports whether the element with index i should sort before the
+// element with index j.
+func (s SortIPAddrsByNetworkSize) Less(i, j int) bool {
+ // Sort masks with a larger binary value (i.e. fewer hosts per network
+ // prefix) after masks with a smaller value (larger number of hosts per
+ // prefix).
+ switch bytes.Compare([]byte(*s.IPAddrs[i].NetIPMask()), []byte(*s.IPAddrs[j].NetIPMask())) {
+ case 0:
+ // Fall through to the second test if the net.IPMasks are the
+ // same.
+ break
+ case 1:
+ return true
+ case -1:
+ return false
+ default:
+ panic("bad, m'kay?")
+ }
+
+ // Sort IPs based on the length (i.e. prefer IPv4 over IPv6).
+ iLen := len(*s.IPAddrs[i].NetIP())
+ jLen := len(*s.IPAddrs[j].NetIP())
+ if iLen != jLen {
+ return iLen > jLen
+ }
+
+ // Sort IPs based on their network address from lowest to highest.
+ switch bytes.Compare(s.IPAddrs[i].NetIPNet().IP, s.IPAddrs[j].NetIPNet().IP) {
+ case 0:
+ break
+ case 1:
+ return false
+ case -1:
+ return true
+ default:
+ panic("lol wut?")
+ }
+
+ // If a host does not have a port set, it always sorts after hosts
+ // that have a port (e.g. a host with a /32 and port number is more
+ // specific and should sort first over a host with a /32 but no port
+ // set).
+ if s.IPAddrs[i].IPPort() == 0 || s.IPAddrs[j].IPPort() == 0 {
+ return false
+ }
+ return s.IPAddrs[i].IPPort() < s.IPAddrs[j].IPPort()
+}
+
+// SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and
+// can be used by the routines in this package. The
+// SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest
+// network (most specific to largest network).
+type SortIPAddrsBySpecificMaskLen struct{ IPAddrs }
+
+// Less reports whether the element with index i should sort before the
+// element with index j.
+func (s SortIPAddrsBySpecificMaskLen) Less(i, j int) bool {
+ return s.IPAddrs[i].Maskbits() > s.IPAddrs[j].Maskbits()
+}
+
+// SortIPAddrsByBroadMaskLen is a type that satisfies sort.Interface and can
+// be used by the routines in this package. The SortIPAddrsByBroadMaskLen
+// type is used to sort IPAddrs by largest network (i.e. largest subnets
+// first).
+type SortIPAddrsByBroadMaskLen struct{ IPAddrs }
+
+// Less reports whether the element with index i should sort before the
+// element with index j.
+func (s SortIPAddrsByBroadMaskLen) Less(i, j int) bool {
+ return s.IPAddrs[i].Maskbits() < s.IPAddrs[j].Maskbits()
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go b/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go
new file mode 100644
index 00000000000..4d395dc954b
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go
@@ -0,0 +1,516 @@
+package sockaddr
+
+import (
+ "encoding/binary"
+ "fmt"
+ "net"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+type (
+ // IPv4Address is a named type representing an IPv4 address.
+ IPv4Address uint32
+
+ // IPv4Network is a named type representing an IPv4 network.
+ IPv4Network uint32
+
+ // IPv4Mask is a named type representing an IPv4 network mask.
+ IPv4Mask uint32
+)
+
+// IPv4HostMask is a constant represents a /32 IPv4 Address
+// (i.e. 255.255.255.255).
+const IPv4HostMask = IPv4Mask(0xffffffff)
+
+// ipv4AddrAttrMap is a map of the IPv4Addr type-specific attributes.
+var ipv4AddrAttrMap map[AttrName]func(IPv4Addr) string
+var ipv4AddrAttrs []AttrName
+var trailingHexNetmaskRE *regexp.Regexp
+
+// IPv4Addr implements a convenience wrapper around the union of Go's
+// built-in net.IP and net.IPNet types. In UNIX-speak, IPv4Addr implements
+// `sockaddr` when the the address family is set to AF_INET
+// (i.e. `sockaddr_in`).
+type IPv4Addr struct {
+ IPAddr
+ Address IPv4Address
+ Mask IPv4Mask
+ Port IPPort
+}
+
+func init() {
+ ipv4AddrInit()
+ trailingHexNetmaskRE = regexp.MustCompile(`/([0f]{8})$`)
+}
+
+// NewIPv4Addr creates an IPv4Addr from a string. String can be in the form
+// of either an IPv4:port (e.g. `1.2.3.4:80`, in which case the mask is
+// assumed to be a `/32`), an IPv4 address (e.g. `1.2.3.4`, also with a `/32`
+// mask), or an IPv4 CIDR (e.g. `1.2.3.4/24`, which has its IP port
+// initialized to zero). ipv4Str can not be a hostname.
+//
+// NOTE: Many net.*() routines will initialize and return an IPv6 address.
+// To create uint32 values from net.IP, always test to make sure the address
+// returned can be converted to a 4 byte array using To4().
+func NewIPv4Addr(ipv4Str string) (IPv4Addr, error) {
+ // Strip off any bogus hex-encoded netmasks that will be mis-parsed by Go. In
+ // particular, clients with the Barracuda VPN client will see something like:
+ // `192.168.3.51/00ffffff` as their IP address.
+ trailingHexNetmaskRe := trailingHexNetmaskRE.Copy()
+ if match := trailingHexNetmaskRe.FindStringIndex(ipv4Str); match != nil {
+ ipv4Str = ipv4Str[:match[0]]
+ }
+
+ // Parse as an IPv4 CIDR
+ ipAddr, network, err := net.ParseCIDR(ipv4Str)
+ if err == nil {
+ ipv4 := ipAddr.To4()
+ if ipv4 == nil {
+ return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address", ipv4Str)
+ }
+
+ // If we see an IPv6 netmask, convert it to an IPv4 mask.
+ netmaskSepPos := strings.LastIndexByte(ipv4Str, '/')
+ if netmaskSepPos != -1 && netmaskSepPos+1 < len(ipv4Str) {
+ netMask, err := strconv.ParseUint(ipv4Str[netmaskSepPos+1:], 10, 8)
+ if err != nil {
+ return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: unable to parse CIDR netmask: %v", ipv4Str, err)
+ } else if netMask > 128 {
+ return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: invalid CIDR netmask", ipv4Str)
+ }
+
+ if netMask >= 96 {
+ // Convert the IPv6 netmask to an IPv4 netmask
+ network.Mask = net.CIDRMask(int(netMask-96), IPv4len*8)
+ }
+ }
+ ipv4Addr := IPv4Addr{
+ Address: IPv4Address(binary.BigEndian.Uint32(ipv4)),
+ Mask: IPv4Mask(binary.BigEndian.Uint32(network.Mask)),
+ }
+ return ipv4Addr, nil
+ }
+
+ // Attempt to parse ipv4Str as a /32 host with a port number.
+ tcpAddr, err := net.ResolveTCPAddr("tcp4", ipv4Str)
+ if err == nil {
+ ipv4 := tcpAddr.IP.To4()
+ if ipv4 == nil {
+ return IPv4Addr{}, fmt.Errorf("Unable to resolve %+q as an IPv4 address", ipv4Str)
+ }
+
+ ipv4Uint32 := binary.BigEndian.Uint32(ipv4)
+ ipv4Addr := IPv4Addr{
+ Address: IPv4Address(ipv4Uint32),
+ Mask: IPv4HostMask,
+ Port: IPPort(tcpAddr.Port),
+ }
+
+ return ipv4Addr, nil
+ }
+
+ // Parse as a naked IPv4 address
+ ip := net.ParseIP(ipv4Str)
+ if ip != nil {
+ ipv4 := ip.To4()
+ if ipv4 == nil {
+ return IPv4Addr{}, fmt.Errorf("Unable to string convert %+q to an IPv4 address", ipv4Str)
+ }
+
+ ipv4Uint32 := binary.BigEndian.Uint32(ipv4)
+ ipv4Addr := IPv4Addr{
+ Address: IPv4Address(ipv4Uint32),
+ Mask: IPv4HostMask,
+ }
+ return ipv4Addr, nil
+ }
+
+ return IPv4Addr{}, fmt.Errorf("Unable to parse %+q to an IPv4 address: %v", ipv4Str, err)
+}
+
+// AddressBinString returns a string with the IPv4Addr's Address represented
+// as a sequence of '0' and '1' characters. This method is useful for
+// debugging or by operators who want to inspect an address.
+func (ipv4 IPv4Addr) AddressBinString() string {
+ return fmt.Sprintf("%032s", strconv.FormatUint(uint64(ipv4.Address), 2))
+}
+
+// AddressHexString returns a string with the IPv4Addr address represented as
+// a sequence of hex characters. This method is useful for debugging or by
+// operators who want to inspect an address.
+func (ipv4 IPv4Addr) AddressHexString() string {
+ return fmt.Sprintf("%08s", strconv.FormatUint(uint64(ipv4.Address), 16))
+}
+
+// Broadcast is an IPv4Addr-only method that returns the broadcast address of
+// the network.
+//
+// NOTE: IPv6 only supports multicast, so this method only exists for
+// IPv4Addr.
+func (ipv4 IPv4Addr) Broadcast() IPAddr {
+ // Nothing should listen on a broadcast address.
+ return IPv4Addr{
+ Address: IPv4Address(ipv4.BroadcastAddress()),
+ Mask: IPv4HostMask,
+ }
+}
+
+// BroadcastAddress returns a IPv4Network of the IPv4Addr's broadcast
+// address.
+func (ipv4 IPv4Addr) BroadcastAddress() IPv4Network {
+ return IPv4Network(uint32(ipv4.Address)&uint32(ipv4.Mask) | ^uint32(ipv4.Mask))
+}
+
+// CmpAddress follows the Cmp() standard protocol and returns:
+//
+// - -1 If the receiver should sort first because its address is lower than arg
+// - 0 if the SockAddr arg is equal to the receiving IPv4Addr or the argument is
+// of a different type.
+// - 1 If the argument should sort first.
+func (ipv4 IPv4Addr) CmpAddress(sa SockAddr) int {
+ ipv4b, ok := sa.(IPv4Addr)
+ if !ok {
+ return sortDeferDecision
+ }
+
+ switch {
+ case ipv4.Address == ipv4b.Address:
+ return sortDeferDecision
+ case ipv4.Address < ipv4b.Address:
+ return sortReceiverBeforeArg
+ default:
+ return sortArgBeforeReceiver
+ }
+}
+
+// CmpPort follows the Cmp() standard protocol and returns:
+//
+// - -1 If the receiver should sort first because its port is lower than arg
+// - 0 if the SockAddr arg's port number is equal to the receiving IPv4Addr,
+// regardless of type.
+// - 1 If the argument should sort first.
+func (ipv4 IPv4Addr) CmpPort(sa SockAddr) int {
+ var saPort IPPort
+ switch v := sa.(type) {
+ case IPv4Addr:
+ saPort = v.Port
+ case IPv6Addr:
+ saPort = v.Port
+ default:
+ return sortDeferDecision
+ }
+
+ switch {
+ case ipv4.Port == saPort:
+ return sortDeferDecision
+ case ipv4.Port < saPort:
+ return sortReceiverBeforeArg
+ default:
+ return sortArgBeforeReceiver
+ }
+}
+
+// CmpRFC follows the Cmp() standard protocol and returns:
+//
+// - -1 If the receiver should sort first because it belongs to the RFC and its
+// arg does not
+// - 0 if the receiver and arg both belong to the same RFC or neither do.
+// - 1 If the arg belongs to the RFC but receiver does not.
+func (ipv4 IPv4Addr) CmpRFC(rfcNum uint, sa SockAddr) int {
+ recvInRFC := IsRFC(rfcNum, ipv4)
+ ipv4b, ok := sa.(IPv4Addr)
+ if !ok {
+ // If the receiver is part of the desired RFC and the SockAddr
+ // argument is not, return -1 so that the receiver sorts before
+ // the non-IPv4 SockAddr. Conversely, if the receiver is not
+ // part of the RFC, punt on sorting and leave it for the next
+ // sorter.
+ if recvInRFC {
+ return sortReceiverBeforeArg
+ } else {
+ return sortDeferDecision
+ }
+ }
+
+ argInRFC := IsRFC(rfcNum, ipv4b)
+ switch {
+ case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC):
+ // If a and b both belong to the RFC, or neither belong to
+ // rfcNum, defer sorting to the next sorter.
+ return sortDeferDecision
+ case recvInRFC && !argInRFC:
+ return sortReceiverBeforeArg
+ default:
+ return sortArgBeforeReceiver
+ }
+}
+
+// Contains returns true if the SockAddr is contained within the receiver.
+func (ipv4 IPv4Addr) Contains(sa SockAddr) bool {
+ ipv4b, ok := sa.(IPv4Addr)
+ if !ok {
+ return false
+ }
+
+ return ipv4.ContainsNetwork(ipv4b)
+}
+
+// ContainsAddress returns true if the IPv4Address is contained within the
+// receiver.
+func (ipv4 IPv4Addr) ContainsAddress(x IPv4Address) bool {
+ return IPv4Address(ipv4.NetworkAddress()) <= x &&
+ IPv4Address(ipv4.BroadcastAddress()) >= x
+}
+
+// ContainsNetwork returns true if the network from IPv4Addr is contained
+// within the receiver.
+func (ipv4 IPv4Addr) ContainsNetwork(x IPv4Addr) bool {
+ return ipv4.NetworkAddress() <= x.NetworkAddress() &&
+ ipv4.BroadcastAddress() >= x.BroadcastAddress()
+}
+
+// DialPacketArgs returns the arguments required to be passed to
+// net.DialUDP(). If the Mask of ipv4 is not a /32 or the Port is 0,
+// DialPacketArgs() will fail. See Host() to create an IPv4Addr with its
+// mask set to /32.
+func (ipv4 IPv4Addr) DialPacketArgs() (network, dialArgs string) {
+ if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 {
+ return "udp4", ""
+ }
+ return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
+}
+
+// DialStreamArgs returns the arguments required to be passed to
+// net.DialTCP(). If the Mask of ipv4 is not a /32 or the Port is 0,
+// DialStreamArgs() will fail. See Host() to create an IPv4Addr with its
+// mask set to /32.
+func (ipv4 IPv4Addr) DialStreamArgs() (network, dialArgs string) {
+ if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 {
+ return "tcp4", ""
+ }
+ return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
+}
+
+// Equal returns true if a SockAddr is equal to the receiving IPv4Addr.
+func (ipv4 IPv4Addr) Equal(sa SockAddr) bool {
+ ipv4b, ok := sa.(IPv4Addr)
+ if !ok {
+ return false
+ }
+
+ if ipv4.Port != ipv4b.Port {
+ return false
+ }
+
+ if ipv4.Address != ipv4b.Address {
+ return false
+ }
+
+ if ipv4.NetIPNet().String() != ipv4b.NetIPNet().String() {
+ return false
+ }
+
+ return true
+}
+
+// FirstUsable returns an IPv4Addr set to the first address following the
+// network prefix. The first usable address in a network is normally the
+// gateway and should not be used except by devices forwarding packets
+// between two administratively distinct networks (i.e. a router). This
+// function does not discriminate against first usable vs "first address that
+// should be used." For example, FirstUsable() on "192.168.1.10/24" would
+// return the address "192.168.1.1/24".
+func (ipv4 IPv4Addr) FirstUsable() IPAddr {
+ addr := ipv4.NetworkAddress()
+
+ // If /32, return the address itself. If /31 assume a point-to-point
+ // link and return the lower address.
+ if ipv4.Maskbits() < 31 {
+ addr++
+ }
+
+ return IPv4Addr{
+ Address: IPv4Address(addr),
+ Mask: IPv4HostMask,
+ }
+}
+
+// Host returns a copy of ipv4 with its mask set to /32 so that it can be
+// used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or
+// ListenStreamArgs().
+func (ipv4 IPv4Addr) Host() IPAddr {
+ // Nothing should listen on a broadcast address.
+ return IPv4Addr{
+ Address: ipv4.Address,
+ Mask: IPv4HostMask,
+ Port: ipv4.Port,
+ }
+}
+
+// IPPort returns the Port number attached to the IPv4Addr
+func (ipv4 IPv4Addr) IPPort() IPPort {
+ return ipv4.Port
+}
+
+// LastUsable returns the last address before the broadcast address in a
+// given network.
+func (ipv4 IPv4Addr) LastUsable() IPAddr {
+ addr := ipv4.BroadcastAddress()
+
+ // If /32, return the address itself. If /31 assume a point-to-point
+ // link and return the upper address.
+ if ipv4.Maskbits() < 31 {
+ addr--
+ }
+
+ return IPv4Addr{
+ Address: IPv4Address(addr),
+ Mask: IPv4HostMask,
+ }
+}
+
+// ListenPacketArgs returns the arguments required to be passed to
+// net.ListenUDP(). If the Mask of ipv4 is not a /32, ListenPacketArgs()
+// will fail. See Host() to create an IPv4Addr with its mask set to /32.
+func (ipv4 IPv4Addr) ListenPacketArgs() (network, listenArgs string) {
+ if ipv4.Mask != IPv4HostMask {
+ return "udp4", ""
+ }
+ return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
+}
+
+// ListenStreamArgs returns the arguments required to be passed to
+// net.ListenTCP(). If the Mask of ipv4 is not a /32, ListenStreamArgs()
+// will fail. See Host() to create an IPv4Addr with its mask set to /32.
+func (ipv4 IPv4Addr) ListenStreamArgs() (network, listenArgs string) {
+ if ipv4.Mask != IPv4HostMask {
+ return "tcp4", ""
+ }
+ return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
+}
+
+// Maskbits returns the number of network mask bits in a given IPv4Addr. For
+// example, the Maskbits() of "192.168.1.1/24" would return 24.
+func (ipv4 IPv4Addr) Maskbits() int {
+ mask := make(net.IPMask, IPv4len)
+ binary.BigEndian.PutUint32(mask, uint32(ipv4.Mask))
+ maskOnes, _ := mask.Size()
+ return maskOnes
+}
+
+// MustIPv4Addr is a helper method that must return an IPv4Addr or panic on
+// invalid input.
+func MustIPv4Addr(addr string) IPv4Addr {
+ ipv4, err := NewIPv4Addr(addr)
+ if err != nil {
+ panic(fmt.Sprintf("Unable to create an IPv4Addr from %+q: %v", addr, err))
+ }
+ return ipv4
+}
+
+// NetIP returns the address as a net.IP (address is always presized to
+// IPv4).
+func (ipv4 IPv4Addr) NetIP() *net.IP {
+ x := make(net.IP, IPv4len)
+ binary.BigEndian.PutUint32(x, uint32(ipv4.Address))
+ return &x
+}
+
+// NetIPMask create a new net.IPMask from the IPv4Addr.
+func (ipv4 IPv4Addr) NetIPMask() *net.IPMask {
+ ipv4Mask := net.IPMask{}
+ ipv4Mask = make(net.IPMask, IPv4len)
+ binary.BigEndian.PutUint32(ipv4Mask, uint32(ipv4.Mask))
+ return &ipv4Mask
+}
+
+// NetIPNet create a new net.IPNet from the IPv4Addr.
+func (ipv4 IPv4Addr) NetIPNet() *net.IPNet {
+ ipv4net := &net.IPNet{}
+ ipv4net.IP = make(net.IP, IPv4len)
+ binary.BigEndian.PutUint32(ipv4net.IP, uint32(ipv4.NetworkAddress()))
+ ipv4net.Mask = *ipv4.NetIPMask()
+ return ipv4net
+}
+
+// Network returns the network prefix or network address for a given network.
+func (ipv4 IPv4Addr) Network() IPAddr {
+ return IPv4Addr{
+ Address: IPv4Address(ipv4.NetworkAddress()),
+ Mask: ipv4.Mask,
+ }
+}
+
+// NetworkAddress returns an IPv4Network of the IPv4Addr's network address.
+func (ipv4 IPv4Addr) NetworkAddress() IPv4Network {
+ return IPv4Network(uint32(ipv4.Address) & uint32(ipv4.Mask))
+}
+
+// Octets returns a slice of the four octets in an IPv4Addr's Address. The
+// order of the bytes is big endian.
+func (ipv4 IPv4Addr) Octets() []int {
+ return []int{
+ int(ipv4.Address >> 24),
+ int((ipv4.Address >> 16) & 0xff),
+ int((ipv4.Address >> 8) & 0xff),
+ int(ipv4.Address & 0xff),
+ }
+}
+
+// String returns a string representation of the IPv4Addr
+func (ipv4 IPv4Addr) String() string {
+ if ipv4.Port != 0 {
+ return fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
+ }
+
+ if ipv4.Maskbits() == 32 {
+ return ipv4.NetIP().String()
+ }
+
+ return fmt.Sprintf("%s/%d", ipv4.NetIP().String(), ipv4.Maskbits())
+}
+
+// Type is used as a type switch and returns TypeIPv4
+func (IPv4Addr) Type() SockAddrType {
+ return TypeIPv4
+}
+
+// IPv4AddrAttr returns a string representation of an attribute for the given
+// IPv4Addr.
+func IPv4AddrAttr(ipv4 IPv4Addr, selector AttrName) string {
+ fn, found := ipv4AddrAttrMap[selector]
+ if !found {
+ return ""
+ }
+
+ return fn(ipv4)
+}
+
+// IPv4Attrs returns a list of attributes supported by the IPv4Addr type
+func IPv4Attrs() []AttrName {
+ return ipv4AddrAttrs
+}
+
+// ipv4AddrInit is called once at init()
+func ipv4AddrInit() {
+ // Sorted for human readability
+ ipv4AddrAttrs = []AttrName{
+ "size", // Same position as in IPv6 for output consistency
+ "broadcast",
+ "uint32",
+ }
+
+ ipv4AddrAttrMap = map[AttrName]func(ipv4 IPv4Addr) string{
+ "broadcast": func(ipv4 IPv4Addr) string {
+ return ipv4.Broadcast().String()
+ },
+ "size": func(ipv4 IPv4Addr) string {
+ return fmt.Sprintf("%d", 1< 2 && ipv6Str[0] == '[' && ipv6Str[len(ipv6Str)-1] == ']' {
+ ipv6Str = ipv6Str[1 : len(ipv6Str)-1]
+ }
+ ip := net.ParseIP(ipv6Str)
+ if ip != nil {
+ ipv6 := ip.To16()
+ if ipv6 == nil {
+ return IPv6Addr{}, fmt.Errorf("Unable to string convert %+q to a 16byte IPv6 address", ipv6Str)
+ }
+
+ ipv6BigIntAddr := new(big.Int)
+ ipv6BigIntAddr.SetBytes(ipv6)
+
+ ipv6BigIntMask := new(big.Int)
+ ipv6BigIntMask.Set(ipv6HostMask)
+
+ return IPv6Addr{
+ Address: IPv6Address(ipv6BigIntAddr),
+ Mask: IPv6Mask(ipv6BigIntMask),
+ }, nil
+ }
+
+ // Parse as an IPv6 CIDR
+ ipAddr, network, err := net.ParseCIDR(ipv6Str)
+ if err == nil {
+ ipv6 := ipAddr.To16()
+ if ipv6 == nil {
+ return IPv6Addr{}, fmt.Errorf("Unable to convert %+q to a 16byte IPv6 address", ipv6Str)
+ }
+
+ ipv6BigIntAddr := new(big.Int)
+ ipv6BigIntAddr.SetBytes(ipv6)
+
+ ipv6BigIntMask := new(big.Int)
+ ipv6BigIntMask.SetBytes(network.Mask)
+
+ ipv6Addr := IPv6Addr{
+ Address: IPv6Address(ipv6BigIntAddr),
+ Mask: IPv6Mask(ipv6BigIntMask),
+ }
+ return ipv6Addr, nil
+ }
+
+ return IPv6Addr{}, fmt.Errorf("Unable to parse %+q to an IPv6 address: %v", ipv6Str, err)
+}
+
+// AddressBinString returns a string with the IPv6Addr's Address represented
+// as a sequence of '0' and '1' characters. This method is useful for
+// debugging or by operators who want to inspect an address.
+func (ipv6 IPv6Addr) AddressBinString() string {
+ bi := big.Int(*ipv6.Address)
+ return fmt.Sprintf("%0128s", bi.Text(2))
+}
+
+// AddressHexString returns a string with the IPv6Addr address represented as
+// a sequence of hex characters. This method is useful for debugging or by
+// operators who want to inspect an address.
+func (ipv6 IPv6Addr) AddressHexString() string {
+ bi := big.Int(*ipv6.Address)
+ return fmt.Sprintf("%032s", bi.Text(16))
+}
+
+// CmpAddress follows the Cmp() standard protocol and returns:
+//
+// - -1 If the receiver should sort first because its address is lower than arg
+// - 0 if the SockAddr arg equal to the receiving IPv6Addr or the argument is of a
+// different type.
+// - 1 If the argument should sort first.
+func (ipv6 IPv6Addr) CmpAddress(sa SockAddr) int {
+ ipv6b, ok := sa.(IPv6Addr)
+ if !ok {
+ return sortDeferDecision
+ }
+
+ ipv6aBigInt := new(big.Int)
+ ipv6aBigInt.Set(ipv6.Address)
+ ipv6bBigInt := new(big.Int)
+ ipv6bBigInt.Set(ipv6b.Address)
+
+ return ipv6aBigInt.Cmp(ipv6bBigInt)
+}
+
+// CmpPort follows the Cmp() standard protocol and returns:
+//
+// - -1 If the receiver should sort first because its port is lower than arg
+// - 0 if the SockAddr arg's port number is equal to the receiving IPv6Addr,
+// regardless of type.
+// - 1 If the argument should sort first.
+func (ipv6 IPv6Addr) CmpPort(sa SockAddr) int {
+ var saPort IPPort
+ switch v := sa.(type) {
+ case IPv4Addr:
+ saPort = v.Port
+ case IPv6Addr:
+ saPort = v.Port
+ default:
+ return sortDeferDecision
+ }
+
+ switch {
+ case ipv6.Port == saPort:
+ return sortDeferDecision
+ case ipv6.Port < saPort:
+ return sortReceiverBeforeArg
+ default:
+ return sortArgBeforeReceiver
+ }
+}
+
+// CmpRFC follows the Cmp() standard protocol and returns:
+//
+// - -1 If the receiver should sort first because it belongs to the RFC and its
+// arg does not
+// - 0 if the receiver and arg both belong to the same RFC or neither do.
+// - 1 If the arg belongs to the RFC but receiver does not.
+func (ipv6 IPv6Addr) CmpRFC(rfcNum uint, sa SockAddr) int {
+ recvInRFC := IsRFC(rfcNum, ipv6)
+ ipv6b, ok := sa.(IPv6Addr)
+ if !ok {
+ // If the receiver is part of the desired RFC and the SockAddr
+ // argument is not, sort receiver before the non-IPv6 SockAddr.
+ // Conversely, if the receiver is not part of the RFC, punt on
+ // sorting and leave it for the next sorter.
+ if recvInRFC {
+ return sortReceiverBeforeArg
+ } else {
+ return sortDeferDecision
+ }
+ }
+
+ argInRFC := IsRFC(rfcNum, ipv6b)
+ switch {
+ case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC):
+ // If a and b both belong to the RFC, or neither belong to
+ // rfcNum, defer sorting to the next sorter.
+ return sortDeferDecision
+ case recvInRFC && !argInRFC:
+ return sortReceiverBeforeArg
+ default:
+ return sortArgBeforeReceiver
+ }
+}
+
+// Contains returns true if the SockAddr is contained within the receiver.
+func (ipv6 IPv6Addr) Contains(sa SockAddr) bool {
+ ipv6b, ok := sa.(IPv6Addr)
+ if !ok {
+ return false
+ }
+
+ return ipv6.ContainsNetwork(ipv6b)
+}
+
+// ContainsAddress returns true if the IPv6Address is contained within the
+// receiver.
+func (ipv6 IPv6Addr) ContainsAddress(x IPv6Address) bool {
+ xAddr := IPv6Addr{
+ Address: x,
+ Mask: ipv6HostMask,
+ }
+
+ {
+ xIPv6 := xAddr.FirstUsable().(IPv6Addr)
+ yIPv6 := ipv6.FirstUsable().(IPv6Addr)
+ if xIPv6.CmpAddress(yIPv6) >= 1 {
+ return false
+ }
+ }
+
+ {
+ xIPv6 := xAddr.LastUsable().(IPv6Addr)
+ yIPv6 := ipv6.LastUsable().(IPv6Addr)
+ if xIPv6.CmpAddress(yIPv6) <= -1 {
+ return false
+ }
+ }
+ return true
+}
+
+// ContainsNetwork returns true if the network from IPv6Addr is contained within
+// the receiver.
+func (x IPv6Addr) ContainsNetwork(y IPv6Addr) bool {
+ {
+ xIPv6 := x.FirstUsable().(IPv6Addr)
+ yIPv6 := y.FirstUsable().(IPv6Addr)
+ if ret := xIPv6.CmpAddress(yIPv6); ret >= 1 {
+ return false
+ }
+ }
+
+ {
+ xIPv6 := x.LastUsable().(IPv6Addr)
+ yIPv6 := y.LastUsable().(IPv6Addr)
+ if ret := xIPv6.CmpAddress(yIPv6); ret <= -1 {
+ return false
+ }
+ }
+ return true
+}
+
+// DialPacketArgs returns the arguments required to be passed to
+// net.DialUDP(). If the Mask of ipv6 is not a /128 or the Port is 0,
+// DialPacketArgs() will fail. See Host() to create an IPv6Addr with its
+// mask set to /128.
+func (ipv6 IPv6Addr) DialPacketArgs() (network, dialArgs string) {
+ ipv6Mask := big.Int(*ipv6.Mask)
+ if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 {
+ return "udp6", ""
+ }
+ return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
+}
+
+// DialStreamArgs returns the arguments required to be passed to
+// net.DialTCP(). If the Mask of ipv6 is not a /128 or the Port is 0,
+// DialStreamArgs() will fail. See Host() to create an IPv6Addr with its
+// mask set to /128.
+func (ipv6 IPv6Addr) DialStreamArgs() (network, dialArgs string) {
+ ipv6Mask := big.Int(*ipv6.Mask)
+ if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 {
+ return "tcp6", ""
+ }
+ return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
+}
+
+// Equal returns true if a SockAddr is equal to the receiving IPv4Addr.
+func (ipv6a IPv6Addr) Equal(sa SockAddr) bool {
+ ipv6b, ok := sa.(IPv6Addr)
+ if !ok {
+ return false
+ }
+
+ if ipv6a.NetIP().String() != ipv6b.NetIP().String() {
+ return false
+ }
+
+ if ipv6a.NetIPNet().String() != ipv6b.NetIPNet().String() {
+ return false
+ }
+
+ if ipv6a.Port != ipv6b.Port {
+ return false
+ }
+
+ return true
+}
+
+// FirstUsable returns an IPv6Addr set to the first address following the
+// network prefix. The first usable address in a network is normally the
+// gateway and should not be used except by devices forwarding packets
+// between two administratively distinct networks (i.e. a router). This
+// function does not discriminate against first usable vs "first address that
+// should be used." For example, FirstUsable() on "2001:0db8::0003/64" would
+// return "2001:0db8::00011".
+func (ipv6 IPv6Addr) FirstUsable() IPAddr {
+ return IPv6Addr{
+ Address: IPv6Address(ipv6.NetworkAddress()),
+ Mask: ipv6HostMask,
+ }
+}
+
+// Host returns a copy of ipv6 with its mask set to /128 so that it can be
+// used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or
+// ListenStreamArgs().
+func (ipv6 IPv6Addr) Host() IPAddr {
+ // Nothing should listen on a broadcast address.
+ return IPv6Addr{
+ Address: ipv6.Address,
+ Mask: ipv6HostMask,
+ Port: ipv6.Port,
+ }
+}
+
+// IPPort returns the Port number attached to the IPv6Addr
+func (ipv6 IPv6Addr) IPPort() IPPort {
+ return ipv6.Port
+}
+
+// LastUsable returns the last address in a given network.
+func (ipv6 IPv6Addr) LastUsable() IPAddr {
+ addr := new(big.Int)
+ addr.Set(ipv6.Address)
+
+ mask := new(big.Int)
+ mask.Set(ipv6.Mask)
+
+ negMask := new(big.Int)
+ negMask.Xor(ipv6HostMask, mask)
+
+ lastAddr := new(big.Int)
+ lastAddr.And(addr, mask)
+ lastAddr.Or(lastAddr, negMask)
+
+ return IPv6Addr{
+ Address: IPv6Address(lastAddr),
+ Mask: ipv6HostMask,
+ }
+}
+
+// ListenPacketArgs returns the arguments required to be passed to
+// net.ListenUDP(). If the Mask of ipv6 is not a /128, ListenPacketArgs()
+// will fail. See Host() to create an IPv6Addr with its mask set to /128.
+func (ipv6 IPv6Addr) ListenPacketArgs() (network, listenArgs string) {
+ ipv6Mask := big.Int(*ipv6.Mask)
+ if ipv6Mask.Cmp(ipv6HostMask) != 0 {
+ return "udp6", ""
+ }
+ return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
+}
+
+// ListenStreamArgs returns the arguments required to be passed to
+// net.ListenTCP(). If the Mask of ipv6 is not a /128, ListenStreamArgs()
+// will fail. See Host() to create an IPv6Addr with its mask set to /128.
+func (ipv6 IPv6Addr) ListenStreamArgs() (network, listenArgs string) {
+ ipv6Mask := big.Int(*ipv6.Mask)
+ if ipv6Mask.Cmp(ipv6HostMask) != 0 {
+ return "tcp6", ""
+ }
+ return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
+}
+
+// Maskbits returns the number of network mask bits in a given IPv6Addr. For
+// example, the Maskbits() of "2001:0db8::0003/64" would return 64.
+func (ipv6 IPv6Addr) Maskbits() int {
+ maskOnes, _ := ipv6.NetIPNet().Mask.Size()
+
+ return maskOnes
+}
+
+// MustIPv6Addr is a helper method that must return an IPv6Addr or panic on
+// invalid input.
+func MustIPv6Addr(addr string) IPv6Addr {
+ ipv6, err := NewIPv6Addr(addr)
+ if err != nil {
+ panic(fmt.Sprintf("Unable to create an IPv6Addr from %+q: %v", addr, err))
+ }
+ return ipv6
+}
+
+// NetIP returns the address as a net.IP.
+func (ipv6 IPv6Addr) NetIP() *net.IP {
+ return bigIntToNetIPv6(ipv6.Address)
+}
+
+// NetIPMask create a new net.IPMask from the IPv6Addr.
+func (ipv6 IPv6Addr) NetIPMask() *net.IPMask {
+ ipv6Mask := make(net.IPMask, IPv6len)
+ m := big.Int(*ipv6.Mask)
+ copy(ipv6Mask, m.Bytes())
+ return &ipv6Mask
+}
+
+// Network returns a pointer to the net.IPNet within IPv4Addr receiver.
+func (ipv6 IPv6Addr) NetIPNet() *net.IPNet {
+ ipv6net := &net.IPNet{}
+ ipv6net.IP = make(net.IP, IPv6len)
+ copy(ipv6net.IP, *ipv6.NetIP())
+ ipv6net.Mask = *ipv6.NetIPMask()
+ return ipv6net
+}
+
+// Network returns the network prefix or network address for a given network.
+func (ipv6 IPv6Addr) Network() IPAddr {
+ return IPv6Addr{
+ Address: IPv6Address(ipv6.NetworkAddress()),
+ Mask: ipv6.Mask,
+ }
+}
+
+// NetworkAddress returns an IPv6Network of the IPv6Addr's network address.
+func (ipv6 IPv6Addr) NetworkAddress() IPv6Network {
+ addr := new(big.Int)
+ addr.SetBytes((*ipv6.Address).Bytes())
+
+ mask := new(big.Int)
+ mask.SetBytes(*ipv6.NetIPMask())
+
+ netAddr := new(big.Int)
+ netAddr.And(addr, mask)
+
+ return IPv6Network(netAddr)
+}
+
+// Octets returns a slice of the 16 octets in an IPv6Addr's Address. The
+// order of the bytes is big endian.
+func (ipv6 IPv6Addr) Octets() []int {
+ x := make([]int, IPv6len)
+ for i, b := range *bigIntToNetIPv6(ipv6.Address) {
+ x[i] = int(b)
+ }
+
+ return x
+}
+
+// String returns a string representation of the IPv6Addr
+func (ipv6 IPv6Addr) String() string {
+ if ipv6.Port != 0 {
+ return fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
+ }
+
+ if ipv6.Maskbits() == 128 {
+ return ipv6.NetIP().String()
+ }
+
+ return fmt.Sprintf("%s/%d", ipv6.NetIP().String(), ipv6.Maskbits())
+}
+
+// Type is used as a type switch and returns TypeIPv6
+func (IPv6Addr) Type() SockAddrType {
+ return TypeIPv6
+}
+
+// IPv6Attrs returns a list of attributes supported by the IPv6Addr type
+func IPv6Attrs() []AttrName {
+ return ipv6AddrAttrs
+}
+
+// IPv6AddrAttr returns a string representation of an attribute for the given
+// IPv6Addr.
+func IPv6AddrAttr(ipv6 IPv6Addr, selector AttrName) string {
+ fn, found := ipv6AddrAttrMap[selector]
+ if !found {
+ return ""
+ }
+
+ return fn(ipv6)
+}
+
+// ipv6AddrInit is called once at init()
+func ipv6AddrInit() {
+ // Sorted for human readability
+ ipv6AddrAttrs = []AttrName{
+ "size", // Same position as in IPv6 for output consistency
+ "uint128",
+ }
+
+ ipv6AddrAttrMap = map[AttrName]func(ipv6 IPv6Addr) string{
+ "size": func(ipv6 IPv6Addr) string {
+ netSize := big.NewInt(1)
+ netSize = netSize.Lsh(netSize, uint(IPv6len*8-ipv6.Maskbits()))
+ return netSize.Text(10)
+ },
+ "uint128": func(ipv6 IPv6Addr) string {
+ b := big.Int(*ipv6.Address)
+ return b.Text(10)
+ },
+ }
+}
+
+// bigIntToNetIPv6 is a helper function that correctly returns a net.IP with the
+// correctly padded values.
+func bigIntToNetIPv6(bi *big.Int) *net.IP {
+ x := make(net.IP, IPv6len)
+ ipv6Bytes := bi.Bytes()
+
+ // It's possibe for ipv6Bytes to be less than IPv6len bytes in size. If
+ // they are different sizes we to pad the size of response.
+ if len(ipv6Bytes) < IPv6len {
+ buf := new(bytes.Buffer)
+ buf.Grow(IPv6len)
+
+ for i := len(ipv6Bytes); i < IPv6len; i++ {
+ if err := binary.Write(buf, binary.BigEndian, byte(0)); err != nil {
+ panic(fmt.Sprintf("Unable to pad byte %d of input %v: %v", i, bi, err))
+ }
+ }
+
+ for _, b := range ipv6Bytes {
+ if err := binary.Write(buf, binary.BigEndian, b); err != nil {
+ panic(fmt.Sprintf("Unable to preserve endianness of input %v: %v", bi, err))
+ }
+ }
+
+ ipv6Bytes = buf.Bytes()
+ }
+ i := copy(x, ipv6Bytes)
+ if i != IPv6len {
+ panic("IPv6 wrong size")
+ }
+ return &x
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/rfc.go b/vendor/github.com/hashicorp/go-sockaddr/rfc.go
new file mode 100644
index 00000000000..02e188f6fe6
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/rfc.go
@@ -0,0 +1,948 @@
+package sockaddr
+
+// ForwardingBlacklist is a faux RFC that includes a list of non-forwardable IP
+// blocks.
+const ForwardingBlacklist = 4294967295
+const ForwardingBlacklistRFC = "4294967295"
+
+// IsRFC tests to see if an SockAddr matches the specified RFC
+func IsRFC(rfcNum uint, sa SockAddr) bool {
+ rfcNetMap := KnownRFCs()
+ rfcNets, ok := rfcNetMap[rfcNum]
+ if !ok {
+ return false
+ }
+
+ var contained bool
+ for _, rfcNet := range rfcNets {
+ if rfcNet.Contains(sa) {
+ contained = true
+ break
+ }
+ }
+ return contained
+}
+
+// KnownRFCs returns an initial set of known RFCs.
+//
+// NOTE (sean@): As this list evolves over time, please submit patches to keep
+// this list current. If something isn't right, inquire, as it may just be a
+// bug on my part. Some of the inclusions were based on my judgement as to what
+// would be a useful value (e.g. RFC3330).
+//
+// Useful resources:
+//
+// * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
+// * https://www.iana.org/assignments/ipv6-unicast-address-assignments/ipv6-unicast-address-assignments.xhtml
+// * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
+func KnownRFCs() map[uint]SockAddrs {
+ // NOTE(sean@): Multiple SockAddrs per RFC lend themselves well to a
+ // RADIX tree, but `ENOTIME`. Patches welcome.
+ return map[uint]SockAddrs{
+ 919: {
+ // [RFC919] Broadcasting Internet Datagrams
+ MustIPv4Addr("255.255.255.255/32"), // [RFC1122], §7 Broadcast IP Addressing - Proposed Standards
+ },
+ 1122: {
+ // [RFC1122] Requirements for Internet Hosts -- Communication Layers
+ MustIPv4Addr("0.0.0.0/8"), // [RFC1122], §3.2.1.3
+ MustIPv4Addr("127.0.0.0/8"), // [RFC1122], §3.2.1.3
+ },
+ 1112: {
+ // [RFC1112] Host Extensions for IP Multicasting
+ MustIPv4Addr("224.0.0.0/4"), // [RFC1112], §4 Host Group Addresses
+ },
+ 1918: {
+ // [RFC1918] Address Allocation for Private Internets
+ MustIPv4Addr("10.0.0.0/8"),
+ MustIPv4Addr("172.16.0.0/12"),
+ MustIPv4Addr("192.168.0.0/16"),
+ },
+ 2544: {
+ // [RFC2544] Benchmarking Methodology for Network
+ // Interconnect Devices
+ MustIPv4Addr("198.18.0.0/15"),
+ },
+ 2765: {
+ // [RFC2765] Stateless IP/ICMP Translation Algorithm
+ // (SIIT) (obsoleted by RFCs 6145, which itself was
+ // later obsoleted by 7915).
+
+ // [RFC2765], §2.1 Addresses
+ MustIPv6Addr("0:0:0:0:0:ffff:0:0/96"),
+ },
+ 2928: {
+ // [RFC2928] Initial IPv6 Sub-TLA ID Assignments
+ MustIPv6Addr("2001::/16"), // Superblock
+ //MustIPv6Addr("2001:0000::/23"), // IANA
+ //MustIPv6Addr("2001:0200::/23"), // APNIC
+ //MustIPv6Addr("2001:0400::/23"), // ARIN
+ //MustIPv6Addr("2001:0600::/23"), // RIPE NCC
+ //MustIPv6Addr("2001:0800::/23"), // (future assignment)
+ // ...
+ //MustIPv6Addr("2001:FE00::/23"), // (future assignment)
+ },
+ 3056: { // 6to4 address
+ // [RFC3056] Connection of IPv6 Domains via IPv4 Clouds
+
+ // [RFC3056], §2 IPv6 Prefix Allocation
+ MustIPv6Addr("2002::/16"),
+ },
+ 3068: {
+ // [RFC3068] An Anycast Prefix for 6to4 Relay Routers
+ // (obsolete by RFC7526)
+
+ // [RFC3068], § 6to4 Relay anycast address
+ MustIPv4Addr("192.88.99.0/24"),
+
+ // [RFC3068], §2.5 6to4 IPv6 relay anycast address
+ //
+ // NOTE: /120 == 128-(32-24)
+ MustIPv6Addr("2002:c058:6301::/120"),
+ },
+ 3171: {
+ // [RFC3171] IANA Guidelines for IPv4 Multicast Address Assignments
+ MustIPv4Addr("224.0.0.0/4"),
+ },
+ 3330: {
+ // [RFC3330] Special-Use IPv4 Addresses
+
+ // Addresses in this block refer to source hosts on
+ // "this" network. Address 0.0.0.0/32 may be used as a
+ // source address for this host on this network; other
+ // addresses within 0.0.0.0/8 may be used to refer to
+ // specified hosts on this network [RFC1700, page 4].
+ MustIPv4Addr("0.0.0.0/8"),
+
+ // 10.0.0.0/8 - This block is set aside for use in
+ // private networks. Its intended use is documented in
+ // [RFC1918]. Addresses within this block should not
+ // appear on the public Internet.
+ MustIPv4Addr("10.0.0.0/8"),
+
+ // 14.0.0.0/8 - This block is set aside for assignments
+ // to the international system of Public Data Networks
+ // [RFC1700, page 181]. The registry of assignments
+ // within this block can be accessed from the "Public
+ // Data Network Numbers" link on the web page at
+ // http://www.iana.org/numbers.html. Addresses within
+ // this block are assigned to users and should be
+ // treated as such.
+
+ // 24.0.0.0/8 - This block was allocated in early 1996
+ // for use in provisioning IP service over cable
+ // television systems. Although the IANA initially was
+ // involved in making assignments to cable operators,
+ // this responsibility was transferred to American
+ // Registry for Internet Numbers (ARIN) in May 2001.
+ // Addresses within this block are assigned in the
+ // normal manner and should be treated as such.
+
+ // 39.0.0.0/8 - This block was used in the "Class A
+ // Subnet Experiment" that commenced in May 1995, as
+ // documented in [RFC1797]. The experiment has been
+ // completed and this block has been returned to the
+ // pool of addresses reserved for future allocation or
+ // assignment. This block therefore no longer has a
+ // special use and is subject to allocation to a
+ // Regional Internet Registry for assignment in the
+ // normal manner.
+
+ // 127.0.0.0/8 - This block is assigned for use as the Internet host
+ // loopback address. A datagram sent by a higher level protocol to an
+ // address anywhere within this block should loop back inside the host.
+ // This is ordinarily implemented using only 127.0.0.1/32 for loopback,
+ // but no addresses within this block should ever appear on any network
+ // anywhere [RFC1700, page 5].
+ MustIPv4Addr("127.0.0.0/8"),
+
+ // 128.0.0.0/16 - This block, corresponding to the
+ // numerically lowest of the former Class B addresses,
+ // was initially and is still reserved by the IANA.
+ // Given the present classless nature of the IP address
+ // space, the basis for the reservation no longer
+ // applies and addresses in this block are subject to
+ // future allocation to a Regional Internet Registry for
+ // assignment in the normal manner.
+
+ // 169.254.0.0/16 - This is the "link local" block. It
+ // is allocated for communication between hosts on a
+ // single link. Hosts obtain these addresses by
+ // auto-configuration, such as when a DHCP server may
+ // not be found.
+ MustIPv4Addr("169.254.0.0/16"),
+
+ // 172.16.0.0/12 - This block is set aside for use in
+ // private networks. Its intended use is documented in
+ // [RFC1918]. Addresses within this block should not
+ // appear on the public Internet.
+ MustIPv4Addr("172.16.0.0/12"),
+
+ // 191.255.0.0/16 - This block, corresponding to the numerically highest
+ // to the former Class B addresses, was initially and is still reserved
+ // by the IANA. Given the present classless nature of the IP address
+ // space, the basis for the reservation no longer applies and addresses
+ // in this block are subject to future allocation to a Regional Internet
+ // Registry for assignment in the normal manner.
+
+ // 192.0.0.0/24 - This block, corresponding to the
+ // numerically lowest of the former Class C addresses,
+ // was initially and is still reserved by the IANA.
+ // Given the present classless nature of the IP address
+ // space, the basis for the reservation no longer
+ // applies and addresses in this block are subject to
+ // future allocation to a Regional Internet Registry for
+ // assignment in the normal manner.
+
+ // 192.0.2.0/24 - This block is assigned as "TEST-NET" for use in
+ // documentation and example code. It is often used in conjunction with
+ // domain names example.com or example.net in vendor and protocol
+ // documentation. Addresses within this block should not appear on the
+ // public Internet.
+ MustIPv4Addr("192.0.2.0/24"),
+
+ // 192.88.99.0/24 - This block is allocated for use as 6to4 relay
+ // anycast addresses, according to [RFC3068].
+ MustIPv4Addr("192.88.99.0/24"),
+
+ // 192.168.0.0/16 - This block is set aside for use in private networks.
+ // Its intended use is documented in [RFC1918]. Addresses within this
+ // block should not appear on the public Internet.
+ MustIPv4Addr("192.168.0.0/16"),
+
+ // 198.18.0.0/15 - This block has been allocated for use
+ // in benchmark tests of network interconnect devices.
+ // Its use is documented in [RFC2544].
+ MustIPv4Addr("198.18.0.0/15"),
+
+ // 223.255.255.0/24 - This block, corresponding to the
+ // numerically highest of the former Class C addresses,
+ // was initially and is still reserved by the IANA.
+ // Given the present classless nature of the IP address
+ // space, the basis for the reservation no longer
+ // applies and addresses in this block are subject to
+ // future allocation to a Regional Internet Registry for
+ // assignment in the normal manner.
+
+ // 224.0.0.0/4 - This block, formerly known as the Class
+ // D address space, is allocated for use in IPv4
+ // multicast address assignments. The IANA guidelines
+ // for assignments from this space are described in
+ // [RFC3171].
+ MustIPv4Addr("224.0.0.0/4"),
+
+ // 240.0.0.0/4 - This block, formerly known as the Class E address
+ // space, is reserved. The "limited broadcast" destination address
+ // 255.255.255.255 should never be forwarded outside the (sub-)net of
+ // the source. The remainder of this space is reserved
+ // for future use. [RFC1700, page 4]
+ MustIPv4Addr("240.0.0.0/4"),
+ },
+ 3849: {
+ // [RFC3849] IPv6 Address Prefix Reserved for Documentation
+ MustIPv6Addr("2001:db8::/32"), // [RFC3849], §4 IANA Considerations
+ },
+ 3927: {
+ // [RFC3927] Dynamic Configuration of IPv4 Link-Local Addresses
+ MustIPv4Addr("169.254.0.0/16"), // [RFC3927], §2.1 Link-Local Address Selection
+ },
+ 4038: {
+ // [RFC4038] Application Aspects of IPv6 Transition
+
+ // [RFC4038], §4.2. IPv6 Applications in a Dual-Stack Node
+ MustIPv6Addr("0:0:0:0:0:ffff::/96"),
+ },
+ 4193: {
+ // [RFC4193] Unique Local IPv6 Unicast Addresses
+ MustIPv6Addr("fc00::/7"),
+ },
+ 4291: {
+ // [RFC4291] IP Version 6 Addressing Architecture
+
+ // [RFC4291], §2.5.2 The Unspecified Address
+ MustIPv6Addr("::/128"),
+
+ // [RFC4291], §2.5.3 The Loopback Address
+ MustIPv6Addr("::1/128"),
+
+ // [RFC4291], §2.5.5.1. IPv4-Compatible IPv6 Address
+ MustIPv6Addr("::/96"),
+
+ // [RFC4291], §2.5.5.2. IPv4-Mapped IPv6 Address
+ MustIPv6Addr("::ffff:0:0/96"),
+
+ // [RFC4291], §2.5.6 Link-Local IPv6 Unicast Addresses
+ MustIPv6Addr("fe80::/10"),
+
+ // [RFC4291], §2.5.7 Site-Local IPv6 Unicast Addresses
+ // (depreciated)
+ MustIPv6Addr("fec0::/10"),
+
+ // [RFC4291], §2.7 Multicast Addresses
+ MustIPv6Addr("ff00::/8"),
+
+ // IPv6 Multicast Information.
+ //
+ // In the following "table" below, `ff0x` is replaced
+ // with the following values depending on the scope of
+ // the query:
+ //
+ // IPv6 Multicast Scopes:
+ // * ff00/9 // reserved
+ // * ff01/9 // interface-local
+ // * ff02/9 // link-local
+ // * ff03/9 // realm-local
+ // * ff04/9 // admin-local
+ // * ff05/9 // site-local
+ // * ff08/9 // organization-local
+ // * ff0e/9 // global
+ // * ff0f/9 // reserved
+ //
+ // IPv6 Multicast Addresses:
+ // * ff0x::2 // All routers
+ // * ff02::5 // OSPFIGP
+ // * ff02::6 // OSPFIGP Designated Routers
+ // * ff02::9 // RIP Routers
+ // * ff02::a // EIGRP Routers
+ // * ff02::d // All PIM Routers
+ // * ff02::1a // All RPL Routers
+ // * ff0x::fb // mDNSv6
+ // * ff0x::101 // All Network Time Protocol (NTP) servers
+ // * ff02::1:1 // Link Name
+ // * ff02::1:2 // All-dhcp-agents
+ // * ff02::1:3 // Link-local Multicast Name Resolution
+ // * ff05::1:3 // All-dhcp-servers
+ // * ff02::1:ff00:0/104 // Solicited-node multicast address.
+ // * ff02::2:ff00:0/104 // Node Information Queries
+ },
+ 4380: {
+ // [RFC4380] Teredo: Tunneling IPv6 over UDP through
+ // Network Address Translations (NATs)
+
+ // [RFC4380], §2.6 Global Teredo IPv6 Service Prefix
+ MustIPv6Addr("2001:0000::/32"),
+ },
+ 4773: {
+ // [RFC4773] Administration of the IANA Special Purpose IPv6 Address Block
+ MustIPv6Addr("2001:0000::/23"), // IANA
+ },
+ 4843: {
+ // [RFC4843] An IPv6 Prefix for Overlay Routable Cryptographic Hash Identifiers (ORCHID)
+ MustIPv6Addr("2001:10::/28"), // [RFC4843], §7 IANA Considerations
+ },
+ 5180: {
+ // [RFC5180] IPv6 Benchmarking Methodology for Network Interconnect Devices
+ MustIPv6Addr("2001:0200::/48"), // [RFC5180], §8 IANA Considerations
+ },
+ 5735: {
+ // [RFC5735] Special Use IPv4 Addresses
+ MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1
+ MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2
+ MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3
+ MustIPv4Addr("198.18.0.0/15"), // Benchmarks
+ },
+ 5737: {
+ // [RFC5737] IPv4 Address Blocks Reserved for Documentation
+ MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1
+ MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2
+ MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3
+ },
+ 6052: {
+ // [RFC6052] IPv6 Addressing of IPv4/IPv6 Translators
+ MustIPv6Addr("64:ff9b::/96"), // [RFC6052], §2.1. Well-Known Prefix
+ },
+ 6333: {
+ // [RFC6333] Dual-Stack Lite Broadband Deployments Following IPv4 Exhaustion
+ MustIPv4Addr("192.0.0.0/29"), // [RFC6333], §5.7 Well-Known IPv4 Address
+ },
+ 6598: {
+ // [RFC6598] IANA-Reserved IPv4 Prefix for Shared Address Space
+ MustIPv4Addr("100.64.0.0/10"),
+ },
+ 6666: {
+ // [RFC6666] A Discard Prefix for IPv6
+ MustIPv6Addr("0100::/64"),
+ },
+ 6890: {
+ // [RFC6890] Special-Purpose IP Address Registries
+
+ // From "RFC6890 §2.2.1 Information Requirements":
+ /*
+ The IPv4 and IPv6 Special-Purpose Address Registries maintain the
+ following information regarding each entry:
+
+ o Address Block - A block of IPv4 or IPv6 addresses that has been
+ registered for a special purpose.
+
+ o Name - A descriptive name for the special-purpose address block.
+
+ o RFC - The RFC through which the special-purpose address block was
+ requested.
+
+ o Allocation Date - The date upon which the special-purpose address
+ block was allocated.
+
+ o Termination Date - The date upon which the allocation is to be
+ terminated. This field is applicable for limited-use allocations
+ only.
+
+ o Source - A boolean value indicating whether an address from the
+ allocated special-purpose address block is valid when used as the
+ source address of an IP datagram that transits two devices.
+
+ o Destination - A boolean value indicating whether an address from
+ the allocated special-purpose address block is valid when used as
+ the destination address of an IP datagram that transits two
+ devices.
+
+ o Forwardable - A boolean value indicating whether a router may
+ forward an IP datagram whose destination address is drawn from the
+ allocated special-purpose address block between external
+ interfaces.
+
+ o Global - A boolean value indicating whether an IP datagram whose
+ destination address is drawn from the allocated special-purpose
+ address block is forwardable beyond a specified administrative
+ domain.
+
+ o Reserved-by-Protocol - A boolean value indicating whether the
+ special-purpose address block is reserved by IP, itself. This
+ value is "TRUE" if the RFC that created the special-purpose
+ address block requires all compliant IP implementations to behave
+ in a special way when processing packets either to or from
+ addresses contained by the address block.
+
+ If the value of "Destination" is FALSE, the values of "Forwardable"
+ and "Global" must also be false.
+ */
+
+ /*+----------------------+----------------------------+
+ * | Attribute | Value |
+ * +----------------------+----------------------------+
+ * | Address Block | 0.0.0.0/8 |
+ * | Name | "This host on this network"|
+ * | RFC | [RFC1122], Section 3.2.1.3 |
+ * | Allocation Date | September 1981 |
+ * | Termination Date | N/A |
+ * | Source | True |
+ * | Destination | False |
+ * | Forwardable | False |
+ * | Global | False |
+ * | Reserved-by-Protocol | True |
+ * +----------------------+----------------------------+*/
+ MustIPv4Addr("0.0.0.0/8"),
+
+ /*+----------------------+---------------+
+ * | Attribute | Value |
+ * +----------------------+---------------+
+ * | Address Block | 10.0.0.0/8 |
+ * | Name | Private-Use |
+ * | RFC | [RFC1918] |
+ * | Allocation Date | February 1996 |
+ * | Termination Date | N/A |
+ * | Source | True |
+ * | Destination | True |
+ * | Forwardable | True |
+ * | Global | False |
+ * | Reserved-by-Protocol | False |
+ * +----------------------+---------------+ */
+ MustIPv4Addr("10.0.0.0/8"),
+
+ /*+----------------------+----------------------+
+ | Attribute | Value |
+ +----------------------+----------------------+
+ | Address Block | 100.64.0.0/10 |
+ | Name | Shared Address Space |
+ | RFC | [RFC6598] |
+ | Allocation Date | April 2012 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | True |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+----------------------+*/
+ MustIPv4Addr("100.64.0.0/10"),
+
+ /*+----------------------+----------------------------+
+ | Attribute | Value |
+ +----------------------+----------------------------+
+ | Address Block | 127.0.0.0/8 |
+ | Name | Loopback |
+ | RFC | [RFC1122], Section 3.2.1.3 |
+ | Allocation Date | September 1981 |
+ | Termination Date | N/A |
+ | Source | False [1] |
+ | Destination | False [1] |
+ | Forwardable | False [1] |
+ | Global | False [1] |
+ | Reserved-by-Protocol | True |
+ +----------------------+----------------------------+*/
+ // [1] Several protocols have been granted exceptions to
+ // this rule. For examples, see [RFC4379] and
+ // [RFC5884].
+ MustIPv4Addr("127.0.0.0/8"),
+
+ /*+----------------------+----------------+
+ | Attribute | Value |
+ +----------------------+----------------+
+ | Address Block | 169.254.0.0/16 |
+ | Name | Link Local |
+ | RFC | [RFC3927] |
+ | Allocation Date | May 2005 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | True |
+ +----------------------+----------------+*/
+ MustIPv4Addr("169.254.0.0/16"),
+
+ /*+----------------------+---------------+
+ | Attribute | Value |
+ +----------------------+---------------+
+ | Address Block | 172.16.0.0/12 |
+ | Name | Private-Use |
+ | RFC | [RFC1918] |
+ | Allocation Date | February 1996 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | True |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+---------------+*/
+ MustIPv4Addr("172.16.0.0/12"),
+
+ /*+----------------------+---------------------------------+
+ | Attribute | Value |
+ +----------------------+---------------------------------+
+ | Address Block | 192.0.0.0/24 [2] |
+ | Name | IETF Protocol Assignments |
+ | RFC | Section 2.1 of this document |
+ | Allocation Date | January 2010 |
+ | Termination Date | N/A |
+ | Source | False |
+ | Destination | False |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+---------------------------------+*/
+ // [2] Not usable unless by virtue of a more specific
+ // reservation.
+ MustIPv4Addr("192.0.0.0/24"),
+
+ /*+----------------------+--------------------------------+
+ | Attribute | Value |
+ +----------------------+--------------------------------+
+ | Address Block | 192.0.0.0/29 |
+ | Name | IPv4 Service Continuity Prefix |
+ | RFC | [RFC6333], [RFC7335] |
+ | Allocation Date | June 2011 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | True |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+--------------------------------+*/
+ MustIPv4Addr("192.0.0.0/29"),
+
+ /*+----------------------+----------------------------+
+ | Attribute | Value |
+ +----------------------+----------------------------+
+ | Address Block | 192.0.2.0/24 |
+ | Name | Documentation (TEST-NET-1) |
+ | RFC | [RFC5737] |
+ | Allocation Date | January 2010 |
+ | Termination Date | N/A |
+ | Source | False |
+ | Destination | False |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+----------------------------+*/
+ MustIPv4Addr("192.0.2.0/24"),
+
+ /*+----------------------+--------------------+
+ | Attribute | Value |
+ +----------------------+--------------------+
+ | Address Block | 192.88.99.0/24 |
+ | Name | 6to4 Relay Anycast |
+ | RFC | [RFC3068] |
+ | Allocation Date | June 2001 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | True |
+ | Global | True |
+ | Reserved-by-Protocol | False |
+ +----------------------+--------------------+*/
+ MustIPv4Addr("192.88.99.0/24"),
+
+ /*+----------------------+----------------+
+ | Attribute | Value |
+ +----------------------+----------------+
+ | Address Block | 192.168.0.0/16 |
+ | Name | Private-Use |
+ | RFC | [RFC1918] |
+ | Allocation Date | February 1996 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | True |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+----------------+*/
+ MustIPv4Addr("192.168.0.0/16"),
+
+ /*+----------------------+---------------+
+ | Attribute | Value |
+ +----------------------+---------------+
+ | Address Block | 198.18.0.0/15 |
+ | Name | Benchmarking |
+ | RFC | [RFC2544] |
+ | Allocation Date | March 1999 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | True |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+---------------+*/
+ MustIPv4Addr("198.18.0.0/15"),
+
+ /*+----------------------+----------------------------+
+ | Attribute | Value |
+ +----------------------+----------------------------+
+ | Address Block | 198.51.100.0/24 |
+ | Name | Documentation (TEST-NET-2) |
+ | RFC | [RFC5737] |
+ | Allocation Date | January 2010 |
+ | Termination Date | N/A |
+ | Source | False |
+ | Destination | False |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+----------------------------+*/
+ MustIPv4Addr("198.51.100.0/24"),
+
+ /*+----------------------+----------------------------+
+ | Attribute | Value |
+ +----------------------+----------------------------+
+ | Address Block | 203.0.113.0/24 |
+ | Name | Documentation (TEST-NET-3) |
+ | RFC | [RFC5737] |
+ | Allocation Date | January 2010 |
+ | Termination Date | N/A |
+ | Source | False |
+ | Destination | False |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+----------------------------+*/
+ MustIPv4Addr("203.0.113.0/24"),
+
+ /*+----------------------+----------------------+
+ | Attribute | Value |
+ +----------------------+----------------------+
+ | Address Block | 240.0.0.0/4 |
+ | Name | Reserved |
+ | RFC | [RFC1112], Section 4 |
+ | Allocation Date | August 1989 |
+ | Termination Date | N/A |
+ | Source | False |
+ | Destination | False |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | True |
+ +----------------------+----------------------+*/
+ MustIPv4Addr("240.0.0.0/4"),
+
+ /*+----------------------+----------------------+
+ | Attribute | Value |
+ +----------------------+----------------------+
+ | Address Block | 255.255.255.255/32 |
+ | Name | Limited Broadcast |
+ | RFC | [RFC0919], Section 7 |
+ | Allocation Date | October 1984 |
+ | Termination Date | N/A |
+ | Source | False |
+ | Destination | True |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+----------------------+*/
+ MustIPv4Addr("255.255.255.255/32"),
+
+ /*+----------------------+------------------+
+ | Attribute | Value |
+ +----------------------+------------------+
+ | Address Block | ::1/128 |
+ | Name | Loopback Address |
+ | RFC | [RFC4291] |
+ | Allocation Date | February 2006 |
+ | Termination Date | N/A |
+ | Source | False |
+ | Destination | False |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | True |
+ +----------------------+------------------+*/
+ MustIPv6Addr("::1/128"),
+
+ /*+----------------------+---------------------+
+ | Attribute | Value |
+ +----------------------+---------------------+
+ | Address Block | ::/128 |
+ | Name | Unspecified Address |
+ | RFC | [RFC4291] |
+ | Allocation Date | February 2006 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | False |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | True |
+ +----------------------+---------------------+*/
+ MustIPv6Addr("::/128"),
+
+ /*+----------------------+---------------------+
+ | Attribute | Value |
+ +----------------------+---------------------+
+ | Address Block | 64:ff9b::/96 |
+ | Name | IPv4-IPv6 Translat. |
+ | RFC | [RFC6052] |
+ | Allocation Date | October 2010 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | True |
+ | Global | True |
+ | Reserved-by-Protocol | False |
+ +----------------------+---------------------+*/
+ MustIPv6Addr("64:ff9b::/96"),
+
+ /*+----------------------+---------------------+
+ | Attribute | Value |
+ +----------------------+---------------------+
+ | Address Block | ::ffff:0:0/96 |
+ | Name | IPv4-mapped Address |
+ | RFC | [RFC4291] |
+ | Allocation Date | February 2006 |
+ | Termination Date | N/A |
+ | Source | False |
+ | Destination | False |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | True |
+ +----------------------+---------------------+*/
+ MustIPv6Addr("::ffff:0:0/96"),
+
+ /*+----------------------+----------------------------+
+ | Attribute | Value |
+ +----------------------+----------------------------+
+ | Address Block | 100::/64 |
+ | Name | Discard-Only Address Block |
+ | RFC | [RFC6666] |
+ | Allocation Date | June 2012 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | True |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+----------------------------+*/
+ MustIPv6Addr("100::/64"),
+
+ /*+----------------------+---------------------------+
+ | Attribute | Value |
+ +----------------------+---------------------------+
+ | Address Block | 2001::/23 |
+ | Name | IETF Protocol Assignments |
+ | RFC | [RFC2928] |
+ | Allocation Date | September 2000 |
+ | Termination Date | N/A |
+ | Source | False[1] |
+ | Destination | False[1] |
+ | Forwardable | False[1] |
+ | Global | False[1] |
+ | Reserved-by-Protocol | False |
+ +----------------------+---------------------------+*/
+ // [1] Unless allowed by a more specific allocation.
+ MustIPv6Addr("2001::/16"),
+
+ /*+----------------------+----------------+
+ | Attribute | Value |
+ +----------------------+----------------+
+ | Address Block | 2001::/32 |
+ | Name | TEREDO |
+ | RFC | [RFC4380] |
+ | Allocation Date | January 2006 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | True |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+----------------+*/
+ // Covered by previous entry, included for completeness.
+ //
+ // MustIPv6Addr("2001::/16"),
+
+ /*+----------------------+----------------+
+ | Attribute | Value |
+ +----------------------+----------------+
+ | Address Block | 2001:2::/48 |
+ | Name | Benchmarking |
+ | RFC | [RFC5180] |
+ | Allocation Date | April 2008 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | True |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+----------------+*/
+ // Covered by previous entry, included for completeness.
+ //
+ // MustIPv6Addr("2001:2::/48"),
+
+ /*+----------------------+---------------+
+ | Attribute | Value |
+ +----------------------+---------------+
+ | Address Block | 2001:db8::/32 |
+ | Name | Documentation |
+ | RFC | [RFC3849] |
+ | Allocation Date | July 2004 |
+ | Termination Date | N/A |
+ | Source | False |
+ | Destination | False |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+---------------+*/
+ // Covered by previous entry, included for completeness.
+ //
+ // MustIPv6Addr("2001:db8::/32"),
+
+ /*+----------------------+--------------+
+ | Attribute | Value |
+ +----------------------+--------------+
+ | Address Block | 2001:10::/28 |
+ | Name | ORCHID |
+ | RFC | [RFC4843] |
+ | Allocation Date | March 2007 |
+ | Termination Date | March 2014 |
+ | Source | False |
+ | Destination | False |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+--------------+*/
+ // Covered by previous entry, included for completeness.
+ //
+ // MustIPv6Addr("2001:10::/28"),
+
+ /*+----------------------+---------------+
+ | Attribute | Value |
+ +----------------------+---------------+
+ | Address Block | 2002::/16 [2] |
+ | Name | 6to4 |
+ | RFC | [RFC3056] |
+ | Allocation Date | February 2001 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | True |
+ | Global | N/A [2] |
+ | Reserved-by-Protocol | False |
+ +----------------------+---------------+*/
+ // [2] See [RFC3056] for details.
+ MustIPv6Addr("2002::/16"),
+
+ /*+----------------------+--------------+
+ | Attribute | Value |
+ +----------------------+--------------+
+ | Address Block | fc00::/7 |
+ | Name | Unique-Local |
+ | RFC | [RFC4193] |
+ | Allocation Date | October 2005 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | True |
+ | Global | False |
+ | Reserved-by-Protocol | False |
+ +----------------------+--------------+*/
+ MustIPv6Addr("fc00::/7"),
+
+ /*+----------------------+-----------------------+
+ | Attribute | Value |
+ +----------------------+-----------------------+
+ | Address Block | fe80::/10 |
+ | Name | Linked-Scoped Unicast |
+ | RFC | [RFC4291] |
+ | Allocation Date | February 2006 |
+ | Termination Date | N/A |
+ | Source | True |
+ | Destination | True |
+ | Forwardable | False |
+ | Global | False |
+ | Reserved-by-Protocol | True |
+ +----------------------+-----------------------+*/
+ MustIPv6Addr("fe80::/10"),
+ },
+ 7335: {
+ // [RFC7335] IPv4 Service Continuity Prefix
+ MustIPv4Addr("192.0.0.0/29"), // [RFC7335], §6 IANA Considerations
+ },
+ ForwardingBlacklist: { // Pseudo-RFC
+ // Blacklist of non-forwardable IP blocks taken from RFC6890
+ //
+ // TODO: the attributes for forwardable should be
+ // searcahble and embedded in the main list of RFCs
+ // above.
+ MustIPv4Addr("0.0.0.0/8"),
+ MustIPv4Addr("127.0.0.0/8"),
+ MustIPv4Addr("169.254.0.0/16"),
+ MustIPv4Addr("192.0.0.0/24"),
+ MustIPv4Addr("192.0.2.0/24"),
+ MustIPv4Addr("198.51.100.0/24"),
+ MustIPv4Addr("203.0.113.0/24"),
+ MustIPv4Addr("240.0.0.0/4"),
+ MustIPv4Addr("255.255.255.255/32"),
+ MustIPv6Addr("::1/128"),
+ MustIPv6Addr("::/128"),
+ MustIPv6Addr("::ffff:0:0/96"),
+
+ // There is no way of expressing a whitelist per RFC2928
+ // atm without creating a negative mask, which I don't
+ // want to do atm.
+ //MustIPv6Addr("2001::/23"),
+
+ MustIPv6Addr("2001:db8::/32"),
+ MustIPv6Addr("2001:10::/28"),
+ MustIPv6Addr("fe80::/10"),
+ },
+ }
+}
+
+// VisitAllRFCs iterates over all known RFCs and calls the visitor
+func VisitAllRFCs(fn func(rfcNum uint, sockaddrs SockAddrs)) {
+ rfcNetMap := KnownRFCs()
+
+ // Blacklist of faux-RFCs. Don't show the world that we're abusing the
+ // RFC system in this library.
+ rfcBlacklist := map[uint]struct{}{
+ ForwardingBlacklist: {},
+ }
+
+ for rfcNum, sas := range rfcNetMap {
+ if _, found := rfcBlacklist[rfcNum]; !found {
+ fn(rfcNum, sas)
+ }
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info.go b/vendor/github.com/hashicorp/go-sockaddr/route_info.go
new file mode 100644
index 00000000000..601a2b5838c
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/route_info.go
@@ -0,0 +1,30 @@
+package sockaddr
+
+import "errors"
+
+var (
+ ErrNoInterface = errors.New("No default interface found (unsupported platform)")
+ ErrNoRoute = errors.New("no route info found (unsupported platform)")
+)
+
+// RouteInterface specifies an interface for obtaining memoized route table and
+// network information from a given OS.
+type RouteInterface interface {
+ // GetDefaultInterfaceName returns the name of the interface that has a
+ // default route or an error and an empty string if a problem was
+ // encountered.
+ GetDefaultInterfaceName() (string, error)
+}
+
+type routeInfo struct {
+ cmds map[string][]string
+}
+
+// VisitCommands visits each command used by the platform-specific RouteInfo
+// implementation.
+func (ri routeInfo) VisitCommands(fn func(name string, cmd []string)) {
+ for k, v := range ri.cmds {
+ cmds := append([]string(nil), v...)
+ fn(k, cmds)
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_aix.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_aix.go
new file mode 100644
index 00000000000..4e23d9d4c6f
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_aix.go
@@ -0,0 +1,35 @@
+//go:build aix
+
+package sockaddr
+
+import (
+ "errors"
+ "os/exec"
+)
+
+var cmds map[string][]string = map[string][]string{
+ "route": {"/usr/sbin/route", "-n", "get", "default"},
+}
+
+// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
+// interface.
+func NewRouteInfo() (routeInfo, error) {
+ return routeInfo{
+ cmds: cmds,
+ }, nil
+}
+
+// GetDefaultInterfaceName returns the interface name attached to the default
+// route on the default interface.
+func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
+ out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output()
+ if err != nil {
+ return "", err
+ }
+
+ var ifName string
+ if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
+ return "", errors.New("No default interface found")
+ }
+ return ifName, nil
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_android.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_android.go
new file mode 100644
index 00000000000..059ddaebf67
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_android.go
@@ -0,0 +1,32 @@
+//go:build android
+
+package sockaddr
+
+import (
+ "errors"
+ "os/exec"
+)
+
+// NewRouteInfo returns a Android-specific implementation of the RouteInfo
+// interface.
+func NewRouteInfo() (routeInfo, error) {
+ return routeInfo{
+ cmds: map[string][]string{"ip": {"/system/bin/ip", "route", "get", "8.8.8.8"}},
+ }, nil
+}
+
+// GetDefaultInterfaceName returns the interface name attached to the default
+// route on the default interface.
+func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
+ out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output()
+ if err != nil {
+ return "", err
+ }
+
+
+ var ifName string
+ if ifName, err = parseDefaultIfNameFromIPCmdAndroid(string(out)); err != nil {
+ return "", errors.New("No default interface found")
+ }
+ return ifName, nil
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_bsd.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_bsd.go
new file mode 100644
index 00000000000..f5e548ac703
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_bsd.go
@@ -0,0 +1,33 @@
+//go:build darwin || dragonfly || freebsd || netbsd || openbsd
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package sockaddr
+
+import "os/exec"
+
+var cmds = map[string][]string{
+ "route": {"/sbin/route", "-n", "get", "default"},
+}
+
+// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
+// interface.
+func NewRouteInfo() (routeInfo, error) {
+ return routeInfo{
+ cmds: cmds,
+ }, nil
+}
+
+// GetDefaultInterfaceName returns the interface name attached to the default
+// route on the default interface.
+func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
+ out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output()
+ if err != nil {
+ return "", err
+ }
+
+ var ifName string
+ if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
+ return "", err
+ }
+ return ifName, nil
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_default.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_default.go
new file mode 100644
index 00000000000..db0052fa8fd
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_default.go
@@ -0,0 +1,19 @@
+//go:build nacl || plan9 || js
+// +build nacl plan9 js
+
+package sockaddr
+
+// getDefaultIfName is the default interface function for unsupported platforms.
+func getDefaultIfName() (string, error) {
+ return "", ErrNoInterface
+}
+
+func NewRouteInfo() (routeInfo, error) {
+ return routeInfo{}, ErrNoRoute
+}
+
+// GetDefaultInterfaceName returns the interface name attached to the default
+// route on the default interface.
+func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
+ return "", ErrNoInterface
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go
new file mode 100644
index 00000000000..cc5f68d0c83
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go
@@ -0,0 +1,39 @@
+//go:build !android
+// +build !android
+
+package sockaddr
+
+import (
+ "errors"
+ "os/exec"
+)
+
+// NewRouteInfo returns a Linux-specific implementation of the RouteInfo
+// interface.
+func NewRouteInfo() (routeInfo, error) {
+ // CoreOS Container Linux moved ip to /usr/bin/ip, so look it up on
+ // $PATH and fallback to /sbin/ip on error.
+ path, _ := exec.LookPath("ip")
+ if path == "" {
+ path = "/sbin/ip"
+ }
+
+ return routeInfo{
+ cmds: map[string][]string{"ip": {path, "route"}},
+ }, nil
+}
+
+// GetDefaultInterfaceName returns the interface name attached to the default
+// route on the default interface.
+func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
+ out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output()
+ if err != nil {
+ return "", err
+ }
+
+ var ifName string
+ if ifName, err = parseDefaultIfNameFromIPCmd(string(out)); err != nil {
+ return "", errors.New("No default interface found")
+ }
+ return ifName, nil
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_solaris.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_solaris.go
new file mode 100644
index 00000000000..1354a73b683
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_solaris.go
@@ -0,0 +1,35 @@
+//go:build solaris
+
+package sockaddr
+
+import (
+ "errors"
+ "os/exec"
+)
+
+var cmds map[string][]string = map[string][]string{
+ "route": {"/usr/sbin/route", "-n", "get", "default"},
+}
+
+// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
+// interface.
+func NewRouteInfo() (routeInfo, error) {
+ return routeInfo{
+ cmds: cmds,
+ }, nil
+}
+
+// GetDefaultInterfaceName returns the interface name attached to the default
+// route on the default interface.
+func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
+ out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output()
+ if err != nil {
+ return "", err
+ }
+
+ var ifName string
+ if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
+ return "", errors.New("No default interface found")
+ }
+ return ifName, nil
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_test_windows.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_test_windows.go
new file mode 100644
index 00000000000..a6eacdb2cf3
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_test_windows.go
@@ -0,0 +1,25 @@
+package sockaddr
+
+import "testing"
+
+func Test_parseWindowsDefaultIfName_new_vs_old(t *testing.T) {
+ if !hasPowershell() {
+ t.Skip("this test requires powershell.")
+ return
+ }
+ ri, err := NewRouteInfo()
+ if err != nil {
+ t.Fatalf("bad: %v", err)
+ }
+ psVer, err1 := ri.GetDefaultInterfaceName()
+ legacyVer, err2 := ri.GetDefaultInterfaceNameLegacy()
+ if err1 != nil {
+ t.Errorf("err != nil for GetDefaultInterfaceName - %v", err1)
+ }
+ if err2 != nil {
+ t.Errorf("err != nil for GetDefaultInterfaceNameLegacy - %v", err2)
+ }
+ if psVer != legacyVer {
+ t.Errorf("got %s; want %s", psVer, legacyVer)
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_windows.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_windows.go
new file mode 100644
index 00000000000..ed9bd0a3860
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_windows.go
@@ -0,0 +1,65 @@
+package sockaddr
+
+import (
+ "os/exec"
+ "strings"
+)
+
+var cmds map[string][]string = map[string][]string{
+ "defaultInterface": {"powershell", "Get-NetRoute -DestinationPrefix '0.0.0.0/0' | select -ExpandProperty InterfaceAlias"},
+ // These commands enable GetDefaultInterfaceNameLegacy and should be removed
+ // when it is.
+ "netstat": {"netstat", "-rn"},
+ "ipconfig": {"ipconfig"},
+}
+
+// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
+// interface.
+func NewRouteInfo() (routeInfo, error) {
+ return routeInfo{
+ cmds: cmds,
+ }, nil
+}
+
+// GetDefaultInterfaceName returns the interface name attached to the default
+// route on the default interface.
+func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
+ if !hasPowershell() {
+ // No powershell, fallback to legacy method
+ return ri.GetDefaultInterfaceNameLegacy()
+ }
+
+ ifNameOut, err := exec.Command(cmds["defaultInterface"][0], cmds["defaultInterface"][1:]...).Output()
+ if err != nil {
+ return "", err
+ }
+
+ ifName := strings.TrimSpace(string(ifNameOut[:]))
+ return ifName, nil
+}
+
+// GetDefaultInterfaceNameLegacy provides legacy behavior for GetDefaultInterfaceName
+// on Windows machines without powershell.
+func (ri routeInfo) GetDefaultInterfaceNameLegacy() (string, error) {
+ ifNameOut, err := exec.Command(cmds["netstat"][0], cmds["netstat"][1:]...).Output()
+ if err != nil {
+ return "", err
+ }
+
+ ipconfigOut, err := exec.Command(cmds["ipconfig"][0], cmds["ipconfig"][1:]...).Output()
+ if err != nil {
+ return "", err
+ }
+
+ ifName, err := parseDefaultIfNameWindows(string(ifNameOut), string(ipconfigOut))
+ if err != nil {
+ return "", err
+ }
+
+ return ifName, nil
+}
+
+func hasPowershell() bool {
+ _, err := exec.LookPath("powershell")
+ return (err != nil)
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go b/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go
new file mode 100644
index 00000000000..826c91c2e3d
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go
@@ -0,0 +1,206 @@
+package sockaddr
+
+import (
+ "encoding/json"
+ "fmt"
+ "strings"
+)
+
+type SockAddrType int
+type AttrName string
+
+const (
+ TypeUnknown SockAddrType = 0x0
+ TypeUnix = 0x1
+ TypeIPv4 = 0x2
+ TypeIPv6 = 0x4
+
+ // TypeIP is the union of TypeIPv4 and TypeIPv6
+ TypeIP = 0x6
+)
+
+type SockAddr interface {
+ // CmpRFC returns 0 if SockAddr exactly matches one of the matched RFC
+ // networks, -1 if the receiver is contained within the RFC network, or
+ // 1 if the address is not contained within the RFC.
+ CmpRFC(rfcNum uint, sa SockAddr) int
+
+ // Contains returns true if the SockAddr arg is contained within the
+ // receiver
+ Contains(SockAddr) bool
+
+ // Equal allows for the comparison of two SockAddrs
+ Equal(SockAddr) bool
+
+ DialPacketArgs() (string, string)
+ DialStreamArgs() (string, string)
+ ListenPacketArgs() (string, string)
+ ListenStreamArgs() (string, string)
+
+ // String returns the string representation of SockAddr
+ String() string
+
+ // Type returns the SockAddrType
+ Type() SockAddrType
+}
+
+// sockAddrAttrMap is a map of the SockAddr type-specific attributes.
+var sockAddrAttrMap map[AttrName]func(SockAddr) string
+var sockAddrAttrs []AttrName
+
+func init() {
+ sockAddrInit()
+}
+
+// New creates a new SockAddr from the string. The order in which New()
+// attempts to construct a SockAddr is: IPv4Addr, IPv6Addr, SockAddrUnix.
+//
+// NOTE: New() relies on the heuristic wherein if the path begins with either a
+// '.' or '/' character before creating a new UnixSock. For UNIX sockets that
+// are absolute paths or are nested within a sub-directory, this works as
+// expected, however if the UNIX socket is contained in the current working
+// directory, this will fail unless the path begins with "./"
+// (e.g. "./my-local-socket"). Calls directly to NewUnixSock() do not suffer
+// this limitation. Invalid IP addresses such as "256.0.0.0/-1" will run afoul
+// of this heuristic and be assumed to be a valid UNIX socket path (which they
+// are, but it is probably not what you want and you won't realize it until you
+// stat(2) the file system to discover it doesn't exist).
+func NewSockAddr(s string) (SockAddr, error) {
+ ipv4Addr, err := NewIPv4Addr(s)
+ if err == nil {
+ return ipv4Addr, nil
+ }
+
+ ipv6Addr, err := NewIPv6Addr(s)
+ if err == nil {
+ return ipv6Addr, nil
+ }
+
+ // Check to make sure the string begins with either a '.' or '/', or
+ // contains a '/'.
+ if len(s) > 1 && (strings.IndexAny(s[0:1], "./") != -1 || strings.IndexByte(s, '/') != -1) {
+ unixSock, err := NewUnixSock(s)
+ if err == nil {
+ return unixSock, nil
+ }
+ }
+
+ return nil, fmt.Errorf("Unable to convert %q to an IPv4 or IPv6 address, or a UNIX Socket", s)
+}
+
+// ToIPAddr returns an IPAddr type or nil if the type conversion fails.
+func ToIPAddr(sa SockAddr) *IPAddr {
+ ipa, ok := sa.(IPAddr)
+ if !ok {
+ return nil
+ }
+ return &ipa
+}
+
+// ToIPv4Addr returns an IPv4Addr type or nil if the type conversion fails.
+func ToIPv4Addr(sa SockAddr) *IPv4Addr {
+ switch v := sa.(type) {
+ case IPv4Addr:
+ return &v
+ default:
+ return nil
+ }
+}
+
+// ToIPv6Addr returns an IPv6Addr type or nil if the type conversion fails.
+func ToIPv6Addr(sa SockAddr) *IPv6Addr {
+ switch v := sa.(type) {
+ case IPv6Addr:
+ return &v
+ default:
+ return nil
+ }
+}
+
+// ToUnixSock returns a UnixSock type or nil if the type conversion fails.
+func ToUnixSock(sa SockAddr) *UnixSock {
+ switch v := sa.(type) {
+ case UnixSock:
+ return &v
+ default:
+ return nil
+ }
+}
+
+// SockAddrAttr returns a string representation of an attribute for the given
+// SockAddr.
+func SockAddrAttr(sa SockAddr, selector AttrName) string {
+ fn, found := sockAddrAttrMap[selector]
+ if !found {
+ return ""
+ }
+
+ return fn(sa)
+}
+
+// String() for SockAddrType returns a string representation of the
+// SockAddrType (e.g. "IPv4", "IPv6", "UNIX", "IP", or "unknown").
+func (sat SockAddrType) String() string {
+ switch sat {
+ case TypeIPv4:
+ return "IPv4"
+ case TypeIPv6:
+ return "IPv6"
+ // There is no concrete "IP" type. Leaving here as a reminder.
+ // case TypeIP:
+ // return "IP"
+ case TypeUnix:
+ return "UNIX"
+ default:
+ panic("unsupported type")
+ }
+}
+
+// sockAddrInit is called once at init()
+func sockAddrInit() {
+ sockAddrAttrs = []AttrName{
+ "type", // type should be first
+ "string",
+ }
+
+ sockAddrAttrMap = map[AttrName]func(sa SockAddr) string{
+ "string": func(sa SockAddr) string {
+ return sa.String()
+ },
+ "type": func(sa SockAddr) string {
+ return sa.Type().String()
+ },
+ }
+}
+
+// UnixSockAttrs returns a list of attributes supported by the UnixSock type
+func SockAddrAttrs() []AttrName {
+ return sockAddrAttrs
+}
+
+// Although this is pretty trivial to do in a program, having the logic here is
+// useful all around. Note that this marshals into a *string* -- the underlying
+// string representation of the sockaddr. If you then unmarshal into this type
+// in Go, all will work as expected, but externally you can take what comes out
+// and use the string value directly.
+type SockAddrMarshaler struct {
+ SockAddr
+}
+
+func (s *SockAddrMarshaler) MarshalJSON() ([]byte, error) {
+ return json.Marshal(s.SockAddr.String())
+}
+
+func (s *SockAddrMarshaler) UnmarshalJSON(in []byte) error {
+ var str string
+ err := json.Unmarshal(in, &str)
+ if err != nil {
+ return err
+ }
+ sa, err := NewSockAddr(str)
+ if err != nil {
+ return err
+ }
+ s.SockAddr = sa
+ return nil
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/sockaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/sockaddrs.go
new file mode 100644
index 00000000000..75fbffb1eab
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/sockaddrs.go
@@ -0,0 +1,193 @@
+package sockaddr
+
+import (
+ "bytes"
+ "sort"
+)
+
+// SockAddrs is a slice of SockAddrs
+type SockAddrs []SockAddr
+
+func (s SockAddrs) Len() int { return len(s) }
+func (s SockAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// CmpAddrFunc is the function signature that must be met to be used in the
+// OrderedAddrBy multiAddrSorter
+type CmpAddrFunc func(p1, p2 *SockAddr) int
+
+// multiAddrSorter implements the Sort interface, sorting the SockAddrs within.
+type multiAddrSorter struct {
+ addrs SockAddrs
+ cmp []CmpAddrFunc
+}
+
+// Sort sorts the argument slice according to the Cmp functions passed to
+// OrderedAddrBy.
+func (ms *multiAddrSorter) Sort(sockAddrs SockAddrs) {
+ ms.addrs = sockAddrs
+ sort.Sort(ms)
+}
+
+// OrderedAddrBy sorts SockAddr by the list of sort function pointers.
+func OrderedAddrBy(cmpFuncs ...CmpAddrFunc) *multiAddrSorter {
+ return &multiAddrSorter{
+ cmp: cmpFuncs,
+ }
+}
+
+// Len is part of sort.Interface.
+func (ms *multiAddrSorter) Len() int {
+ return len(ms.addrs)
+}
+
+// Less is part of sort.Interface. It is implemented by looping along the
+// Cmp() functions until it finds a comparison that is either less than,
+// equal to, or greater than.
+func (ms *multiAddrSorter) Less(i, j int) bool {
+ p, q := &ms.addrs[i], &ms.addrs[j]
+ // Try all but the last comparison.
+ var k int
+ for k = 0; k < len(ms.cmp)-1; k++ {
+ cmp := ms.cmp[k]
+ x := cmp(p, q)
+ switch x {
+ case -1:
+ // p < q, so we have a decision.
+ return true
+ case 1:
+ // p > q, so we have a decision.
+ return false
+ }
+ // p == q; try the next comparison.
+ }
+ // All comparisons to here said "equal", so just return whatever the
+ // final comparison reports.
+ switch ms.cmp[k](p, q) {
+ case -1:
+ return true
+ case 1:
+ return false
+ default:
+ // Still a tie! Now what?
+ return false
+ }
+}
+
+// Swap is part of sort.Interface.
+func (ms *multiAddrSorter) Swap(i, j int) {
+ ms.addrs[i], ms.addrs[j] = ms.addrs[j], ms.addrs[i]
+}
+
+const (
+ // NOTE (sean@): These constants are here for code readability only and
+ // are sprucing up the code for readability purposes. Some of the
+ // Cmp*() variants have confusing logic (especially when dealing with
+ // mixed-type comparisons) and this, I think, has made it easier to grok
+ // the code faster.
+ sortReceiverBeforeArg = -1
+ sortDeferDecision = 0
+ sortArgBeforeReceiver = 1
+)
+
+// AscAddress is a sorting function to sort SockAddrs by their respective
+// address type. Non-equal types are deferred in the sort.
+func AscAddress(p1Ptr, p2Ptr *SockAddr) int {
+ p1 := *p1Ptr
+ p2 := *p2Ptr
+
+ switch v := p1.(type) {
+ case IPv4Addr:
+ return v.CmpAddress(p2)
+ case IPv6Addr:
+ return v.CmpAddress(p2)
+ case UnixSock:
+ return v.CmpAddress(p2)
+ default:
+ return sortDeferDecision
+ }
+}
+
+// AscPort is a sorting function to sort SockAddrs by their respective address
+// type. Non-equal types are deferred in the sort.
+func AscPort(p1Ptr, p2Ptr *SockAddr) int {
+ p1 := *p1Ptr
+ p2 := *p2Ptr
+
+ switch v := p1.(type) {
+ case IPv4Addr:
+ return v.CmpPort(p2)
+ case IPv6Addr:
+ return v.CmpPort(p2)
+ default:
+ return sortDeferDecision
+ }
+}
+
+// AscPrivate is a sorting function to sort "more secure" private values before
+// "more public" values. Both IPv4 and IPv6 are compared against RFC6890
+// (RFC6890 includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and
+// IPv6 includes RFC4193).
+func AscPrivate(p1Ptr, p2Ptr *SockAddr) int {
+ p1 := *p1Ptr
+ p2 := *p2Ptr
+
+ switch v := p1.(type) {
+ case IPv4Addr, IPv6Addr:
+ return v.CmpRFC(6890, p2)
+ default:
+ return sortDeferDecision
+ }
+}
+
+// AscNetworkSize is a sorting function to sort SockAddrs based on their network
+// size. Non-equal types are deferred in the sort.
+func AscNetworkSize(p1Ptr, p2Ptr *SockAddr) int {
+ p1 := *p1Ptr
+ p2 := *p2Ptr
+ p1Type := p1.Type()
+ p2Type := p2.Type()
+
+ // Network size operations on non-IP types make no sense
+ if p1Type != p2Type && p1Type != TypeIP {
+ return sortDeferDecision
+ }
+
+ ipA := p1.(IPAddr)
+ ipB := p2.(IPAddr)
+
+ return bytes.Compare([]byte(*ipA.NetIPMask()), []byte(*ipB.NetIPMask()))
+}
+
+// AscType is a sorting function to sort "more secure" types before
+// "less-secure" types.
+func AscType(p1Ptr, p2Ptr *SockAddr) int {
+ p1 := *p1Ptr
+ p2 := *p2Ptr
+ p1Type := p1.Type()
+ p2Type := p2.Type()
+ switch {
+ case p1Type < p2Type:
+ return sortReceiverBeforeArg
+ case p1Type == p2Type:
+ return sortDeferDecision
+ case p1Type > p2Type:
+ return sortArgBeforeReceiver
+ default:
+ return sortDeferDecision
+ }
+}
+
+// FilterByType returns two lists: a list of matched and unmatched SockAddrs
+func (sas SockAddrs) FilterByType(type_ SockAddrType) (matched, excluded SockAddrs) {
+ matched = make(SockAddrs, 0, len(sas))
+ excluded = make(SockAddrs, 0, len(sas))
+
+ for _, sa := range sas {
+ if sa.Type()&type_ != 0 {
+ matched = append(matched, sa)
+ } else {
+ excluded = append(excluded, sa)
+ }
+ }
+ return matched, excluded
+}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/unixsock.go b/vendor/github.com/hashicorp/go-sockaddr/unixsock.go
new file mode 100644
index 00000000000..17aed98adf0
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-sockaddr/unixsock.go
@@ -0,0 +1,148 @@
+package sockaddr
+
+import (
+ "fmt"
+ "strings"
+)
+
+type UnixSock struct {
+ SockAddr
+ path string
+}
+type UnixSocks []*UnixSock
+
+// unixAttrMap is a map of the UnixSockAddr type-specific attributes.
+var unixAttrMap map[AttrName]func(UnixSock) string
+var unixAttrs []AttrName
+
+func init() {
+ unixAttrInit()
+}
+
+// NewUnixSock creates an UnixSock from a string path. String can be in the
+// form of either URI-based string (e.g. `file:///etc/passwd`), an absolute
+// path (e.g. `/etc/passwd`), or a relative path (e.g. `./foo`).
+func NewUnixSock(s string) (ret UnixSock, err error) {
+ ret.path = s
+ return ret, nil
+}
+
+// Contains returns true if sa and us have the same path
+func (us UnixSock) Contains(sa SockAddr) bool {
+ usb, ok := sa.(UnixSock)
+ if !ok {
+ return false
+ }
+
+ return usb.path == us.path
+}
+
+// CmpAddress follows the Cmp() standard protocol and returns:
+//
+// - -1 If the receiver should sort first because its name lexically sorts before arg
+// - 0 if the SockAddr arg is not a UnixSock, or is a UnixSock with the same path.
+// - 1 If the argument should sort first.
+func (us UnixSock) CmpAddress(sa SockAddr) int {
+ usb, ok := sa.(UnixSock)
+ if !ok {
+ return sortDeferDecision
+ }
+
+ return strings.Compare(us.Path(), usb.Path())
+}
+
+// CmpRFC doesn't make sense for a Unix socket, so just return defer decision
+func (us UnixSock) CmpRFC(rfcNum uint, sa SockAddr) int { return sortDeferDecision }
+
+// DialPacketArgs returns the arguments required to be passed to net.DialUnix()
+// with the `unixgram` network type.
+func (us UnixSock) DialPacketArgs() (network, dialArgs string) {
+ return "unixgram", us.path
+}
+
+// DialStreamArgs returns the arguments required to be passed to net.DialUnix()
+// with the `unix` network type.
+func (us UnixSock) DialStreamArgs() (network, dialArgs string) {
+ return "unix", us.path
+}
+
+// Equal returns true if a SockAddr is equal to the receiving UnixSock.
+func (us UnixSock) Equal(sa SockAddr) bool {
+ usb, ok := sa.(UnixSock)
+ if !ok {
+ return false
+ }
+
+ if us.Path() != usb.Path() {
+ return false
+ }
+
+ return true
+}
+
+// ListenPacketArgs returns the arguments required to be passed to
+// net.ListenUnixgram() with the `unixgram` network type.
+func (us UnixSock) ListenPacketArgs() (network, dialArgs string) {
+ return "unixgram", us.path
+}
+
+// ListenStreamArgs returns the arguments required to be passed to
+// net.ListenUnix() with the `unix` network type.
+func (us UnixSock) ListenStreamArgs() (network, dialArgs string) {
+ return "unix", us.path
+}
+
+// MustUnixSock is a helper method that must return an UnixSock or panic on
+// invalid input.
+func MustUnixSock(addr string) UnixSock {
+ us, err := NewUnixSock(addr)
+ if err != nil {
+ panic(fmt.Sprintf("Unable to create a UnixSock from %+q: %v", addr, err))
+ }
+ return us
+}
+
+// Path returns the given path of the UnixSock
+func (us UnixSock) Path() string {
+ return us.path
+}
+
+// String returns the path of the UnixSock
+func (us UnixSock) String() string {
+ return fmt.Sprintf("%+q", us.path)
+}
+
+// Type is used as a type switch and returns TypeUnix
+func (UnixSock) Type() SockAddrType {
+ return TypeUnix
+}
+
+// UnixSockAttrs returns a list of attributes supported by the UnixSockAddr type
+func UnixSockAttrs() []AttrName {
+ return unixAttrs
+}
+
+// UnixSockAttr returns a string representation of an attribute for the given
+// UnixSock.
+func UnixSockAttr(us UnixSock, attrName AttrName) string {
+ fn, found := unixAttrMap[attrName]
+ if !found {
+ return ""
+ }
+
+ return fn(us)
+}
+
+// unixAttrInit is called once at init()
+func unixAttrInit() {
+ // Sorted for human readability
+ unixAttrs = []AttrName{
+ "path",
+ }
+
+ unixAttrMap = map[AttrName]func(us UnixSock) string{
+ "path": func(us UnixSock) string {
+ return us.Path()
+ },
+ }
+}
diff --git a/vendor/github.com/hashicorp/golang-lru/LICENSE b/vendor/github.com/hashicorp/golang-lru/LICENSE
new file mode 100644
index 00000000000..0e5d580e0e9
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/LICENSE
@@ -0,0 +1,364 @@
+Copyright (c) 2014 HashiCorp, Inc.
+
+Mozilla Public License, version 2.0
+
+1. Definitions
+
+1.1. "Contributor"
+
+ means each individual or legal entity that creates, contributes to the
+ creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+
+ means the combination of the Contributions of others (if any) used by a
+ Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+
+ means Source Code Form to which the initial Contributor has attached the
+ notice in Exhibit A, the Executable Form of such Source Code Form, and
+ Modifications of such Source Code Form, in each case including portions
+ thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ a. that the initial Contributor has attached the notice described in
+ Exhibit B to the Covered Software; or
+
+ b. that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the terms of
+ a Secondary License.
+
+1.6. "Executable Form"
+
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+
+ means a work that combines Covered Software with other material, in a
+ separate file or files, that is not Covered Software.
+
+1.8. "License"
+
+ means this document.
+
+1.9. "Licensable"
+
+ means having the right to grant, to the maximum extent possible, whether
+ at the time of the initial grant or subsequently, any and all of the
+ rights conveyed by this License.
+
+1.10. "Modifications"
+
+ means any of the following:
+
+ a. any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered Software; or
+
+ b. any new file in Source Code Form that contains any Covered Software.
+
+1.11. "Patent Claims" of a Contributor
+
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the License,
+ by the making, using, selling, offering for sale, having made, import,
+ or transfer of either its Contributions or its Contributor Version.
+
+1.12. "Secondary License"
+
+ means either the GNU General Public License, Version 2.0, the GNU Lesser
+ General Public License, Version 2.1, the GNU Affero General Public
+ License, Version 3.0, or any later versions of those licenses.
+
+1.13. "Source Code Form"
+
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that controls, is
+ controlled by, or is under common control with You. For purposes of this
+ definition, "control" means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by contract or
+ otherwise, or (b) ownership of more than fifty percent (50%) of the
+ outstanding shares or beneficial ownership of such entity.
+
+
+2. License Grants and Conditions
+
+2.1. Grants
+
+ Each Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ a. under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+ b. under Patent Claims of such Contributor to make, use, sell, offer for
+ sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+ The licenses granted in Section 2.1 with respect to any Contribution
+ become effective for each Contribution on the date the Contributor first
+ distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+ The licenses granted in this Section 2 are the only rights granted under
+ this License. No additional rights or licenses will be implied from the
+ distribution or licensing of Covered Software under this License.
+ Notwithstanding Section 2.1(b) above, no patent license is granted by a
+ Contributor:
+
+ a. for any code that a Contributor has removed from Covered Software; or
+
+ b. for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+ c. under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+ This License does not grant any rights in the trademarks, service marks,
+ or logos of any Contributor (except as may be necessary to comply with
+ the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+ No Contributor makes additional grants as a result of Your choice to
+ distribute the Covered Software under a subsequent version of this
+ License (see Section 10.2) or under the terms of a Secondary License (if
+ permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+ Each Contributor represents that the Contributor believes its
+ Contributions are its original creation(s) or it has sufficient rights to
+ grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+ This License is not intended to limit any rights You have under
+ applicable copyright doctrines of fair use, fair dealing, or other
+ equivalents.
+
+2.7. Conditions
+
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+ Section 2.1.
+
+
+3. Responsibilities
+
+3.1. Distribution of Source Form
+
+ All distribution of Covered Software in Source Code Form, including any
+ Modifications that You create or to which You contribute, must be under
+ the terms of this License. You must inform recipients that the Source
+ Code Form of the Covered Software is governed by the terms of this
+ License, and how they can obtain a copy of this License. You may not
+ attempt to alter or restrict the recipients' rights in the Source Code
+ Form.
+
+3.2. Distribution of Executable Form
+
+ If You distribute Covered Software in Executable Form then:
+
+ a. such Covered Software must also be made available in Source Code Form,
+ as described in Section 3.1, and You must inform recipients of the
+ Executable Form how they can obtain a copy of such Source Code Form by
+ reasonable means in a timely manner, at a charge no more than the cost
+ of distribution to the recipient; and
+
+ b. You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter the
+ recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+ You may create and distribute a Larger Work under terms of Your choice,
+ provided that You also comply with the requirements of this License for
+ the Covered Software. If the Larger Work is a combination of Covered
+ Software with a work governed by one or more Secondary Licenses, and the
+ Covered Software is not Incompatible With Secondary Licenses, this
+ License permits You to additionally distribute such Covered Software
+ under the terms of such Secondary License(s), so that the recipient of
+ the Larger Work may, at their option, further distribute the Covered
+ Software under the terms of either this License or such Secondary
+ License(s).
+
+3.4. Notices
+
+ You may not remove or alter the substance of any license notices
+ (including copyright notices, patent notices, disclaimers of warranty, or
+ limitations of liability) contained within the Source Code Form of the
+ Covered Software, except that You may alter any license notices to the
+ extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+ You may choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of Covered
+ Software. However, You may do so only on Your own behalf, and not on
+ behalf of any Contributor. You must make it absolutely clear that any
+ such warranty, support, indemnity, or liability obligation is offered by
+ You alone, and You hereby agree to indemnify every Contributor for any
+ liability incurred by such Contributor as a result of warranty, support,
+ indemnity or liability terms You offer. You may include additional
+ disclaimers of warranty and limitations of liability specific to any
+ jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+
+ If it is impossible for You to comply with any of the terms of this License
+ with respect to some or all of the Covered Software due to statute,
+ judicial order, or regulation then You must: (a) comply with the terms of
+ this License to the maximum extent possible; and (b) describe the
+ limitations and the code they affect. Such description must be placed in a
+ text file included with all distributions of the Covered Software under
+ this License. Except to the extent prohibited by statute or regulation,
+ such description must be sufficiently detailed for a recipient of ordinary
+ skill to be able to understand it.
+
+5. Termination
+
+5.1. The rights granted under this License will terminate automatically if You
+ fail to comply with any of its terms. However, if You become compliant,
+ then the rights granted under this License from a particular Contributor
+ are reinstated (a) provisionally, unless and until such Contributor
+ explicitly and finally terminates Your grants, and (b) on an ongoing
+ basis, if such Contributor fails to notify You of the non-compliance by
+ some reasonable means prior to 60 days after You have come back into
+ compliance. Moreover, Your grants from a particular Contributor are
+ reinstated on an ongoing basis if such Contributor notifies You of the
+ non-compliance by some reasonable means, this is the first time You have
+ received notice of non-compliance with this License from such
+ Contributor, and You become compliant prior to 30 days after Your receipt
+ of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+ infringement claim (excluding declaratory judgment actions,
+ counter-claims, and cross-claims) alleging that a Contributor Version
+ directly or indirectly infringes any patent, then the rights granted to
+ You by any and all Contributors for the Covered Software under Section
+ 2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
+ license agreements (excluding distributors and resellers) which have been
+ validly granted by You or Your distributors under this License prior to
+ termination shall survive termination.
+
+6. Disclaimer of Warranty
+
+ Covered Software is provided under this License on an "as is" basis,
+ without warranty of any kind, either expressed, implied, or statutory,
+ including, without limitation, warranties that the Covered Software is free
+ of defects, merchantable, fit for a particular purpose or non-infringing.
+ The entire risk as to the quality and performance of the Covered Software
+ is with You. Should any Covered Software prove defective in any respect,
+ You (not any Contributor) assume the cost of any necessary servicing,
+ repair, or correction. This disclaimer of warranty constitutes an essential
+ part of this License. No use of any Covered Software is authorized under
+ this License except under this disclaimer.
+
+7. Limitation of Liability
+
+ Under no circumstances and under no legal theory, whether tort (including
+ negligence), contract, or otherwise, shall any Contributor, or anyone who
+ distributes Covered Software as permitted above, be liable to You for any
+ direct, indirect, special, incidental, or consequential damages of any
+ character including, without limitation, damages for lost profits, loss of
+ goodwill, work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses, even if such party shall have been
+ informed of the possibility of such damages. This limitation of liability
+ shall not apply to liability for death or personal injury resulting from
+ such party's negligence to the extent applicable law prohibits such
+ limitation. Some jurisdictions do not allow the exclusion or limitation of
+ incidental or consequential damages, so this exclusion and limitation may
+ not apply to You.
+
+8. Litigation
+
+ Any litigation relating to this License may be brought only in the courts
+ of a jurisdiction where the defendant maintains its principal place of
+ business and such litigation shall be governed by laws of that
+ jurisdiction, without reference to its conflict-of-law provisions. Nothing
+ in this Section shall prevent a party's ability to bring cross-claims or
+ counter-claims.
+
+9. Miscellaneous
+
+ This License represents the complete agreement concerning the subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. Any law or regulation which provides that
+ the language of a contract shall be construed against the drafter shall not
+ be used to construe this License against a Contributor.
+
+
+10. Versions of the License
+
+10.1. New Versions
+
+ Mozilla Foundation is the license steward. Except as provided in Section
+ 10.3, no one other than the license steward has the right to modify or
+ publish new versions of this License. Each version will be given a
+ distinguishing version number.
+
+10.2. Effect of New Versions
+
+ You may distribute the Covered Software under the terms of the version
+ of the License under which You originally received the Covered Software,
+ or under the terms of any subsequent version published by the license
+ steward.
+
+10.3. Modified Versions
+
+ If you create software not governed by this License, and you want to
+ create a new license for such software, you may create and use a
+ modified version of this License if you rename the license and remove
+ any references to the name of the license steward (except to note that
+ such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+ Licenses If You choose to distribute Source Code Form that is
+ Incompatible With Secondary Licenses under the terms of this version of
+ the License, the notice described in Exhibit B of this License must be
+ attached.
+
+Exhibit A - Source Code Form License Notice
+
+ This Source Code Form is subject to the
+ terms of the Mozilla Public License, v.
+ 2.0. If a copy of the MPL was not
+ distributed with this file, You can
+ obtain one at
+ http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular file,
+then You may include the notice in a location (such as a LICENSE file in a
+relevant directory) where a recipient would be likely to look for such a
+notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+
+ This Source Code Form is "Incompatible
+ With Secondary Licenses", as defined by
+ the Mozilla Public License, v. 2.0.
diff --git a/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go b/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go
new file mode 100644
index 00000000000..9233583c91c
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go
@@ -0,0 +1,177 @@
+package simplelru
+
+import (
+ "container/list"
+ "errors"
+)
+
+// EvictCallback is used to get a callback when a cache entry is evicted
+type EvictCallback func(key interface{}, value interface{})
+
+// LRU implements a non-thread safe fixed size LRU cache
+type LRU struct {
+ size int
+ evictList *list.List
+ items map[interface{}]*list.Element
+ onEvict EvictCallback
+}
+
+// entry is used to hold a value in the evictList
+type entry struct {
+ key interface{}
+ value interface{}
+}
+
+// NewLRU constructs an LRU of the given size
+func NewLRU(size int, onEvict EvictCallback) (*LRU, error) {
+ if size <= 0 {
+ return nil, errors.New("must provide a positive size")
+ }
+ c := &LRU{
+ size: size,
+ evictList: list.New(),
+ items: make(map[interface{}]*list.Element),
+ onEvict: onEvict,
+ }
+ return c, nil
+}
+
+// Purge is used to completely clear the cache.
+func (c *LRU) Purge() {
+ for k, v := range c.items {
+ if c.onEvict != nil {
+ c.onEvict(k, v.Value.(*entry).value)
+ }
+ delete(c.items, k)
+ }
+ c.evictList.Init()
+}
+
+// Add adds a value to the cache. Returns true if an eviction occurred.
+func (c *LRU) Add(key, value interface{}) (evicted bool) {
+ // Check for existing item
+ if ent, ok := c.items[key]; ok {
+ c.evictList.MoveToFront(ent)
+ ent.Value.(*entry).value = value
+ return false
+ }
+
+ // Add new item
+ ent := &entry{key, value}
+ entry := c.evictList.PushFront(ent)
+ c.items[key] = entry
+
+ evict := c.evictList.Len() > c.size
+ // Verify size not exceeded
+ if evict {
+ c.removeOldest()
+ }
+ return evict
+}
+
+// Get looks up a key's value from the cache.
+func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
+ if ent, ok := c.items[key]; ok {
+ c.evictList.MoveToFront(ent)
+ if ent.Value.(*entry) == nil {
+ return nil, false
+ }
+ return ent.Value.(*entry).value, true
+ }
+ return
+}
+
+// Contains checks if a key is in the cache, without updating the recent-ness
+// or deleting it for being stale.
+func (c *LRU) Contains(key interface{}) (ok bool) {
+ _, ok = c.items[key]
+ return ok
+}
+
+// Peek returns the key value (or undefined if not found) without updating
+// the "recently used"-ness of the key.
+func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
+ var ent *list.Element
+ if ent, ok = c.items[key]; ok {
+ return ent.Value.(*entry).value, true
+ }
+ return nil, ok
+}
+
+// Remove removes the provided key from the cache, returning if the
+// key was contained.
+func (c *LRU) Remove(key interface{}) (present bool) {
+ if ent, ok := c.items[key]; ok {
+ c.removeElement(ent)
+ return true
+ }
+ return false
+}
+
+// RemoveOldest removes the oldest item from the cache.
+func (c *LRU) RemoveOldest() (key, value interface{}, ok bool) {
+ ent := c.evictList.Back()
+ if ent != nil {
+ c.removeElement(ent)
+ kv := ent.Value.(*entry)
+ return kv.key, kv.value, true
+ }
+ return nil, nil, false
+}
+
+// GetOldest returns the oldest entry
+func (c *LRU) GetOldest() (key, value interface{}, ok bool) {
+ ent := c.evictList.Back()
+ if ent != nil {
+ kv := ent.Value.(*entry)
+ return kv.key, kv.value, true
+ }
+ return nil, nil, false
+}
+
+// Keys returns a slice of the keys in the cache, from oldest to newest.
+func (c *LRU) Keys() []interface{} {
+ keys := make([]interface{}, len(c.items))
+ i := 0
+ for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() {
+ keys[i] = ent.Value.(*entry).key
+ i++
+ }
+ return keys
+}
+
+// Len returns the number of items in the cache.
+func (c *LRU) Len() int {
+ return c.evictList.Len()
+}
+
+// Resize changes the cache size.
+func (c *LRU) Resize(size int) (evicted int) {
+ diff := c.Len() - size
+ if diff < 0 {
+ diff = 0
+ }
+ for i := 0; i < diff; i++ {
+ c.removeOldest()
+ }
+ c.size = size
+ return diff
+}
+
+// removeOldest removes the oldest item from the cache.
+func (c *LRU) removeOldest() {
+ ent := c.evictList.Back()
+ if ent != nil {
+ c.removeElement(ent)
+ }
+}
+
+// removeElement is used to remove a given list element from the cache
+func (c *LRU) removeElement(e *list.Element) {
+ c.evictList.Remove(e)
+ kv := e.Value.(*entry)
+ delete(c.items, kv.key)
+ if c.onEvict != nil {
+ c.onEvict(kv.key, kv.value)
+ }
+}
diff --git a/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go b/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go
new file mode 100644
index 00000000000..cb7f8caf03d
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go
@@ -0,0 +1,40 @@
+// Package simplelru provides simple LRU implementation based on build-in container/list.
+package simplelru
+
+// LRUCache is the interface for simple LRU cache.
+type LRUCache interface {
+ // Adds a value to the cache, returns true if an eviction occurred and
+ // updates the "recently used"-ness of the key.
+ Add(key, value interface{}) bool
+
+ // Returns key's value from the cache and
+ // updates the "recently used"-ness of the key. #value, isFound
+ Get(key interface{}) (value interface{}, ok bool)
+
+ // Checks if a key exists in cache without updating the recent-ness.
+ Contains(key interface{}) (ok bool)
+
+ // Returns key's value without updating the "recently used"-ness of the key.
+ Peek(key interface{}) (value interface{}, ok bool)
+
+ // Removes a key from the cache.
+ Remove(key interface{}) bool
+
+ // Removes the oldest entry from cache.
+ RemoveOldest() (interface{}, interface{}, bool)
+
+ // Returns the oldest entry from the cache. #key, value, isFound
+ GetOldest() (interface{}, interface{}, bool)
+
+ // Returns a slice of the keys in the cache, from oldest to newest.
+ Keys() []interface{}
+
+ // Returns the number of items in the cache.
+ Len() int
+
+ // Clears all cache entries.
+ Purge()
+
+ // Resizes cache, returning number evicted
+ Resize(int) int
+}
diff --git a/vendor/github.com/hashicorp/golang-lru/v2/.gitignore b/vendor/github.com/hashicorp/golang-lru/v2/.gitignore
new file mode 100644
index 00000000000..836562412fe
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/v2/.gitignore
@@ -0,0 +1,23 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
diff --git a/vendor/github.com/hashicorp/golang-lru/v2/.golangci.yml b/vendor/github.com/hashicorp/golang-lru/v2/.golangci.yml
new file mode 100644
index 00000000000..7e7b8a96275
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/v2/.golangci.yml
@@ -0,0 +1,46 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+linters:
+ fast: false
+ disable-all: true
+ enable:
+ - revive
+ - megacheck
+ - govet
+ - unconvert
+ - gas
+ - gocyclo
+ - dupl
+ - misspell
+ - unparam
+ - unused
+ - typecheck
+ - ineffassign
+ # - stylecheck
+ - exportloopref
+ - gocritic
+ - nakedret
+ - gosimple
+ - prealloc
+
+# golangci-lint configuration file
+linters-settings:
+ revive:
+ ignore-generated-header: true
+ severity: warning
+ rules:
+ - name: package-comments
+ severity: warning
+ disabled: true
+ - name: exported
+ severity: warning
+ disabled: false
+ arguments: ["checkPrivateReceivers", "disableStutteringCheck"]
+
+issues:
+ exclude-use-default: false
+ exclude-rules:
+ - path: _test\.go
+ linters:
+ - dupl
diff --git a/vendor/github.com/hashicorp/golang-lru/v2/2q.go b/vendor/github.com/hashicorp/golang-lru/v2/2q.go
new file mode 100644
index 00000000000..8c95252b6f2
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/v2/2q.go
@@ -0,0 +1,267 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package lru
+
+import (
+ "errors"
+ "sync"
+
+ "github.com/hashicorp/golang-lru/v2/simplelru"
+)
+
+const (
+ // Default2QRecentRatio is the ratio of the 2Q cache dedicated
+ // to recently added entries that have only been accessed once.
+ Default2QRecentRatio = 0.25
+
+ // Default2QGhostEntries is the default ratio of ghost
+ // entries kept to track entries recently evicted
+ Default2QGhostEntries = 0.50
+)
+
+// TwoQueueCache is a thread-safe fixed size 2Q cache.
+// 2Q is an enhancement over the standard LRU cache
+// in that it tracks both frequently and recently used
+// entries separately. This avoids a burst in access to new
+// entries from evicting frequently used entries. It adds some
+// additional tracking overhead to the standard LRU cache, and is
+// computationally about 2x the cost, and adds some metadata over
+// head. The ARCCache is similar, but does not require setting any
+// parameters.
+type TwoQueueCache[K comparable, V any] struct {
+ size int
+ recentSize int
+ recentRatio float64
+ ghostRatio float64
+
+ recent simplelru.LRUCache[K, V]
+ frequent simplelru.LRUCache[K, V]
+ recentEvict simplelru.LRUCache[K, struct{}]
+ lock sync.RWMutex
+}
+
+// New2Q creates a new TwoQueueCache using the default
+// values for the parameters.
+func New2Q[K comparable, V any](size int) (*TwoQueueCache[K, V], error) {
+ return New2QParams[K, V](size, Default2QRecentRatio, Default2QGhostEntries)
+}
+
+// New2QParams creates a new TwoQueueCache using the provided
+// parameter values.
+func New2QParams[K comparable, V any](size int, recentRatio, ghostRatio float64) (*TwoQueueCache[K, V], error) {
+ if size <= 0 {
+ return nil, errors.New("invalid size")
+ }
+ if recentRatio < 0.0 || recentRatio > 1.0 {
+ return nil, errors.New("invalid recent ratio")
+ }
+ if ghostRatio < 0.0 || ghostRatio > 1.0 {
+ return nil, errors.New("invalid ghost ratio")
+ }
+
+ // Determine the sub-sizes
+ recentSize := int(float64(size) * recentRatio)
+ evictSize := int(float64(size) * ghostRatio)
+
+ // Allocate the LRUs
+ recent, err := simplelru.NewLRU[K, V](size, nil)
+ if err != nil {
+ return nil, err
+ }
+ frequent, err := simplelru.NewLRU[K, V](size, nil)
+ if err != nil {
+ return nil, err
+ }
+ recentEvict, err := simplelru.NewLRU[K, struct{}](evictSize, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ // Initialize the cache
+ c := &TwoQueueCache[K, V]{
+ size: size,
+ recentSize: recentSize,
+ recentRatio: recentRatio,
+ ghostRatio: ghostRatio,
+ recent: recent,
+ frequent: frequent,
+ recentEvict: recentEvict,
+ }
+ return c, nil
+}
+
+// Get looks up a key's value from the cache.
+func (c *TwoQueueCache[K, V]) Get(key K) (value V, ok bool) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ // Check if this is a frequent value
+ if val, ok := c.frequent.Get(key); ok {
+ return val, ok
+ }
+
+ // If the value is contained in recent, then we
+ // promote it to frequent
+ if val, ok := c.recent.Peek(key); ok {
+ c.recent.Remove(key)
+ c.frequent.Add(key, val)
+ return val, ok
+ }
+
+ // No hit
+ return
+}
+
+// Add adds a value to the cache.
+func (c *TwoQueueCache[K, V]) Add(key K, value V) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ // Check if the value is frequently used already,
+ // and just update the value
+ if c.frequent.Contains(key) {
+ c.frequent.Add(key, value)
+ return
+ }
+
+ // Check if the value is recently used, and promote
+ // the value into the frequent list
+ if c.recent.Contains(key) {
+ c.recent.Remove(key)
+ c.frequent.Add(key, value)
+ return
+ }
+
+ // If the value was recently evicted, add it to the
+ // frequently used list
+ if c.recentEvict.Contains(key) {
+ c.ensureSpace(true)
+ c.recentEvict.Remove(key)
+ c.frequent.Add(key, value)
+ return
+ }
+
+ // Add to the recently seen list
+ c.ensureSpace(false)
+ c.recent.Add(key, value)
+}
+
+// ensureSpace is used to ensure we have space in the cache
+func (c *TwoQueueCache[K, V]) ensureSpace(recentEvict bool) {
+ // If we have space, nothing to do
+ recentLen := c.recent.Len()
+ freqLen := c.frequent.Len()
+ if recentLen+freqLen < c.size {
+ return
+ }
+
+ // If the recent buffer is larger than
+ // the target, evict from there
+ if recentLen > 0 && (recentLen > c.recentSize || (recentLen == c.recentSize && !recentEvict)) {
+ k, _, _ := c.recent.RemoveOldest()
+ c.recentEvict.Add(k, struct{}{})
+ return
+ }
+
+ // Remove from the frequent list otherwise
+ c.frequent.RemoveOldest()
+}
+
+// Len returns the number of items in the cache.
+func (c *TwoQueueCache[K, V]) Len() int {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ return c.recent.Len() + c.frequent.Len()
+}
+
+// Resize changes the cache size.
+func (c *TwoQueueCache[K, V]) Resize(size int) (evicted int) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ // Recalculate the sub-sizes
+ recentSize := int(float64(size) * c.recentRatio)
+ evictSize := int(float64(size) * c.ghostRatio)
+ c.size = size
+ c.recentSize = recentSize
+
+ // ensureSpace
+ diff := c.recent.Len() + c.frequent.Len() - size
+ if diff < 0 {
+ diff = 0
+ }
+ for i := 0; i < diff; i++ {
+ c.ensureSpace(true)
+ }
+
+ // Reallocate the LRUs
+ c.recent.Resize(size)
+ c.frequent.Resize(size)
+ c.recentEvict.Resize(evictSize)
+
+ return diff
+}
+
+// Keys returns a slice of the keys in the cache.
+// The frequently used keys are first in the returned slice.
+func (c *TwoQueueCache[K, V]) Keys() []K {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ k1 := c.frequent.Keys()
+ k2 := c.recent.Keys()
+ return append(k1, k2...)
+}
+
+// Values returns a slice of the values in the cache.
+// The frequently used values are first in the returned slice.
+func (c *TwoQueueCache[K, V]) Values() []V {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ v1 := c.frequent.Values()
+ v2 := c.recent.Values()
+ return append(v1, v2...)
+}
+
+// Remove removes the provided key from the cache.
+func (c *TwoQueueCache[K, V]) Remove(key K) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+ if c.frequent.Remove(key) {
+ return
+ }
+ if c.recent.Remove(key) {
+ return
+ }
+ if c.recentEvict.Remove(key) {
+ return
+ }
+}
+
+// Purge is used to completely clear the cache.
+func (c *TwoQueueCache[K, V]) Purge() {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+ c.recent.Purge()
+ c.frequent.Purge()
+ c.recentEvict.Purge()
+}
+
+// Contains is used to check if the cache contains a key
+// without updating recency or frequency.
+func (c *TwoQueueCache[K, V]) Contains(key K) bool {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ return c.frequent.Contains(key) || c.recent.Contains(key)
+}
+
+// Peek is used to inspect the cache value of a key
+// without updating recency or frequency.
+func (c *TwoQueueCache[K, V]) Peek(key K) (value V, ok bool) {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ if val, ok := c.frequent.Peek(key); ok {
+ return val, ok
+ }
+ return c.recent.Peek(key)
+}
diff --git a/vendor/github.com/hashicorp/golang-lru/v2/LICENSE b/vendor/github.com/hashicorp/golang-lru/v2/LICENSE
new file mode 100644
index 00000000000..0e5d580e0e9
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/v2/LICENSE
@@ -0,0 +1,364 @@
+Copyright (c) 2014 HashiCorp, Inc.
+
+Mozilla Public License, version 2.0
+
+1. Definitions
+
+1.1. "Contributor"
+
+ means each individual or legal entity that creates, contributes to the
+ creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+
+ means the combination of the Contributions of others (if any) used by a
+ Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+
+ means Source Code Form to which the initial Contributor has attached the
+ notice in Exhibit A, the Executable Form of such Source Code Form, and
+ Modifications of such Source Code Form, in each case including portions
+ thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ a. that the initial Contributor has attached the notice described in
+ Exhibit B to the Covered Software; or
+
+ b. that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the terms of
+ a Secondary License.
+
+1.6. "Executable Form"
+
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+
+ means a work that combines Covered Software with other material, in a
+ separate file or files, that is not Covered Software.
+
+1.8. "License"
+
+ means this document.
+
+1.9. "Licensable"
+
+ means having the right to grant, to the maximum extent possible, whether
+ at the time of the initial grant or subsequently, any and all of the
+ rights conveyed by this License.
+
+1.10. "Modifications"
+
+ means any of the following:
+
+ a. any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered Software; or
+
+ b. any new file in Source Code Form that contains any Covered Software.
+
+1.11. "Patent Claims" of a Contributor
+
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the License,
+ by the making, using, selling, offering for sale, having made, import,
+ or transfer of either its Contributions or its Contributor Version.
+
+1.12. "Secondary License"
+
+ means either the GNU General Public License, Version 2.0, the GNU Lesser
+ General Public License, Version 2.1, the GNU Affero General Public
+ License, Version 3.0, or any later versions of those licenses.
+
+1.13. "Source Code Form"
+
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that controls, is
+ controlled by, or is under common control with You. For purposes of this
+ definition, "control" means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by contract or
+ otherwise, or (b) ownership of more than fifty percent (50%) of the
+ outstanding shares or beneficial ownership of such entity.
+
+
+2. License Grants and Conditions
+
+2.1. Grants
+
+ Each Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ a. under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+ b. under Patent Claims of such Contributor to make, use, sell, offer for
+ sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+ The licenses granted in Section 2.1 with respect to any Contribution
+ become effective for each Contribution on the date the Contributor first
+ distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+ The licenses granted in this Section 2 are the only rights granted under
+ this License. No additional rights or licenses will be implied from the
+ distribution or licensing of Covered Software under this License.
+ Notwithstanding Section 2.1(b) above, no patent license is granted by a
+ Contributor:
+
+ a. for any code that a Contributor has removed from Covered Software; or
+
+ b. for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+ c. under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+ This License does not grant any rights in the trademarks, service marks,
+ or logos of any Contributor (except as may be necessary to comply with
+ the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+ No Contributor makes additional grants as a result of Your choice to
+ distribute the Covered Software under a subsequent version of this
+ License (see Section 10.2) or under the terms of a Secondary License (if
+ permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+ Each Contributor represents that the Contributor believes its
+ Contributions are its original creation(s) or it has sufficient rights to
+ grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+ This License is not intended to limit any rights You have under
+ applicable copyright doctrines of fair use, fair dealing, or other
+ equivalents.
+
+2.7. Conditions
+
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+ Section 2.1.
+
+
+3. Responsibilities
+
+3.1. Distribution of Source Form
+
+ All distribution of Covered Software in Source Code Form, including any
+ Modifications that You create or to which You contribute, must be under
+ the terms of this License. You must inform recipients that the Source
+ Code Form of the Covered Software is governed by the terms of this
+ License, and how they can obtain a copy of this License. You may not
+ attempt to alter or restrict the recipients' rights in the Source Code
+ Form.
+
+3.2. Distribution of Executable Form
+
+ If You distribute Covered Software in Executable Form then:
+
+ a. such Covered Software must also be made available in Source Code Form,
+ as described in Section 3.1, and You must inform recipients of the
+ Executable Form how they can obtain a copy of such Source Code Form by
+ reasonable means in a timely manner, at a charge no more than the cost
+ of distribution to the recipient; and
+
+ b. You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter the
+ recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+ You may create and distribute a Larger Work under terms of Your choice,
+ provided that You also comply with the requirements of this License for
+ the Covered Software. If the Larger Work is a combination of Covered
+ Software with a work governed by one or more Secondary Licenses, and the
+ Covered Software is not Incompatible With Secondary Licenses, this
+ License permits You to additionally distribute such Covered Software
+ under the terms of such Secondary License(s), so that the recipient of
+ the Larger Work may, at their option, further distribute the Covered
+ Software under the terms of either this License or such Secondary
+ License(s).
+
+3.4. Notices
+
+ You may not remove or alter the substance of any license notices
+ (including copyright notices, patent notices, disclaimers of warranty, or
+ limitations of liability) contained within the Source Code Form of the
+ Covered Software, except that You may alter any license notices to the
+ extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+ You may choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of Covered
+ Software. However, You may do so only on Your own behalf, and not on
+ behalf of any Contributor. You must make it absolutely clear that any
+ such warranty, support, indemnity, or liability obligation is offered by
+ You alone, and You hereby agree to indemnify every Contributor for any
+ liability incurred by such Contributor as a result of warranty, support,
+ indemnity or liability terms You offer. You may include additional
+ disclaimers of warranty and limitations of liability specific to any
+ jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+
+ If it is impossible for You to comply with any of the terms of this License
+ with respect to some or all of the Covered Software due to statute,
+ judicial order, or regulation then You must: (a) comply with the terms of
+ this License to the maximum extent possible; and (b) describe the
+ limitations and the code they affect. Such description must be placed in a
+ text file included with all distributions of the Covered Software under
+ this License. Except to the extent prohibited by statute or regulation,
+ such description must be sufficiently detailed for a recipient of ordinary
+ skill to be able to understand it.
+
+5. Termination
+
+5.1. The rights granted under this License will terminate automatically if You
+ fail to comply with any of its terms. However, if You become compliant,
+ then the rights granted under this License from a particular Contributor
+ are reinstated (a) provisionally, unless and until such Contributor
+ explicitly and finally terminates Your grants, and (b) on an ongoing
+ basis, if such Contributor fails to notify You of the non-compliance by
+ some reasonable means prior to 60 days after You have come back into
+ compliance. Moreover, Your grants from a particular Contributor are
+ reinstated on an ongoing basis if such Contributor notifies You of the
+ non-compliance by some reasonable means, this is the first time You have
+ received notice of non-compliance with this License from such
+ Contributor, and You become compliant prior to 30 days after Your receipt
+ of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+ infringement claim (excluding declaratory judgment actions,
+ counter-claims, and cross-claims) alleging that a Contributor Version
+ directly or indirectly infringes any patent, then the rights granted to
+ You by any and all Contributors for the Covered Software under Section
+ 2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
+ license agreements (excluding distributors and resellers) which have been
+ validly granted by You or Your distributors under this License prior to
+ termination shall survive termination.
+
+6. Disclaimer of Warranty
+
+ Covered Software is provided under this License on an "as is" basis,
+ without warranty of any kind, either expressed, implied, or statutory,
+ including, without limitation, warranties that the Covered Software is free
+ of defects, merchantable, fit for a particular purpose or non-infringing.
+ The entire risk as to the quality and performance of the Covered Software
+ is with You. Should any Covered Software prove defective in any respect,
+ You (not any Contributor) assume the cost of any necessary servicing,
+ repair, or correction. This disclaimer of warranty constitutes an essential
+ part of this License. No use of any Covered Software is authorized under
+ this License except under this disclaimer.
+
+7. Limitation of Liability
+
+ Under no circumstances and under no legal theory, whether tort (including
+ negligence), contract, or otherwise, shall any Contributor, or anyone who
+ distributes Covered Software as permitted above, be liable to You for any
+ direct, indirect, special, incidental, or consequential damages of any
+ character including, without limitation, damages for lost profits, loss of
+ goodwill, work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses, even if such party shall have been
+ informed of the possibility of such damages. This limitation of liability
+ shall not apply to liability for death or personal injury resulting from
+ such party's negligence to the extent applicable law prohibits such
+ limitation. Some jurisdictions do not allow the exclusion or limitation of
+ incidental or consequential damages, so this exclusion and limitation may
+ not apply to You.
+
+8. Litigation
+
+ Any litigation relating to this License may be brought only in the courts
+ of a jurisdiction where the defendant maintains its principal place of
+ business and such litigation shall be governed by laws of that
+ jurisdiction, without reference to its conflict-of-law provisions. Nothing
+ in this Section shall prevent a party's ability to bring cross-claims or
+ counter-claims.
+
+9. Miscellaneous
+
+ This License represents the complete agreement concerning the subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. Any law or regulation which provides that
+ the language of a contract shall be construed against the drafter shall not
+ be used to construe this License against a Contributor.
+
+
+10. Versions of the License
+
+10.1. New Versions
+
+ Mozilla Foundation is the license steward. Except as provided in Section
+ 10.3, no one other than the license steward has the right to modify or
+ publish new versions of this License. Each version will be given a
+ distinguishing version number.
+
+10.2. Effect of New Versions
+
+ You may distribute the Covered Software under the terms of the version
+ of the License under which You originally received the Covered Software,
+ or under the terms of any subsequent version published by the license
+ steward.
+
+10.3. Modified Versions
+
+ If you create software not governed by this License, and you want to
+ create a new license for such software, you may create and use a
+ modified version of this License if you rename the license and remove
+ any references to the name of the license steward (except to note that
+ such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+ Licenses If You choose to distribute Source Code Form that is
+ Incompatible With Secondary Licenses under the terms of this version of
+ the License, the notice described in Exhibit B of this License must be
+ attached.
+
+Exhibit A - Source Code Form License Notice
+
+ This Source Code Form is subject to the
+ terms of the Mozilla Public License, v.
+ 2.0. If a copy of the MPL was not
+ distributed with this file, You can
+ obtain one at
+ http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular file,
+then You may include the notice in a location (such as a LICENSE file in a
+relevant directory) where a recipient would be likely to look for such a
+notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+
+ This Source Code Form is "Incompatible
+ With Secondary Licenses", as defined by
+ the Mozilla Public License, v. 2.0.
diff --git a/vendor/github.com/hashicorp/golang-lru/v2/README.md b/vendor/github.com/hashicorp/golang-lru/v2/README.md
new file mode 100644
index 00000000000..a942eb53970
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/v2/README.md
@@ -0,0 +1,79 @@
+golang-lru
+==========
+
+This provides the `lru` package which implements a fixed-size
+thread safe LRU cache. It is based on the cache in Groupcache.
+
+Documentation
+=============
+
+Full docs are available on [Go Packages](https://pkg.go.dev/github.com/hashicorp/golang-lru/v2)
+
+LRU cache example
+=================
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/hashicorp/golang-lru/v2"
+)
+
+func main() {
+ l, _ := lru.New[int, any](128)
+ for i := 0; i < 256; i++ {
+ l.Add(i, nil)
+ }
+ if l.Len() != 128 {
+ panic(fmt.Sprintf("bad len: %v", l.Len()))
+ }
+}
+```
+
+Expirable LRU cache example
+===========================
+
+```go
+package main
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/hashicorp/golang-lru/v2/expirable"
+)
+
+func main() {
+ // make cache with 10ms TTL and 5 max keys
+ cache := expirable.NewLRU[string, string](5, nil, time.Millisecond*10)
+
+
+ // set value under key1.
+ cache.Add("key1", "val1")
+
+ // get value under key1
+ r, ok := cache.Get("key1")
+
+ // check for OK value
+ if ok {
+ fmt.Printf("value before expiration is found: %v, value: %q\n", ok, r)
+ }
+
+ // wait for cache to expire
+ time.Sleep(time.Millisecond * 12)
+
+ // get value under key1 after key expiration
+ r, ok = cache.Get("key1")
+ fmt.Printf("value after expiration is found: %v, value: %q\n", ok, r)
+
+ // set value under key2, would evict old entry because it is already expired.
+ cache.Add("key2", "val2")
+
+ fmt.Printf("Cache len: %d\n", cache.Len())
+ // Output:
+ // value before expiration is found: true, value: "val1"
+ // value after expiration is found: false, value: ""
+ // Cache len: 1
+}
+```
diff --git a/vendor/github.com/hashicorp/golang-lru/v2/doc.go b/vendor/github.com/hashicorp/golang-lru/v2/doc.go
new file mode 100644
index 00000000000..24107ee0ede
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/v2/doc.go
@@ -0,0 +1,24 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package lru provides three different LRU caches of varying sophistication.
+//
+// Cache is a simple LRU cache. It is based on the LRU implementation in
+// groupcache: https://github.com/golang/groupcache/tree/master/lru
+//
+// TwoQueueCache tracks frequently used and recently used entries separately.
+// This avoids a burst of accesses from taking out frequently used entries, at
+// the cost of about 2x computational overhead and some extra bookkeeping.
+//
+// ARCCache is an adaptive replacement cache. It tracks recent evictions as well
+// as recent usage in both the frequent and recent caches. Its computational
+// overhead is comparable to TwoQueueCache, but the memory overhead is linear
+// with the size of the cache.
+//
+// ARC has been patented by IBM, so do not use it if that is problematic for
+// your program. For this reason, it is in a separate go module contained within
+// this repository.
+//
+// All caches in this package take locks while operating, and are therefore
+// thread-safe for consumers.
+package lru
diff --git a/vendor/github.com/hashicorp/golang-lru/v2/internal/list.go b/vendor/github.com/hashicorp/golang-lru/v2/internal/list.go
new file mode 100644
index 00000000000..5cd74a03433
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/v2/internal/list.go
@@ -0,0 +1,142 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE_list file.
+
+package internal
+
+import "time"
+
+// Entry is an LRU Entry
+type Entry[K comparable, V any] struct {
+ // Next and previous pointers in the doubly-linked list of elements.
+ // To simplify the implementation, internally a list l is implemented
+ // as a ring, such that &l.root is both the next element of the last
+ // list element (l.Back()) and the previous element of the first list
+ // element (l.Front()).
+ next, prev *Entry[K, V]
+
+ // The list to which this element belongs.
+ list *LruList[K, V]
+
+ // The LRU Key of this element.
+ Key K
+
+ // The Value stored with this element.
+ Value V
+
+ // The time this element would be cleaned up, optional
+ ExpiresAt time.Time
+
+ // The expiry bucket item was put in, optional
+ ExpireBucket uint8
+}
+
+// PrevEntry returns the previous list element or nil.
+func (e *Entry[K, V]) PrevEntry() *Entry[K, V] {
+ if p := e.prev; e.list != nil && p != &e.list.root {
+ return p
+ }
+ return nil
+}
+
+// LruList represents a doubly linked list.
+// The zero Value for LruList is an empty list ready to use.
+type LruList[K comparable, V any] struct {
+ root Entry[K, V] // sentinel list element, only &root, root.prev, and root.next are used
+ len int // current list Length excluding (this) sentinel element
+}
+
+// Init initializes or clears list l.
+func (l *LruList[K, V]) Init() *LruList[K, V] {
+ l.root.next = &l.root
+ l.root.prev = &l.root
+ l.len = 0
+ return l
+}
+
+// NewList returns an initialized list.
+func NewList[K comparable, V any]() *LruList[K, V] { return new(LruList[K, V]).Init() }
+
+// Length returns the number of elements of list l.
+// The complexity is O(1).
+func (l *LruList[K, V]) Length() int { return l.len }
+
+// Back returns the last element of list l or nil if the list is empty.
+func (l *LruList[K, V]) Back() *Entry[K, V] {
+ if l.len == 0 {
+ return nil
+ }
+ return l.root.prev
+}
+
+// lazyInit lazily initializes a zero List Value.
+func (l *LruList[K, V]) lazyInit() {
+ if l.root.next == nil {
+ l.Init()
+ }
+}
+
+// insert inserts e after at, increments l.len, and returns e.
+func (l *LruList[K, V]) insert(e, at *Entry[K, V]) *Entry[K, V] {
+ e.prev = at
+ e.next = at.next
+ e.prev.next = e
+ e.next.prev = e
+ e.list = l
+ l.len++
+ return e
+}
+
+// insertValue is a convenience wrapper for insert(&Entry{Value: v, ExpiresAt: ExpiresAt}, at).
+func (l *LruList[K, V]) insertValue(k K, v V, expiresAt time.Time, at *Entry[K, V]) *Entry[K, V] {
+ return l.insert(&Entry[K, V]{Value: v, Key: k, ExpiresAt: expiresAt}, at)
+}
+
+// Remove removes e from its list, decrements l.len
+func (l *LruList[K, V]) Remove(e *Entry[K, V]) V {
+ e.prev.next = e.next
+ e.next.prev = e.prev
+ e.next = nil // avoid memory leaks
+ e.prev = nil // avoid memory leaks
+ e.list = nil
+ l.len--
+
+ return e.Value
+}
+
+// move moves e to next to at.
+func (l *LruList[K, V]) move(e, at *Entry[K, V]) {
+ if e == at {
+ return
+ }
+ e.prev.next = e.next
+ e.next.prev = e.prev
+
+ e.prev = at
+ e.next = at.next
+ e.prev.next = e
+ e.next.prev = e
+}
+
+// PushFront inserts a new element e with value v at the front of list l and returns e.
+func (l *LruList[K, V]) PushFront(k K, v V) *Entry[K, V] {
+ l.lazyInit()
+ return l.insertValue(k, v, time.Time{}, &l.root)
+}
+
+// PushFrontExpirable inserts a new expirable element e with Value v at the front of list l and returns e.
+func (l *LruList[K, V]) PushFrontExpirable(k K, v V, expiresAt time.Time) *Entry[K, V] {
+ l.lazyInit()
+ return l.insertValue(k, v, expiresAt, &l.root)
+}
+
+// MoveToFront moves element e to the front of list l.
+// If e is not an element of l, the list is not modified.
+// The element must not be nil.
+func (l *LruList[K, V]) MoveToFront(e *Entry[K, V]) {
+ if e.list != l || l.root.next == e {
+ return
+ }
+ // see comment in List.Remove about initialization of l
+ l.move(e, &l.root)
+}
diff --git a/vendor/github.com/hashicorp/golang-lru/v2/lru.go b/vendor/github.com/hashicorp/golang-lru/v2/lru.go
new file mode 100644
index 00000000000..a2655f1f310
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/v2/lru.go
@@ -0,0 +1,250 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package lru
+
+import (
+ "sync"
+
+ "github.com/hashicorp/golang-lru/v2/simplelru"
+)
+
+const (
+ // DefaultEvictedBufferSize defines the default buffer size to store evicted key/val
+ DefaultEvictedBufferSize = 16
+)
+
+// Cache is a thread-safe fixed size LRU cache.
+type Cache[K comparable, V any] struct {
+ lru *simplelru.LRU[K, V]
+ evictedKeys []K
+ evictedVals []V
+ onEvictedCB func(k K, v V)
+ lock sync.RWMutex
+}
+
+// New creates an LRU of the given size.
+func New[K comparable, V any](size int) (*Cache[K, V], error) {
+ return NewWithEvict[K, V](size, nil)
+}
+
+// NewWithEvict constructs a fixed size cache with the given eviction
+// callback.
+func NewWithEvict[K comparable, V any](size int, onEvicted func(key K, value V)) (c *Cache[K, V], err error) {
+ // create a cache with default settings
+ c = &Cache[K, V]{
+ onEvictedCB: onEvicted,
+ }
+ if onEvicted != nil {
+ c.initEvictBuffers()
+ onEvicted = c.onEvicted
+ }
+ c.lru, err = simplelru.NewLRU(size, onEvicted)
+ return
+}
+
+func (c *Cache[K, V]) initEvictBuffers() {
+ c.evictedKeys = make([]K, 0, DefaultEvictedBufferSize)
+ c.evictedVals = make([]V, 0, DefaultEvictedBufferSize)
+}
+
+// onEvicted save evicted key/val and sent in externally registered callback
+// outside of critical section
+func (c *Cache[K, V]) onEvicted(k K, v V) {
+ c.evictedKeys = append(c.evictedKeys, k)
+ c.evictedVals = append(c.evictedVals, v)
+}
+
+// Purge is used to completely clear the cache.
+func (c *Cache[K, V]) Purge() {
+ var ks []K
+ var vs []V
+ c.lock.Lock()
+ c.lru.Purge()
+ if c.onEvictedCB != nil && len(c.evictedKeys) > 0 {
+ ks, vs = c.evictedKeys, c.evictedVals
+ c.initEvictBuffers()
+ }
+ c.lock.Unlock()
+ // invoke callback outside of critical section
+ if c.onEvictedCB != nil {
+ for i := 0; i < len(ks); i++ {
+ c.onEvictedCB(ks[i], vs[i])
+ }
+ }
+}
+
+// Add adds a value to the cache. Returns true if an eviction occurred.
+func (c *Cache[K, V]) Add(key K, value V) (evicted bool) {
+ var k K
+ var v V
+ c.lock.Lock()
+ evicted = c.lru.Add(key, value)
+ if c.onEvictedCB != nil && evicted {
+ k, v = c.evictedKeys[0], c.evictedVals[0]
+ c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
+ }
+ c.lock.Unlock()
+ if c.onEvictedCB != nil && evicted {
+ c.onEvictedCB(k, v)
+ }
+ return
+}
+
+// Get looks up a key's value from the cache.
+func (c *Cache[K, V]) Get(key K) (value V, ok bool) {
+ c.lock.Lock()
+ value, ok = c.lru.Get(key)
+ c.lock.Unlock()
+ return value, ok
+}
+
+// Contains checks if a key is in the cache, without updating the
+// recent-ness or deleting it for being stale.
+func (c *Cache[K, V]) Contains(key K) bool {
+ c.lock.RLock()
+ containKey := c.lru.Contains(key)
+ c.lock.RUnlock()
+ return containKey
+}
+
+// Peek returns the key value (or undefined if not found) without updating
+// the "recently used"-ness of the key.
+func (c *Cache[K, V]) Peek(key K) (value V, ok bool) {
+ c.lock.RLock()
+ value, ok = c.lru.Peek(key)
+ c.lock.RUnlock()
+ return value, ok
+}
+
+// ContainsOrAdd checks if a key is in the cache without updating the
+// recent-ness or deleting it for being stale, and if not, adds the value.
+// Returns whether found and whether an eviction occurred.
+func (c *Cache[K, V]) ContainsOrAdd(key K, value V) (ok, evicted bool) {
+ var k K
+ var v V
+ c.lock.Lock()
+ if c.lru.Contains(key) {
+ c.lock.Unlock()
+ return true, false
+ }
+ evicted = c.lru.Add(key, value)
+ if c.onEvictedCB != nil && evicted {
+ k, v = c.evictedKeys[0], c.evictedVals[0]
+ c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
+ }
+ c.lock.Unlock()
+ if c.onEvictedCB != nil && evicted {
+ c.onEvictedCB(k, v)
+ }
+ return false, evicted
+}
+
+// PeekOrAdd checks if a key is in the cache without updating the
+// recent-ness or deleting it for being stale, and if not, adds the value.
+// Returns whether found and whether an eviction occurred.
+func (c *Cache[K, V]) PeekOrAdd(key K, value V) (previous V, ok, evicted bool) {
+ var k K
+ var v V
+ c.lock.Lock()
+ previous, ok = c.lru.Peek(key)
+ if ok {
+ c.lock.Unlock()
+ return previous, true, false
+ }
+ evicted = c.lru.Add(key, value)
+ if c.onEvictedCB != nil && evicted {
+ k, v = c.evictedKeys[0], c.evictedVals[0]
+ c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
+ }
+ c.lock.Unlock()
+ if c.onEvictedCB != nil && evicted {
+ c.onEvictedCB(k, v)
+ }
+ return
+}
+
+// Remove removes the provided key from the cache.
+func (c *Cache[K, V]) Remove(key K) (present bool) {
+ var k K
+ var v V
+ c.lock.Lock()
+ present = c.lru.Remove(key)
+ if c.onEvictedCB != nil && present {
+ k, v = c.evictedKeys[0], c.evictedVals[0]
+ c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
+ }
+ c.lock.Unlock()
+ if c.onEvictedCB != nil && present {
+ c.onEvictedCB(k, v)
+ }
+ return
+}
+
+// Resize changes the cache size.
+func (c *Cache[K, V]) Resize(size int) (evicted int) {
+ var ks []K
+ var vs []V
+ c.lock.Lock()
+ evicted = c.lru.Resize(size)
+ if c.onEvictedCB != nil && evicted > 0 {
+ ks, vs = c.evictedKeys, c.evictedVals
+ c.initEvictBuffers()
+ }
+ c.lock.Unlock()
+ if c.onEvictedCB != nil && evicted > 0 {
+ for i := 0; i < len(ks); i++ {
+ c.onEvictedCB(ks[i], vs[i])
+ }
+ }
+ return evicted
+}
+
+// RemoveOldest removes the oldest item from the cache.
+func (c *Cache[K, V]) RemoveOldest() (key K, value V, ok bool) {
+ var k K
+ var v V
+ c.lock.Lock()
+ key, value, ok = c.lru.RemoveOldest()
+ if c.onEvictedCB != nil && ok {
+ k, v = c.evictedKeys[0], c.evictedVals[0]
+ c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
+ }
+ c.lock.Unlock()
+ if c.onEvictedCB != nil && ok {
+ c.onEvictedCB(k, v)
+ }
+ return
+}
+
+// GetOldest returns the oldest entry
+func (c *Cache[K, V]) GetOldest() (key K, value V, ok bool) {
+ c.lock.RLock()
+ key, value, ok = c.lru.GetOldest()
+ c.lock.RUnlock()
+ return
+}
+
+// Keys returns a slice of the keys in the cache, from oldest to newest.
+func (c *Cache[K, V]) Keys() []K {
+ c.lock.RLock()
+ keys := c.lru.Keys()
+ c.lock.RUnlock()
+ return keys
+}
+
+// Values returns a slice of the values in the cache, from oldest to newest.
+func (c *Cache[K, V]) Values() []V {
+ c.lock.RLock()
+ values := c.lru.Values()
+ c.lock.RUnlock()
+ return values
+}
+
+// Len returns the number of items in the cache.
+func (c *Cache[K, V]) Len() int {
+ c.lock.RLock()
+ length := c.lru.Len()
+ c.lock.RUnlock()
+ return length
+}
diff --git a/vendor/github.com/hashicorp/golang-lru/v2/simplelru/LICENSE_list b/vendor/github.com/hashicorp/golang-lru/v2/simplelru/LICENSE_list
new file mode 100644
index 00000000000..c4764e6b2f0
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/v2/simplelru/LICENSE_list
@@ -0,0 +1,29 @@
+This license applies to simplelru/list.go
+
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru.go b/vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru.go
new file mode 100644
index 00000000000..f69792388c1
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru.go
@@ -0,0 +1,177 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package simplelru
+
+import (
+ "errors"
+
+ "github.com/hashicorp/golang-lru/v2/internal"
+)
+
+// EvictCallback is used to get a callback when a cache entry is evicted
+type EvictCallback[K comparable, V any] func(key K, value V)
+
+// LRU implements a non-thread safe fixed size LRU cache
+type LRU[K comparable, V any] struct {
+ size int
+ evictList *internal.LruList[K, V]
+ items map[K]*internal.Entry[K, V]
+ onEvict EvictCallback[K, V]
+}
+
+// NewLRU constructs an LRU of the given size
+func NewLRU[K comparable, V any](size int, onEvict EvictCallback[K, V]) (*LRU[K, V], error) {
+ if size <= 0 {
+ return nil, errors.New("must provide a positive size")
+ }
+
+ c := &LRU[K, V]{
+ size: size,
+ evictList: internal.NewList[K, V](),
+ items: make(map[K]*internal.Entry[K, V]),
+ onEvict: onEvict,
+ }
+ return c, nil
+}
+
+// Purge is used to completely clear the cache.
+func (c *LRU[K, V]) Purge() {
+ for k, v := range c.items {
+ if c.onEvict != nil {
+ c.onEvict(k, v.Value)
+ }
+ delete(c.items, k)
+ }
+ c.evictList.Init()
+}
+
+// Add adds a value to the cache. Returns true if an eviction occurred.
+func (c *LRU[K, V]) Add(key K, value V) (evicted bool) {
+ // Check for existing item
+ if ent, ok := c.items[key]; ok {
+ c.evictList.MoveToFront(ent)
+ ent.Value = value
+ return false
+ }
+
+ // Add new item
+ ent := c.evictList.PushFront(key, value)
+ c.items[key] = ent
+
+ evict := c.evictList.Length() > c.size
+ // Verify size not exceeded
+ if evict {
+ c.removeOldest()
+ }
+ return evict
+}
+
+// Get looks up a key's value from the cache.
+func (c *LRU[K, V]) Get(key K) (value V, ok bool) {
+ if ent, ok := c.items[key]; ok {
+ c.evictList.MoveToFront(ent)
+ return ent.Value, true
+ }
+ return
+}
+
+// Contains checks if a key is in the cache, without updating the recent-ness
+// or deleting it for being stale.
+func (c *LRU[K, V]) Contains(key K) (ok bool) {
+ _, ok = c.items[key]
+ return ok
+}
+
+// Peek returns the key value (or undefined if not found) without updating
+// the "recently used"-ness of the key.
+func (c *LRU[K, V]) Peek(key K) (value V, ok bool) {
+ var ent *internal.Entry[K, V]
+ if ent, ok = c.items[key]; ok {
+ return ent.Value, true
+ }
+ return
+}
+
+// Remove removes the provided key from the cache, returning if the
+// key was contained.
+func (c *LRU[K, V]) Remove(key K) (present bool) {
+ if ent, ok := c.items[key]; ok {
+ c.removeElement(ent)
+ return true
+ }
+ return false
+}
+
+// RemoveOldest removes the oldest item from the cache.
+func (c *LRU[K, V]) RemoveOldest() (key K, value V, ok bool) {
+ if ent := c.evictList.Back(); ent != nil {
+ c.removeElement(ent)
+ return ent.Key, ent.Value, true
+ }
+ return
+}
+
+// GetOldest returns the oldest entry
+func (c *LRU[K, V]) GetOldest() (key K, value V, ok bool) {
+ if ent := c.evictList.Back(); ent != nil {
+ return ent.Key, ent.Value, true
+ }
+ return
+}
+
+// Keys returns a slice of the keys in the cache, from oldest to newest.
+func (c *LRU[K, V]) Keys() []K {
+ keys := make([]K, c.evictList.Length())
+ i := 0
+ for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() {
+ keys[i] = ent.Key
+ i++
+ }
+ return keys
+}
+
+// Values returns a slice of the values in the cache, from oldest to newest.
+func (c *LRU[K, V]) Values() []V {
+ values := make([]V, len(c.items))
+ i := 0
+ for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() {
+ values[i] = ent.Value
+ i++
+ }
+ return values
+}
+
+// Len returns the number of items in the cache.
+func (c *LRU[K, V]) Len() int {
+ return c.evictList.Length()
+}
+
+// Resize changes the cache size.
+func (c *LRU[K, V]) Resize(size int) (evicted int) {
+ diff := c.Len() - size
+ if diff < 0 {
+ diff = 0
+ }
+ for i := 0; i < diff; i++ {
+ c.removeOldest()
+ }
+ c.size = size
+ return diff
+}
+
+// removeOldest removes the oldest item from the cache.
+func (c *LRU[K, V]) removeOldest() {
+ if ent := c.evictList.Back(); ent != nil {
+ c.removeElement(ent)
+ }
+}
+
+// removeElement is used to remove a given list element from the cache
+func (c *LRU[K, V]) removeElement(e *internal.Entry[K, V]) {
+ c.evictList.Remove(e)
+ delete(c.items, e.Key)
+ if c.onEvict != nil {
+ c.onEvict(e.Key, e.Value)
+ }
+}
diff --git a/vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru_interface.go b/vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru_interface.go
new file mode 100644
index 00000000000..043b8bcc3f3
--- /dev/null
+++ b/vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru_interface.go
@@ -0,0 +1,46 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package simplelru provides simple LRU implementation based on build-in container/list.
+package simplelru
+
+// LRUCache is the interface for simple LRU cache.
+type LRUCache[K comparable, V any] interface {
+ // Adds a value to the cache, returns true if an eviction occurred and
+ // updates the "recently used"-ness of the key.
+ Add(key K, value V) bool
+
+ // Returns key's value from the cache and
+ // updates the "recently used"-ness of the key. #value, isFound
+ Get(key K) (value V, ok bool)
+
+ // Checks if a key exists in cache without updating the recent-ness.
+ Contains(key K) (ok bool)
+
+ // Returns key's value without updating the "recently used"-ness of the key.
+ Peek(key K) (value V, ok bool)
+
+ // Removes a key from the cache.
+ Remove(key K) bool
+
+ // Removes the oldest entry from cache.
+ RemoveOldest() (K, V, bool)
+
+ // Returns the oldest entry from the cache. #key, value, isFound
+ GetOldest() (K, V, bool)
+
+ // Returns a slice of the keys in the cache, from oldest to newest.
+ Keys() []K
+
+ // Values returns a slice of the values in the cache, from oldest to newest.
+ Values() []V
+
+ // Returns the number of items in the cache.
+ Len() int
+
+ // Clears all cache entries.
+ Purge()
+
+ // Resizes cache, returning number evicted
+ Resize(int) int
+}
diff --git a/vendor/github.com/hashicorp/memberlist/.gitignore b/vendor/github.com/hashicorp/memberlist/.gitignore
new file mode 100644
index 00000000000..9158f171a5f
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/.gitignore
@@ -0,0 +1,25 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+.vagrant/
+
diff --git a/vendor/github.com/hashicorp/memberlist/.go-version b/vendor/github.com/hashicorp/memberlist/.go-version
new file mode 100644
index 00000000000..5fb5a6b4f54
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/.go-version
@@ -0,0 +1 @@
+1.20
diff --git a/vendor/github.com/hashicorp/memberlist/.golangci.yml b/vendor/github.com/hashicorp/memberlist/.golangci.yml
new file mode 100644
index 00000000000..0c5e79636d2
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/.golangci.yml
@@ -0,0 +1,11 @@
+# Copyright IBM Corp. 2013, 2025
+# SPDX-License-Identifier: MPL-2.0
+
+version: "2"
+issues:
+ max-issues-per-linter: 0
+ max-same-issues: 0
+
+run:
+ timeout: 10m
+ concurrency: 4
diff --git a/vendor/github.com/hashicorp/memberlist/CHANGELOG.md b/vendor/github.com/hashicorp/memberlist/CHANGELOG.md
new file mode 100644
index 00000000000..a0b285324bd
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/CHANGELOG.md
@@ -0,0 +1,9 @@
+## Unreleased
+
+### Improvements
+
+### Changes
+
+### Fixed
+
+### Security
diff --git a/vendor/github.com/hashicorp/memberlist/LICENSE b/vendor/github.com/hashicorp/memberlist/LICENSE
new file mode 100644
index 00000000000..e3ff754c93b
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/LICENSE
@@ -0,0 +1,356 @@
+Copyright IBM Corp. 2013, 2025
+
+Mozilla Public License, version 2.0
+
+1. Definitions
+
+1.1. “Contributor”
+
+ means each individual or legal entity that creates, contributes to the
+ creation of, or owns Covered Software.
+
+1.2. “Contributor Version”
+
+ means the combination of the Contributions of others (if any) used by a
+ Contributor and that particular Contributor’s Contribution.
+
+1.3. “Contribution”
+
+ means Covered Software of a particular Contributor.
+
+1.4. “Covered Software”
+
+ means Source Code Form to which the initial Contributor has attached the
+ notice in Exhibit A, the Executable Form of such Source Code Form, and
+ Modifications of such Source Code Form, in each case including portions
+ thereof.
+
+1.5. “Incompatible With Secondary Licenses”
+ means
+
+ a. that the initial Contributor has attached the notice described in
+ Exhibit B to the Covered Software; or
+
+ b. that the Covered Software was made available under the terms of version
+ 1.1 or earlier of the License, but not also under the terms of a
+ Secondary License.
+
+1.6. “Executable Form”
+
+ means any form of the work other than Source Code Form.
+
+1.7. “Larger Work”
+
+ means a work that combines Covered Software with other material, in a separate
+ file or files, that is not Covered Software.
+
+1.8. “License”
+
+ means this document.
+
+1.9. “Licensable”
+
+ means having the right to grant, to the maximum extent possible, whether at the
+ time of the initial grant or subsequently, any and all of the rights conveyed by
+ this License.
+
+1.10. “Modifications”
+
+ means any of the following:
+
+ a. any file in Source Code Form that results from an addition to, deletion
+ from, or modification of the contents of Covered Software; or
+
+ b. any new file in Source Code Form that contains any Covered Software.
+
+1.11. “Patent Claims” of a Contributor
+
+ means any patent claim(s), including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by such Contributor that
+ would be infringed, but for the grant of the License, by the making,
+ using, selling, offering for sale, having made, import, or transfer of
+ either its Contributions or its Contributor Version.
+
+1.12. “Secondary License”
+
+ means either the GNU General Public License, Version 2.0, the GNU Lesser
+ General Public License, Version 2.1, the GNU Affero General Public
+ License, Version 3.0, or any later versions of those licenses.
+
+1.13. “Source Code Form”
+
+ means the form of the work preferred for making modifications.
+
+1.14. “You” (or “Your”)
+
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, “You” includes any entity that controls, is
+ controlled by, or is under common control with You. For purposes of this
+ definition, “control” means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by contract or
+ otherwise, or (b) ownership of more than fifty percent (50%) of the
+ outstanding shares or beneficial ownership of such entity.
+
+
+2. License Grants and Conditions
+
+2.1. Grants
+
+ Each Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ a. under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or as
+ part of a Larger Work; and
+
+ b. under Patent Claims of such Contributor to make, use, sell, offer for
+ sale, have made, import, and otherwise transfer either its Contributions
+ or its Contributor Version.
+
+2.2. Effective Date
+
+ The licenses granted in Section 2.1 with respect to any Contribution become
+ effective for each Contribution on the date the Contributor first distributes
+ such Contribution.
+
+2.3. Limitations on Grant Scope
+
+ The licenses granted in this Section 2 are the only rights granted under this
+ License. No additional rights or licenses will be implied from the distribution
+ or licensing of Covered Software under this License. Notwithstanding Section
+ 2.1(b) above, no patent license is granted by a Contributor:
+
+ a. for any code that a Contributor has removed from Covered Software; or
+
+ b. for infringements caused by: (i) Your and any other third party’s
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+ c. under Patent Claims infringed by Covered Software in the absence of its
+ Contributions.
+
+ This License does not grant any rights in the trademarks, service marks, or
+ logos of any Contributor (except as may be necessary to comply with the
+ notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+ No Contributor makes additional grants as a result of Your choice to
+ distribute the Covered Software under a subsequent version of this License
+ (see Section 10.2) or under the terms of a Secondary License (if permitted
+ under the terms of Section 3.3).
+
+2.5. Representation
+
+ Each Contributor represents that the Contributor believes its Contributions
+ are its original creation(s) or it has sufficient rights to grant the
+ rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+ This License is not intended to limit any rights You have under applicable
+ copyright doctrines of fair use, fair dealing, or other equivalents.
+
+2.7. Conditions
+
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+ Section 2.1.
+
+
+3. Responsibilities
+
+3.1. Distribution of Source Form
+
+ All distribution of Covered Software in Source Code Form, including any
+ Modifications that You create or to which You contribute, must be under the
+ terms of this License. You must inform recipients that the Source Code Form
+ of the Covered Software is governed by the terms of this License, and how
+ they can obtain a copy of this License. You may not attempt to alter or
+ restrict the recipients’ rights in the Source Code Form.
+
+3.2. Distribution of Executable Form
+
+ If You distribute Covered Software in Executable Form then:
+
+ a. such Covered Software must also be made available in Source Code Form,
+ as described in Section 3.1, and You must inform recipients of the
+ Executable Form how they can obtain a copy of such Source Code Form by
+ reasonable means in a timely manner, at a charge no more than the cost
+ of distribution to the recipient; and
+
+ b. You may distribute such Executable Form under the terms of this License,
+ or sublicense it under different terms, provided that the license for
+ the Executable Form does not attempt to limit or alter the recipients’
+ rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+ You may create and distribute a Larger Work under terms of Your choice,
+ provided that You also comply with the requirements of this License for the
+ Covered Software. If the Larger Work is a combination of Covered Software
+ with a work governed by one or more Secondary Licenses, and the Covered
+ Software is not Incompatible With Secondary Licenses, this License permits
+ You to additionally distribute such Covered Software under the terms of
+ such Secondary License(s), so that the recipient of the Larger Work may, at
+ their option, further distribute the Covered Software under the terms of
+ either this License or such Secondary License(s).
+
+3.4. Notices
+
+ You may not remove or alter the substance of any license notices (including
+ copyright notices, patent notices, disclaimers of warranty, or limitations
+ of liability) contained within the Source Code Form of the Covered
+ Software, except that You may alter any license notices to the extent
+ required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+ You may choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of Covered
+ Software. However, You may do so only on Your own behalf, and not on behalf
+ of any Contributor. You must make it absolutely clear that any such
+ warranty, support, indemnity, or liability obligation is offered by You
+ alone, and You hereby agree to indemnify every Contributor for any
+ liability incurred by such Contributor as a result of warranty, support,
+ indemnity or liability terms You offer. You may include additional
+ disclaimers of warranty and limitations of liability specific to any
+ jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+
+ If it is impossible for You to comply with any of the terms of this License
+ with respect to some or all of the Covered Software due to statute, judicial
+ order, or regulation then You must: (a) comply with the terms of this License
+ to the maximum extent possible; and (b) describe the limitations and the code
+ they affect. Such description must be placed in a text file included with all
+ distributions of the Covered Software under this License. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+
+5. Termination
+
+5.1. The rights granted under this License will terminate automatically if You
+ fail to comply with any of its terms. However, if You become compliant,
+ then the rights granted under this License from a particular Contributor
+ are reinstated (a) provisionally, unless and until such Contributor
+ explicitly and finally terminates Your grants, and (b) on an ongoing basis,
+ if such Contributor fails to notify You of the non-compliance by some
+ reasonable means prior to 60 days after You have come back into compliance.
+ Moreover, Your grants from a particular Contributor are reinstated on an
+ ongoing basis if such Contributor notifies You of the non-compliance by
+ some reasonable means, this is the first time You have received notice of
+ non-compliance with this License from such Contributor, and You become
+ compliant prior to 30 days after Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+ infringement claim (excluding declaratory judgment actions, counter-claims,
+ and cross-claims) alleging that a Contributor Version directly or
+ indirectly infringes any patent, then the rights granted to You by any and
+ all Contributors for the Covered Software under Section 2.1 of this License
+ shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
+ license agreements (excluding distributors and resellers) which have been
+ validly granted by You or Your distributors under this License prior to
+ termination shall survive termination.
+
+6. Disclaimer of Warranty
+
+ Covered Software is provided under this License on an “as is” basis, without
+ warranty of any kind, either expressed, implied, or statutory, including,
+ without limitation, warranties that the Covered Software is free of defects,
+ merchantable, fit for a particular purpose or non-infringing. The entire
+ risk as to the quality and performance of the Covered Software is with You.
+ Should any Covered Software prove defective in any respect, You (not any
+ Contributor) assume the cost of any necessary servicing, repair, or
+ correction. This disclaimer of warranty constitutes an essential part of this
+ License. No use of any Covered Software is authorized under this License
+ except under this disclaimer.
+
+7. Limitation of Liability
+
+ Under no circumstances and under no legal theory, whether tort (including
+ negligence), contract, or otherwise, shall any Contributor, or anyone who
+ distributes Covered Software as permitted above, be liable to You for any
+ direct, indirect, special, incidental, or consequential damages of any
+ character including, without limitation, damages for lost profits, loss of
+ goodwill, work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses, even if such party shall have been
+ informed of the possibility of such damages. This limitation of liability
+ shall not apply to liability for death or personal injury resulting from such
+ party’s negligence to the extent applicable law prohibits such limitation.
+ Some jurisdictions do not allow the exclusion or limitation of incidental or
+ consequential damages, so this exclusion and limitation may not apply to You.
+
+8. Litigation
+
+ Any litigation relating to this License may be brought only in the courts of
+ a jurisdiction where the defendant maintains its principal place of business
+ and such litigation shall be governed by laws of that jurisdiction, without
+ reference to its conflict-of-law provisions. Nothing in this Section shall
+ prevent a party’s ability to bring cross-claims or counter-claims.
+
+9. Miscellaneous
+
+ This License represents the complete agreement concerning the subject matter
+ hereof. If any provision of this License is held to be unenforceable, such
+ provision shall be reformed only to the extent necessary to make it
+ enforceable. Any law or regulation which provides that the language of a
+ contract shall be construed against the drafter shall not be used to construe
+ this License against a Contributor.
+
+
+10. Versions of the License
+
+10.1. New Versions
+
+ Mozilla Foundation is the license steward. Except as provided in Section
+ 10.3, no one other than the license steward has the right to modify or
+ publish new versions of this License. Each version will be given a
+ distinguishing version number.
+
+10.2. Effect of New Versions
+
+ You may distribute the Covered Software under the terms of the version of
+ the License under which You originally received the Covered Software, or
+ under the terms of any subsequent version published by the license
+ steward.
+
+10.3. Modified Versions
+
+ If you create software not governed by this License, and you want to
+ create a new license for such software, you may create and use a modified
+ version of this License if you rename the license and remove any
+ references to the name of the license steward (except to note that such
+ modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
+ If You choose to distribute Source Code Form that is Incompatible With
+ Secondary Licenses under the terms of this version of the License, the
+ notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+
+ This Source Code Form is subject to the
+ terms of the Mozilla Public License, v.
+ 2.0. If a copy of the MPL was not
+ distributed with this file, You can
+ obtain one at
+ http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular file, then
+You may include the notice in a location (such as a LICENSE file in a relevant
+directory) where a recipient would be likely to look for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - “Incompatible With Secondary Licenses” Notice
+
+ This Source Code Form is “Incompatible
+ With Secondary Licenses”, as defined by
+ the Mozilla Public License, v. 2.0.
+
diff --git a/vendor/github.com/hashicorp/memberlist/Makefile b/vendor/github.com/hashicorp/memberlist/Makefile
new file mode 100644
index 00000000000..e9b7b287074
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/Makefile
@@ -0,0 +1,33 @@
+SHELL := bash
+
+GOFILES ?= $(shell go list ./... | grep -v /vendor/)
+
+default: test
+
+test: vet subnet
+ go test ./...
+
+integ: subnet
+ INTEG_TESTS=yes go test ./...
+
+subnet:
+ ./test/setup_subnet.sh
+
+cov:
+ go test ./... -coverprofile=coverage.out
+ go tool cover -html=coverage.out
+
+format:
+ @echo "--> Running go fmt"
+ @go fmt $(GOFILES)
+
+vet:
+ @echo "--> Running go vet"
+ @go vet -tags '$(GOTAGS)' $(GOFILES); if [ $$? -eq 1 ]; then \
+ echo ""; \
+ echo "Vet found suspicious constructs. Please check the reported constructs"; \
+ echo "and fix them if necessary before submitting the code for review."; \
+ exit 1; \
+ fi
+
+.PHONY: default test integ subnet cov format vet
diff --git a/vendor/github.com/hashicorp/memberlist/README.md b/vendor/github.com/hashicorp/memberlist/README.md
new file mode 100644
index 00000000000..5aa5bdb6765
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/README.md
@@ -0,0 +1,98 @@
+# memberlist [](https://godoc.org/github.com/hashicorp/memberlist) [](https://circleci.com/gh/hashicorp/memberlist)
+
+memberlist is a [Go](http://www.golang.org) library that manages cluster
+membership and member failure detection using a gossip based protocol.
+
+The use cases for such a library are far-reaching: all distributed systems
+require membership, and memberlist is a re-usable solution to managing
+cluster membership and node failure detection.
+
+memberlist is eventually consistent but converges quickly on average.
+The speed at which it converges can be heavily tuned via various knobs
+on the protocol. Node failures are detected and network partitions are partially
+tolerated by attempting to communicate to potentially dead nodes through
+multiple routes.
+
+## Building
+
+If you wish to build memberlist you'll need Go version 1.2+ installed.
+
+Please check your installation with:
+
+```
+go version
+```
+
+## Usage
+
+Memberlist is surprisingly simple to use. An example is shown below:
+
+```go
+/* Create the initial memberlist from a safe configuration.
+ Please reference the godoc for other default config types.
+ http://godoc.org/github.com/hashicorp/memberlist#Config
+*/
+list, err := memberlist.Create(memberlist.DefaultLocalConfig())
+if err != nil {
+ panic("Failed to create memberlist: " + err.Error())
+}
+
+// Join an existing cluster by specifying at least one known member.
+n, err := list.Join([]string{"1.2.3.4"})
+if err != nil {
+ panic("Failed to join cluster: " + err.Error())
+}
+
+// Ask for members of the cluster
+for _, member := range list.Members() {
+ fmt.Printf("Member: %s %s\n", member.Name, member.Addr)
+}
+
+// Continue doing whatever you need, memberlist will maintain membership
+// information in the background. Delegates can be used for receiving
+// events when members join or leave.
+```
+
+The most difficult part of memberlist is configuring it since it has many
+available knobs in order to tune state propagation delay and convergence times.
+Memberlist provides a default configuration that offers a good starting point,
+but errs on the side of caution, choosing values that are optimized for
+higher convergence at the cost of higher bandwidth usage.
+
+For complete documentation, see the associated [Godoc](http://godoc.org/github.com/hashicorp/memberlist).
+
+## Protocol
+
+memberlist is based on ["SWIM: Scalable Weakly-consistent Infection-style Process Group Membership Protocol"](http://ieeexplore.ieee.org/document/1028914/). However, we extend the protocol in a number of ways:
+
+* Several extensions are made to increase propagation speed and
+convergence rate.
+* Another set of extensions, that we call Lifeguard, are made to make memberlist more robust in the presence of slow message processing (due to factors such as CPU starvation, and network delay or loss).
+
+For details on all of these extensions, please read our paper "[Lifeguard : SWIM-ing with Situational Awareness](https://arxiv.org/abs/1707.00788)", along with the memberlist source. We welcome any questions related
+to the protocol on our issue tracker.
+
+## Metrics Emission and Compatibility
+
+This library can emit metrics using either `github.com/armon/go-metrics` or `github.com/hashicorp/go-metrics`. Choosing between the libraries is controlled via build tags.
+
+**Build Tags**
+* `armonmetrics` - Using this tag will cause metrics to be routed to `armon/go-metrics`
+* `hashicorpmetrics` - Using this tag will cause all metrics to be routed to `hashicorp/go-metrics`
+
+If no build tag is specified, the default behavior is to use `armon/go-metrics`.
+
+**Deprecating `armon/go-metrics`**
+
+Emitting metrics to `armon/go-metrics` is officially deprecated. Usage of `armon/go-metrics` will remain the default until mid-2025 with opt-in support continuing to the end of 2025.
+
+**Migration**
+To migrate an application currently using the older `armon/go-metrics` to instead use `hashicorp/go-metrics` the following should be done.
+
+1. Upgrade libraries using `armon/go-metrics` to consume `hashicorp/go-metrics/compat` instead. This should involve only changing import statements. All repositories in the `hashicorp` namespace
+2. Update an applications library dependencies to those that have the compatibility layer configured.
+3. Update the application to use `hashicorp/go-metrics` for configuring metrics export instead of `armon/go-metrics`
+ * Replace all application imports of `github.com/armon/go-metrics` with `github.com/hashicorp/go-metrics`
+ * Instrument your build system to build with the `hashicorpmetrics` tag.
+
+Eventually once the default behavior changes to use `hashicorp/go-metrics` by default (mid-2025), you can drop the `hashicorpmetrics` build tag.
diff --git a/vendor/github.com/hashicorp/memberlist/alive_delegate.go b/vendor/github.com/hashicorp/memberlist/alive_delegate.go
new file mode 100644
index 00000000000..6a5b8a5a1cc
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/alive_delegate.go
@@ -0,0 +1,17 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+// AliveDelegate is used to involve a client in processing
+// a node "alive" message. When a node joins, either through
+// a UDP gossip or TCP push/pull, we update the state of
+// that node via an alive message. This can be used to filter
+// a node out and prevent it from being considered a peer
+// using application specific logic.
+type AliveDelegate interface {
+ // NotifyAlive is invoked when a message about a live
+ // node is received from the network. Returning a non-nil
+ // error prevents the node from being considered a peer.
+ NotifyAlive(peer *Node) error
+}
diff --git a/vendor/github.com/hashicorp/memberlist/awareness.go b/vendor/github.com/hashicorp/memberlist/awareness.go
new file mode 100644
index 00000000000..566967edbee
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/awareness.go
@@ -0,0 +1,76 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "sync"
+ "time"
+
+ "github.com/hashicorp/go-metrics/compat"
+)
+
+// awareness manages a simple metric for tracking the estimated health of the
+// local node. Health is primary the node's ability to respond in the soft
+// real-time manner required for correct health checking of other nodes in the
+// cluster.
+type awareness struct {
+ sync.RWMutex
+
+ // max is the upper threshold for the timeout scale (the score will be
+ // constrained to be from 0 <= score < max).
+ max int
+
+ // score is the current awareness score. Lower values are healthier and
+ // zero is the minimum value.
+ score int
+
+ // metricLabels is the slice of labels to put on all emitted metrics
+ metricLabels []metrics.Label
+}
+
+// newAwareness returns a new awareness object.
+func newAwareness(max int, metricLabels []metrics.Label) *awareness {
+ return &awareness{
+ max: max,
+ score: 0,
+ metricLabels: metricLabels,
+ }
+}
+
+// ApplyDelta takes the given delta and applies it to the score in a thread-safe
+// manner. It also enforces a floor of zero and a max of max, so deltas may not
+// change the overall score if it's railed at one of the extremes.
+func (a *awareness) ApplyDelta(delta int) {
+ a.Lock()
+ initial := a.score
+ a.score += delta
+ if a.score < 0 {
+ a.score = 0
+ } else if a.score > (a.max - 1) {
+ a.score = (a.max - 1)
+ }
+ final := a.score
+ a.Unlock()
+
+ if initial != final {
+ metrics.SetGaugeWithLabels([]string{"memberlist", "health", "score"}, float32(final), a.metricLabels)
+ }
+}
+
+// GetHealthScore returns the raw health score.
+func (a *awareness) GetHealthScore() int {
+ a.RLock()
+ score := a.score
+ a.RUnlock()
+ return score
+}
+
+// ScaleTimeout takes the given duration and scales it based on the current
+// score. Less healthyness will lead to longer timeouts.
+func (a *awareness) ScaleTimeout(timeout time.Duration) time.Duration {
+ a.RLock()
+ score := a.score
+ a.RUnlock()
+ return timeout * (time.Duration(score) + 1)
+}
diff --git a/vendor/github.com/hashicorp/memberlist/broadcast.go b/vendor/github.com/hashicorp/memberlist/broadcast.go
new file mode 100644
index 00000000000..98b8c784c64
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/broadcast.go
@@ -0,0 +1,108 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+/*
+The broadcast mechanism works by maintaining a sorted list of messages to be
+sent out. When a message is to be broadcast, the retransmit count
+is set to zero and appended to the queue. The retransmit count serves
+as the "priority", ensuring that newer messages get sent first. Once
+a message hits the retransmit limit, it is removed from the queue.
+
+Additionally, older entries can be invalidated by new messages that
+are contradictory. For example, if we send "{suspect M1 inc: 1},
+then a following {alive M1 inc: 2} will invalidate that message
+*/
+
+type memberlistBroadcast struct {
+ node string
+ msg []byte
+ notify chan struct{}
+}
+
+func (b *memberlistBroadcast) Invalidates(other Broadcast) bool {
+ // Check if that broadcast is a memberlist type
+ mb, ok := other.(*memberlistBroadcast)
+ if !ok {
+ return false
+ }
+
+ // Invalidates any message about the same node
+ return b.node == mb.node
+}
+
+// memberlist.NamedBroadcast optional interface
+func (b *memberlistBroadcast) Name() string {
+ return b.node
+}
+
+func (b *memberlistBroadcast) Message() []byte {
+ return b.msg
+}
+
+func (b *memberlistBroadcast) Finished() {
+ select {
+ case b.notify <- struct{}{}:
+ default:
+ }
+}
+
+// encodeAndBroadcast encodes a message and enqueues it for broadcast. Fails
+// silently if there is an encoding error.
+func (m *Memberlist) encodeAndBroadcast(node string, msgType messageType, msg interface{}) {
+ m.encodeBroadcastNotify(node, msgType, msg, nil)
+}
+
+// encodeBroadcastNotify encodes a message and enqueues it for broadcast
+// and notifies the given channel when transmission is finished. Fails
+// silently if there is an encoding error.
+func (m *Memberlist) encodeBroadcastNotify(node string, msgType messageType, msg interface{}, notify chan struct{}) {
+ buf, err := encode(msgType, msg, m.config.MsgpackUseNewTimeFormat)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to encode message for broadcast: %s", err)
+ } else {
+ m.queueBroadcast(node, buf.Bytes(), notify)
+ }
+}
+
+// queueBroadcast is used to start dissemination of a message. It will be
+// sent up to a configured number of times. The message could potentially
+// be invalidated by a future message about the same node
+func (m *Memberlist) queueBroadcast(node string, msg []byte, notify chan struct{}) {
+ b := &memberlistBroadcast{node, msg, notify}
+ m.broadcasts.QueueBroadcast(b)
+}
+
+// getBroadcasts is used to return a slice of broadcasts to send up to
+// a maximum byte size, while imposing a per-broadcast overhead. This is used
+// to fill a UDP packet with piggybacked data
+func (m *Memberlist) getBroadcasts(overhead, limit int) [][]byte {
+ // Get memberlist messages first
+ toSend := m.broadcasts.GetBroadcasts(overhead, limit)
+
+ // Check if the user has anything to broadcast
+ d := m.config.Delegate
+ if d != nil {
+ // Determine the bytes used already
+ bytesUsed := 0
+ for _, msg := range toSend {
+ bytesUsed += len(msg) + overhead
+ }
+
+ // Check space remaining for user messages
+ avail := limit - bytesUsed
+ if avail > overhead+userMsgOverhead {
+ userMsgs := d.GetBroadcasts(overhead+userMsgOverhead, avail)
+
+ // Frame each user message
+ for _, msg := range userMsgs {
+ buf := make([]byte, 1, len(msg)+1)
+ buf[0] = byte(userMsg)
+ buf = append(buf, msg...)
+ toSend = append(toSend, buf)
+ }
+ }
+ }
+ return toSend
+}
diff --git a/vendor/github.com/hashicorp/memberlist/config.go b/vendor/github.com/hashicorp/memberlist/config.go
new file mode 100644
index 00000000000..1a869c10a43
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/config.go
@@ -0,0 +1,397 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/hashicorp/go-metrics/compat"
+ "github.com/hashicorp/go-multierror"
+)
+
+type Config struct {
+ // The name of this node. This must be unique in the cluster.
+ Name string
+
+ // Transport is a hook for providing custom code to communicate with
+ // other nodes. If this is left nil, then memberlist will by default
+ // make a NetTransport using BindAddr and BindPort from this structure.
+ Transport Transport
+
+ // Label is an optional set of bytes to include on the outside of each
+ // packet and stream.
+ //
+ // If gossip encryption is enabled and this is set it is treated as GCM
+ // authenticated data.
+ Label string
+
+ // SkipInboundLabelCheck skips the check that inbound packets and gossip
+ // streams need to be label prefixed.
+ SkipInboundLabelCheck bool
+
+ // Configuration related to what address to bind to and ports to
+ // listen on. The port is used for both UDP and TCP gossip. It is
+ // assumed other nodes are running on this port, but they do not need
+ // to.
+ BindAddr string
+ BindPort int
+
+ // Configuration related to what address to advertise to other
+ // cluster members. Used for nat traversal.
+ AdvertiseAddr string
+ AdvertisePort int
+
+ // ProtocolVersion is the configured protocol version that we
+ // will _speak_. This must be between ProtocolVersionMin and
+ // ProtocolVersionMax.
+ ProtocolVersion uint8
+
+ // TCPTimeout is the timeout for establishing a stream connection with
+ // a remote node for a full state sync, and for stream read and write
+ // operations. This is a legacy name for backwards compatibility, but
+ // should really be called StreamTimeout now that we have generalized
+ // the transport.
+ TCPTimeout time.Duration
+
+ // IndirectChecks is the number of nodes that will be asked to perform
+ // an indirect probe of a node in the case a direct probe fails. Memberlist
+ // waits for an ack from any single indirect node, so increasing this
+ // number will increase the likelihood that an indirect probe will succeed
+ // at the expense of bandwidth.
+ IndirectChecks int
+
+ // RetransmitMult is the multiplier for the number of retransmissions
+ // that are attempted for messages broadcasted over gossip. The actual
+ // count of retransmissions is calculated using the formula:
+ //
+ // Retransmits = RetransmitMult * log(N+1)
+ //
+ // This allows the retransmits to scale properly with cluster size. The
+ // higher the multiplier, the more likely a failed broadcast is to converge
+ // at the expense of increased bandwidth.
+ RetransmitMult int
+
+ // SuspicionMult is the multiplier for determining the time an
+ // inaccessible node is considered suspect before declaring it dead.
+ // The actual timeout is calculated using the formula:
+ //
+ // SuspicionTimeout = SuspicionMult * log(N+1) * ProbeInterval
+ //
+ // This allows the timeout to scale properly with expected propagation
+ // delay with a larger cluster size. The higher the multiplier, the longer
+ // an inaccessible node is considered part of the cluster before declaring
+ // it dead, giving that suspect node more time to refute if it is indeed
+ // still alive.
+ SuspicionMult int
+
+ // SuspicionMaxTimeoutMult is the multiplier applied to the
+ // SuspicionTimeout used as an upper bound on detection time. This max
+ // timeout is calculated using the formula:
+ //
+ // SuspicionMaxTimeout = SuspicionMaxTimeoutMult * SuspicionTimeout
+ //
+ // If everything is working properly, confirmations from other nodes will
+ // accelerate suspicion timers in a manner which will cause the timeout
+ // to reach the base SuspicionTimeout before that elapses, so this value
+ // will typically only come into play if a node is experiencing issues
+ // communicating with other nodes. It should be set to a something fairly
+ // large so that a node having problems will have a lot of chances to
+ // recover before falsely declaring other nodes as failed, but short
+ // enough for a legitimately isolated node to still make progress marking
+ // nodes failed in a reasonable amount of time.
+ SuspicionMaxTimeoutMult int
+
+ // PushPullInterval is the interval between complete state syncs.
+ // Complete state syncs are done with a single node over TCP and are
+ // quite expensive relative to standard gossiped messages. Setting this
+ // to zero will disable state push/pull syncs completely.
+ //
+ // Setting this interval lower (more frequent) will increase convergence
+ // speeds across larger clusters at the expense of increased bandwidth
+ // usage.
+ PushPullInterval time.Duration
+
+ // ProbeInterval and ProbeTimeout are used to configure probing
+ // behavior for memberlist.
+ //
+ // ProbeInterval is the interval between random node probes. Setting
+ // this lower (more frequent) will cause the memberlist cluster to detect
+ // failed nodes more quickly at the expense of increased bandwidth usage.
+ //
+ // ProbeTimeout is the timeout to wait for an ack from a probed node
+ // before assuming it is unhealthy. This should be set to 99-percentile
+ // of RTT (round-trip time) on your network.
+ ProbeInterval time.Duration
+ ProbeTimeout time.Duration
+
+ // DisableTcpPings will turn off the fallback TCP pings that are attempted
+ // if the direct UDP ping fails. These get pipelined along with the
+ // indirect UDP pings.
+ DisableTcpPings bool
+
+ // DisableTcpPingsForNode is like DisableTcpPings, but lets you control
+ // whether to perform TCP pings on a node-by-node basis.
+ DisableTcpPingsForNode func(nodeName string) bool
+
+ // AwarenessMaxMultiplier will increase the probe interval if the node
+ // becomes aware that it might be degraded and not meeting the soft real
+ // time requirements to reliably probe other nodes.
+ AwarenessMaxMultiplier int
+
+ // GossipInterval and GossipNodes are used to configure the gossip
+ // behavior of memberlist.
+ //
+ // GossipInterval is the interval between sending messages that need
+ // to be gossiped that haven't been able to piggyback on probing messages.
+ // If this is set to zero, non-piggyback gossip is disabled. By lowering
+ // this value (more frequent) gossip messages are propagated across
+ // the cluster more quickly at the expense of increased bandwidth.
+ //
+ // GossipNodes is the number of random nodes to send gossip messages to
+ // per GossipInterval. Increasing this number causes the gossip messages
+ // to propagate across the cluster more quickly at the expense of
+ // increased bandwidth.
+ //
+ // GossipToTheDeadTime is the interval after which a node has died that
+ // we will still try to gossip to it. This gives it a chance to refute.
+ GossipInterval time.Duration
+ GossipNodes int
+ GossipToTheDeadTime time.Duration
+
+ // GossipVerifyIncoming controls whether to enforce encryption for incoming
+ // gossip. It is used for upshifting from unencrypted to encrypted gossip on
+ // a running cluster.
+ GossipVerifyIncoming bool
+
+ // GossipVerifyOutgoing controls whether to enforce encryption for outgoing
+ // gossip. It is used for upshifting from unencrypted to encrypted gossip on
+ // a running cluster.
+ GossipVerifyOutgoing bool
+
+ // EnableCompression is used to control message compression. This can
+ // be used to reduce bandwidth usage at the cost of slightly more CPU
+ // utilization. This is only available starting at protocol version 1.
+ EnableCompression bool
+
+ // SecretKey is used to initialize the primary encryption key in a keyring.
+ // The primary encryption key is the only key used to encrypt messages and
+ // the first key used while attempting to decrypt messages. Providing a
+ // value for this primary key will enable message-level encryption and
+ // verification, and automatically install the key onto the keyring.
+ // The value should be either 16, 24, or 32 bytes to select AES-128,
+ // AES-192, or AES-256.
+ SecretKey []byte
+
+ // The keyring holds all of the encryption keys used internally. It is
+ // automatically initialized using the SecretKey and SecretKeys values.
+ Keyring *Keyring
+
+ // Delegate and Events are delegates for receiving and providing
+ // data to memberlist via callback mechanisms. For Delegate, see
+ // the Delegate interface. For Events, see the EventDelegate interface.
+ //
+ // The DelegateProtocolMin/Max are used to guarantee protocol-compatibility
+ // for any custom messages that the delegate might do (broadcasts,
+ // local/remote state, etc.). If you don't set these, then the protocol
+ // versions will just be zero, and version compliance won't be done.
+ Delegate Delegate
+ DelegateProtocolVersion uint8
+ DelegateProtocolMin uint8
+ DelegateProtocolMax uint8
+ Events EventDelegate
+ Conflict ConflictDelegate
+ Merge MergeDelegate
+ Ping PingDelegate
+ Alive AliveDelegate
+
+ // DNSConfigPath points to the system's DNS config file, usually located
+ // at /etc/resolv.conf. It can be overridden via config for easier testing.
+ DNSConfigPath string
+
+ // LogOutput is the writer where logs should be sent. If this is not
+ // set, logging will go to stderr by default. You cannot specify both LogOutput
+ // and Logger at the same time.
+ LogOutput io.Writer
+
+ // Logger is a custom logger which you provide. If Logger is set, it will use
+ // this for the internal logger. If Logger is not set, it will fall back to the
+ // behavior for using LogOutput. You cannot specify both LogOutput and Logger
+ // at the same time.
+ Logger *log.Logger
+
+ // Size of Memberlist's internal channel which handles UDP messages. The
+ // size of this determines the size of the queue which Memberlist will keep
+ // while UDP messages are handled.
+ HandoffQueueDepth int
+
+ // Maximum number of bytes that memberlist will put in a packet (this
+ // will be for UDP packets by default with a NetTransport). A safe value
+ // for this is typically 1400 bytes (which is the default). However,
+ // depending on your network's MTU (Maximum Transmission Unit) you may
+ // be able to increase this to get more content into each gossip packet.
+ // This is a legacy name for backward compatibility but should really be
+ // called PacketBufferSize now that we have generalized the transport.
+ UDPBufferSize int
+
+ // DeadNodeReclaimTime controls the time before a dead node's name can be
+ // reclaimed by one with a different address or port. By default, this is 0,
+ // meaning nodes cannot be reclaimed this way.
+ DeadNodeReclaimTime time.Duration
+
+ // RequireNodeNames controls if the name of a node is required when sending
+ // a message to that node.
+ RequireNodeNames bool
+
+ // CIDRsAllowed If nil, allow any connection (default), otherwise specify all networks
+ // allowed to connect (you must specify IPv6/IPv4 separately)
+ // Using [] will block all connections.
+ CIDRsAllowed []net.IPNet
+
+ // MetricLabels is a map of optional labels to apply to all metrics emitted.
+ MetricLabels []metrics.Label
+
+ // QueueCheckInterval is the interval at which we check the message
+ // queue to apply the warning and max depth.
+ QueueCheckInterval time.Duration
+
+ // MsgpackUseNewTimeFormat when set to true, force the underlying msgpack
+ // codec to use the new format of time.Time when encoding (used in
+ // go-msgpack v1.1.5 by default). Decoding is not affected, as all
+ // go-msgpack v2.1.0+ decoders know how to decode both formats.
+ MsgpackUseNewTimeFormat bool
+}
+
+// ParseCIDRs return a possible empty list of all Network that have been parsed
+// In case of error, it returns succesfully parsed CIDRs and the last error found
+func ParseCIDRs(v []string) ([]net.IPNet, error) {
+ nets := make([]net.IPNet, 0)
+ if v == nil {
+ return nets, nil
+ }
+ var errs error
+ hasErrors := false
+ for _, p := range v {
+ _, net, err := net.ParseCIDR(strings.TrimSpace(p))
+ if err != nil {
+ err = fmt.Errorf("invalid cidr: %s", p)
+ errs = multierror.Append(errs, err)
+ hasErrors = true
+ } else {
+ nets = append(nets, *net)
+ }
+ }
+ if !hasErrors {
+ errs = nil
+ }
+ return nets, errs
+}
+
+// DefaultLANConfig returns a sane set of configurations for Memberlist.
+// It uses the hostname as the node name, and otherwise sets very conservative
+// values that are sane for most LAN environments. The default configuration
+// errs on the side of caution, choosing values that are optimized
+// for higher convergence at the cost of higher bandwidth usage. Regardless,
+// these values are a good starting point when getting started with memberlist.
+func DefaultLANConfig() *Config {
+ hostname, _ := os.Hostname()
+ return &Config{
+ Name: hostname,
+ BindAddr: "0.0.0.0",
+ BindPort: 7946,
+ AdvertiseAddr: "",
+ AdvertisePort: 7946,
+ ProtocolVersion: ProtocolVersion2Compatible,
+ TCPTimeout: 10 * time.Second, // Timeout after 10 seconds
+ IndirectChecks: 3, // Use 3 nodes for the indirect ping
+ RetransmitMult: 4, // Retransmit a message 4 * log(N+1) nodes
+ SuspicionMult: 4, // Suspect a node for 4 * log(N+1) * Interval
+ SuspicionMaxTimeoutMult: 6, // For 10k nodes this will give a max timeout of 120 seconds
+ PushPullInterval: 30 * time.Second, // Low frequency
+ ProbeTimeout: 500 * time.Millisecond, // Reasonable RTT time for LAN
+ ProbeInterval: 1 * time.Second, // Failure check every second
+ DisableTcpPings: false, // TCP pings are safe, even with mixed versions
+ AwarenessMaxMultiplier: 8, // Probe interval backs off to 8 seconds
+
+ GossipNodes: 3, // Gossip to 3 nodes
+ GossipInterval: 200 * time.Millisecond, // Gossip more rapidly
+ GossipToTheDeadTime: 30 * time.Second, // Same as push/pull
+ GossipVerifyIncoming: true,
+ GossipVerifyOutgoing: true,
+
+ EnableCompression: true, // Enable compression by default
+
+ SecretKey: nil,
+ Keyring: nil,
+
+ DNSConfigPath: "/etc/resolv.conf",
+
+ HandoffQueueDepth: 1024,
+ UDPBufferSize: 1400,
+ CIDRsAllowed: nil, // same as allow all
+
+ QueueCheckInterval: 30 * time.Second,
+ }
+}
+
+// DefaultWANConfig works like DefaultConfig, however it returns a configuration
+// that is optimized for most WAN environments. The default configuration is
+// still very conservative and errs on the side of caution.
+func DefaultWANConfig() *Config {
+ conf := DefaultLANConfig()
+ conf.TCPTimeout = 30 * time.Second
+ conf.SuspicionMult = 6
+ conf.PushPullInterval = 60 * time.Second
+ conf.ProbeTimeout = 3 * time.Second
+ conf.ProbeInterval = 5 * time.Second
+ conf.GossipNodes = 4 // Gossip less frequently, but to an additional node
+ conf.GossipInterval = 500 * time.Millisecond
+ conf.GossipToTheDeadTime = 60 * time.Second
+ return conf
+}
+
+// IPMustBeChecked return true if IPAllowed must be called
+func (c *Config) IPMustBeChecked() bool {
+ return len(c.CIDRsAllowed) > 0
+}
+
+// IPAllowed return an error if access to memberlist is denied
+func (c *Config) IPAllowed(ip net.IP) error {
+ if !c.IPMustBeChecked() {
+ return nil
+ }
+ for _, n := range c.CIDRsAllowed {
+ if n.Contains(ip) {
+ return nil
+ }
+ }
+ return fmt.Errorf("%s is not allowed", ip)
+}
+
+// DefaultLocalConfig works like DefaultConfig, however it returns a configuration
+// that is optimized for a local loopback environments. The default configuration is
+// still very conservative and errs on the side of caution.
+func DefaultLocalConfig() *Config {
+ conf := DefaultLANConfig()
+ conf.TCPTimeout = time.Second
+ conf.IndirectChecks = 1
+ conf.RetransmitMult = 2
+ conf.SuspicionMult = 3
+ conf.PushPullInterval = 15 * time.Second
+ conf.ProbeTimeout = 200 * time.Millisecond
+ conf.ProbeInterval = time.Second
+ conf.GossipInterval = 100 * time.Millisecond
+ conf.GossipToTheDeadTime = 15 * time.Second
+ return conf
+}
+
+// Returns whether or not encryption is enabled
+func (c *Config) EncryptionEnabled() bool {
+ return c.Keyring != nil && len(c.Keyring.GetKeys()) > 0
+}
diff --git a/vendor/github.com/hashicorp/memberlist/conflict_delegate.go b/vendor/github.com/hashicorp/memberlist/conflict_delegate.go
new file mode 100644
index 00000000000..a01de2fbb04
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/conflict_delegate.go
@@ -0,0 +1,13 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+// ConflictDelegate is a used to inform a client that
+// a node has attempted to join which would result in a
+// name conflict. This happens if two clients are configured
+// with the same name but different addresses.
+type ConflictDelegate interface {
+ // NotifyConflict is invoked when a name conflict is detected
+ NotifyConflict(existing, other *Node)
+}
diff --git a/vendor/github.com/hashicorp/memberlist/delegate.go b/vendor/github.com/hashicorp/memberlist/delegate.go
new file mode 100644
index 00000000000..5d8af2b05b5
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/delegate.go
@@ -0,0 +1,40 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+// Delegate is the interface that clients must implement if they want to hook
+// into the gossip layer of Memberlist. All the methods must be thread-safe,
+// as they can and generally will be called concurrently.
+type Delegate interface {
+ // NodeMeta is used to retrieve meta-data about the current node
+ // when broadcasting an alive message. It's length is limited to
+ // the given byte size. This metadata is available in the Node structure.
+ NodeMeta(limit int) []byte
+
+ // NotifyMsg is called when a user-data message is received.
+ // Care should be taken that this method does not block, since doing
+ // so would block the entire UDP packet receive loop. Additionally, the byte
+ // slice may be modified after the call returns, so it should be copied if needed
+ NotifyMsg([]byte)
+
+ // GetBroadcasts is called when user data messages can be broadcast.
+ // It can return a list of buffers to send. Each buffer should assume an
+ // overhead as provided with a limit on the total byte size allowed.
+ // The total byte size of the resulting data to send must not exceed
+ // the limit. Care should be taken that this method does not block,
+ // since doing so would block the entire UDP packet receive loop.
+ GetBroadcasts(overhead, limit int) [][]byte
+
+ // LocalState is used for a TCP Push/Pull. This is sent to
+ // the remote side in addition to the membership information. Any
+ // data can be sent here. See MergeRemoteState as well. The `join`
+ // boolean indicates this is for a join instead of a push/pull.
+ LocalState(join bool) []byte
+
+ // MergeRemoteState is invoked after a TCP Push/Pull. This is the
+ // state received from the remote side and is the result of the
+ // remote side's LocalState call. The 'join'
+ // boolean indicates this is for a join instead of a push/pull.
+ MergeRemoteState(buf []byte, join bool)
+}
diff --git a/vendor/github.com/hashicorp/memberlist/event_delegate.go b/vendor/github.com/hashicorp/memberlist/event_delegate.go
new file mode 100644
index 00000000000..caedfa31072
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/event_delegate.go
@@ -0,0 +1,67 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+// EventDelegate is a simpler delegate that is used only to receive
+// notifications about members joining and leaving. The methods in this
+// delegate may be called by multiple goroutines, but never concurrently.
+// This allows you to reason about ordering.
+type EventDelegate interface {
+ // NotifyJoin is invoked when a node is detected to have joined.
+ // The Node argument must not be modified.
+ NotifyJoin(*Node)
+
+ // NotifyLeave is invoked when a node is detected to have left.
+ // The Node argument must not be modified.
+ NotifyLeave(*Node)
+
+ // NotifyUpdate is invoked when a node is detected to have
+ // updated, usually involving the meta data. The Node argument
+ // must not be modified.
+ NotifyUpdate(*Node)
+}
+
+// ChannelEventDelegate is used to enable an application to receive
+// events about joins and leaves over a channel instead of a direct
+// function call.
+//
+// Care must be taken that events are processed in a timely manner from
+// the channel, since this delegate will block until an event can be sent.
+type ChannelEventDelegate struct {
+ Ch chan<- NodeEvent
+}
+
+// NodeEventType are the types of events that can be sent from the
+// ChannelEventDelegate.
+type NodeEventType int
+
+const (
+ NodeJoin NodeEventType = iota
+ NodeLeave
+ NodeUpdate
+)
+
+// NodeEvent is a single event related to node activity in the memberlist.
+// The Node member of this struct must not be directly modified. It is passed
+// as a pointer to avoid unnecessary copies. If you wish to modify the node,
+// make a copy first.
+type NodeEvent struct {
+ Event NodeEventType
+ Node *Node
+}
+
+func (c *ChannelEventDelegate) NotifyJoin(n *Node) {
+ node := *n
+ c.Ch <- NodeEvent{NodeJoin, &node}
+}
+
+func (c *ChannelEventDelegate) NotifyLeave(n *Node) {
+ node := *n
+ c.Ch <- NodeEvent{NodeLeave, &node}
+}
+
+func (c *ChannelEventDelegate) NotifyUpdate(n *Node) {
+ node := *n
+ c.Ch <- NodeEvent{NodeUpdate, &node}
+}
diff --git a/vendor/github.com/hashicorp/memberlist/keyring.go b/vendor/github.com/hashicorp/memberlist/keyring.go
new file mode 100644
index 00000000000..084460be462
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/keyring.go
@@ -0,0 +1,163 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "bytes"
+ "fmt"
+ "sync"
+)
+
+type Keyring struct {
+ // Keys stores the key data used during encryption and decryption. It is
+ // ordered in such a way where the first key (index 0) is the primary key,
+ // which is used for encrypting messages, and is the first key tried during
+ // message decryption.
+ keys [][]byte
+
+ // The keyring lock is used while performing IO operations on the keyring.
+ l sync.Mutex
+}
+
+// Init allocates substructures
+func (k *Keyring) init() {
+ k.keys = make([][]byte, 0)
+}
+
+// NewKeyring constructs a new container for a set of encryption keys. The
+// keyring contains all key data used internally by memberlist.
+//
+// While creating a new keyring, you must do one of:
+// - Omit keys and primary key, effectively disabling encryption
+// - Pass a set of keys plus the primary key
+// - Pass only a primary key
+//
+// If only a primary key is passed, then it will be automatically added to the
+// keyring. If creating a keyring with multiple keys, one key must be designated
+// primary by passing it as the primaryKey. If the primaryKey does not exist in
+// the list of secondary keys, it will be automatically added at position 0.
+//
+// A key should be either 16, 24, or 32 bytes to select AES-128,
+// AES-192, or AES-256.
+func NewKeyring(keys [][]byte, primaryKey []byte) (*Keyring, error) {
+ keyring := &Keyring{}
+ keyring.init()
+
+ if len(keys) > 0 || len(primaryKey) > 0 {
+ if len(primaryKey) == 0 {
+ return nil, fmt.Errorf("empty primary key not allowed")
+ }
+ if err := keyring.AddKey(primaryKey); err != nil {
+ return nil, err
+ }
+ for _, key := range keys {
+ if err := keyring.AddKey(key); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ return keyring, nil
+}
+
+// ValidateKey will check to see if the key is valid and returns an error if not.
+//
+// key should be either 16, 24, or 32 bytes to select AES-128,
+// AES-192, or AES-256.
+func ValidateKey(key []byte) error {
+ if l := len(key); l != 16 && l != 24 && l != 32 {
+ return fmt.Errorf("key size must be 16, 24 or 32 bytes")
+ }
+ return nil
+}
+
+// AddKey will install a new key on the ring. Adding a key to the ring will make
+// it available for use in decryption. If the key already exists on the ring,
+// this function will just return noop.
+//
+// key should be either 16, 24, or 32 bytes to select AES-128,
+// AES-192, or AES-256.
+func (k *Keyring) AddKey(key []byte) error {
+ if err := ValidateKey(key); err != nil {
+ return err
+ }
+
+ // No-op if key is already installed
+ for _, installedKey := range k.keys {
+ if bytes.Equal(installedKey, key) {
+ return nil
+ }
+ }
+
+ keys := append(k.keys, key)
+ primaryKey := k.GetPrimaryKey()
+ if primaryKey == nil {
+ primaryKey = key
+ }
+ k.installKeys(keys, primaryKey)
+ return nil
+}
+
+// UseKey changes the key used to encrypt messages. This is the only key used to
+// encrypt messages, so peers should know this key before this method is called.
+func (k *Keyring) UseKey(key []byte) error {
+ for _, installedKey := range k.keys {
+ if bytes.Equal(key, installedKey) {
+ k.installKeys(k.keys, key)
+ return nil
+ }
+ }
+ return fmt.Errorf("requested key is not in the keyring")
+}
+
+// RemoveKey drops a key from the keyring. This will return an error if the key
+// requested for removal is currently at position 0 (primary key).
+func (k *Keyring) RemoveKey(key []byte) error {
+ if bytes.Equal(key, k.keys[0]) {
+ return fmt.Errorf("removing the primary key is not allowed")
+ }
+ for i, installedKey := range k.keys {
+ if bytes.Equal(key, installedKey) {
+ keys := append(k.keys[:i], k.keys[i+1:]...)
+ k.installKeys(keys, k.keys[0])
+ }
+ }
+ return nil
+}
+
+// installKeys will take out a lock on the keyring, and replace the keys with a
+// new set of keys. The key indicated by primaryKey will be installed as the new
+// primary key.
+func (k *Keyring) installKeys(keys [][]byte, primaryKey []byte) {
+ k.l.Lock()
+ defer k.l.Unlock()
+
+ newKeys := [][]byte{primaryKey}
+ for _, key := range keys {
+ if !bytes.Equal(key, primaryKey) {
+ newKeys = append(newKeys, key)
+ }
+ }
+ k.keys = newKeys
+}
+
+// GetKeys returns the current set of keys on the ring.
+func (k *Keyring) GetKeys() [][]byte {
+ k.l.Lock()
+ defer k.l.Unlock()
+
+ return k.keys
+}
+
+// GetPrimaryKey returns the key on the ring at position 0. This is the key used
+// for encrypting messages, and is the first key tried for decrypting messages.
+func (k *Keyring) GetPrimaryKey() (key []byte) {
+ k.l.Lock()
+ defer k.l.Unlock()
+
+ if len(k.keys) > 0 {
+ key = k.keys[0]
+ }
+ return
+}
diff --git a/vendor/github.com/hashicorp/memberlist/label.go b/vendor/github.com/hashicorp/memberlist/label.go
new file mode 100644
index 00000000000..030e6d60a30
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/label.go
@@ -0,0 +1,181 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "net"
+)
+
+// General approach is to prefix all packets and streams with the same structure:
+//
+// magic type byte (244): uint8
+// length of label name: uint8 (because labels can't be longer than 255 bytes)
+// label name: []uint8
+
+// LabelMaxSize is the maximum length of a packet or stream label.
+const LabelMaxSize = 255
+
+// AddLabelHeaderToPacket prefixes outgoing packets with the correct header if
+// the label is not empty.
+func AddLabelHeaderToPacket(buf []byte, label string) ([]byte, error) {
+ if label == "" {
+ return buf, nil
+ }
+ if len(label) > LabelMaxSize {
+ return nil, fmt.Errorf("label %q is too long", label)
+ }
+
+ return makeLabelHeader(label, buf), nil
+}
+
+// RemoveLabelHeaderFromPacket removes any label header from the provided
+// packet and returns it along with the remaining packet contents.
+func RemoveLabelHeaderFromPacket(buf []byte) (newBuf []byte, label string, err error) {
+ if len(buf) == 0 {
+ return buf, "", nil // can't possibly be labeled
+ }
+
+ // [type:byte] [size:byte] [size bytes]
+
+ msgType := messageType(buf[0])
+ if msgType != hasLabelMsg {
+ return buf, "", nil
+ }
+
+ if len(buf) < 2 {
+ return nil, "", fmt.Errorf("cannot decode label; packet has been truncated")
+ }
+
+ size := int(buf[1])
+ if size < 1 {
+ return nil, "", fmt.Errorf("label header cannot be empty when present")
+ }
+
+ if len(buf) < 2+size {
+ return nil, "", fmt.Errorf("cannot decode label; packet has been truncated")
+ }
+
+ label = string(buf[2 : 2+size])
+ newBuf = buf[2+size:]
+
+ return newBuf, label, nil
+}
+
+// AddLabelHeaderToStream prefixes outgoing streams with the correct header if
+// the label is not empty.
+func AddLabelHeaderToStream(conn net.Conn, label string) error {
+ if label == "" {
+ return nil
+ }
+ if len(label) > LabelMaxSize {
+ return fmt.Errorf("label %q is too long", label)
+ }
+
+ header := makeLabelHeader(label, nil)
+
+ _, err := conn.Write(header)
+ return err
+}
+
+// RemoveLabelHeaderFromStream removes any label header from the beginning of
+// the stream if present and returns it along with an updated conn with that
+// header removed.
+//
+// Note that on error it is the caller's responsibility to close the
+// connection.
+func RemoveLabelHeaderFromStream(conn net.Conn) (net.Conn, string, error) {
+ br := bufio.NewReader(conn)
+
+ // First check for the type byte.
+ peeked, err := br.Peek(1)
+ if err != nil {
+ if err == io.EOF {
+ // It is safe to return the original net.Conn at this point because
+ // it never contained any data in the first place so we don't have
+ // to splice the buffer into the conn because both are empty.
+ return conn, "", nil
+ }
+ return nil, "", err
+ }
+
+ msgType := messageType(peeked[0])
+ if msgType != hasLabelMsg {
+ conn, err = newPeekedConnFromBufferedReader(conn, br, 0)
+ return conn, "", err
+ }
+
+ // We are guaranteed to get a size byte as well.
+ peeked, err = br.Peek(2)
+ if err != nil {
+ if err == io.EOF {
+ return nil, "", fmt.Errorf("cannot decode label; stream has been truncated")
+ }
+ return nil, "", err
+ }
+
+ size := int(peeked[1])
+ if size < 1 {
+ return nil, "", fmt.Errorf("label header cannot be empty when present")
+ }
+ // NOTE: we don't have to check this against LabelMaxSize because a byte
+ // already has a max value of 255.
+
+ // Once we know the size we can peek the label as well. Note that since we
+ // are using the default bufio.Reader size of 4096, the entire label header
+ // fits in the initial buffer fill so this should be free.
+ peeked, err = br.Peek(2 + size)
+ if err != nil {
+ if err == io.EOF {
+ return nil, "", fmt.Errorf("cannot decode label; stream has been truncated")
+ }
+ return nil, "", err
+ }
+
+ label := string(peeked[2 : 2+size])
+
+ conn, err = newPeekedConnFromBufferedReader(conn, br, 2+size)
+ if err != nil {
+ return nil, "", err
+ }
+
+ return conn, label, nil
+}
+
+// newPeekedConnFromBufferedReader will splice the buffer contents after the
+// offset into the provided net.Conn and return the result so that the rest of
+// the buffer contents are returned first when reading from the returned
+// peekedConn before moving on to the unbuffered conn contents.
+func newPeekedConnFromBufferedReader(conn net.Conn, br *bufio.Reader, offset int) (*peekedConn, error) {
+ // Extract any of the readahead buffer.
+ peeked, err := br.Peek(br.Buffered())
+ if err != nil {
+ return nil, err
+ }
+
+ return &peekedConn{
+ Peeked: peeked[offset:],
+ Conn: conn,
+ }, nil
+}
+
+func makeLabelHeader(label string, rest []byte) []byte {
+ newBuf := make([]byte, 2, 2+len(label)+len(rest))
+ newBuf[0] = byte(hasLabelMsg)
+ newBuf[1] = byte(len(label))
+ newBuf = append(newBuf, []byte(label)...)
+ if len(rest) > 0 {
+ newBuf = append(newBuf, []byte(rest)...)
+ }
+ return newBuf
+}
+
+func labelOverhead(label string) int {
+ if label == "" {
+ return 0
+ }
+ return 2 + len(label)
+}
diff --git a/vendor/github.com/hashicorp/memberlist/logging.go b/vendor/github.com/hashicorp/memberlist/logging.go
new file mode 100644
index 00000000000..8fe09d406f7
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/logging.go
@@ -0,0 +1,33 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "fmt"
+ "net"
+)
+
+func LogAddress(addr net.Addr) string {
+ if addr == nil {
+ return "from="
+ }
+
+ return fmt.Sprintf("from=%s", addr.String())
+}
+
+func LogStringAddress(addr string) string {
+ if addr == "" {
+ return "from="
+ }
+
+ return fmt.Sprintf("from=%s", addr)
+}
+
+func LogConn(conn net.Conn) string {
+ if conn == nil {
+ return LogAddress(nil)
+ }
+
+ return LogAddress(conn.RemoteAddr())
+}
diff --git a/vendor/github.com/hashicorp/memberlist/memberlist.go b/vendor/github.com/hashicorp/memberlist/memberlist.go
new file mode 100644
index 00000000000..ddf35c76962
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/memberlist.go
@@ -0,0 +1,797 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+/*
+memberlist is a library that manages cluster
+membership and member failure detection using a gossip based protocol.
+
+The use cases for such a library are far-reaching: all distributed systems
+require membership, and memberlist is a re-usable solution to managing
+cluster membership and node failure detection.
+
+memberlist is eventually consistent but converges quickly on average.
+The speed at which it converges can be heavily tuned via various knobs
+on the protocol. Node failures are detected and network partitions are partially
+tolerated by attempting to communicate to potentially dead nodes through
+multiple routes.
+*/
+package memberlist
+
+import (
+ "container/list"
+ "errors"
+ "fmt"
+ "log"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ metrics "github.com/hashicorp/go-metrics/compat"
+ "github.com/hashicorp/go-multierror"
+ "github.com/hashicorp/go-sockaddr"
+ "github.com/miekg/dns"
+)
+
+var errNodeNamesAreRequired = errors.New("memberlist: node names are required by configuration but one was not provided")
+
+type Memberlist struct {
+ sequenceNum uint32 // Local sequence number
+ incarnation uint32 // Local incarnation number
+ numNodes uint32 // Number of known nodes (estimate)
+ pushPullReq uint32 // Number of push/pull requests
+
+ advertiseLock sync.RWMutex
+ advertiseAddr net.IP
+ advertisePort uint16
+
+ config *Config
+ shutdown int32 // Used as an atomic boolean value
+ shutdownCh chan struct{}
+ leave int32 // Used as an atomic boolean value
+ leaveBroadcast chan struct{}
+
+ shutdownLock sync.Mutex // Serializes calls to Shutdown
+ leaveLock sync.Mutex // Serializes calls to Leave
+
+ transport NodeAwareTransport
+
+ handoffCh chan struct{}
+ highPriorityMsgQueue *list.List
+ lowPriorityMsgQueue *list.List
+ msgQueueLock sync.Mutex
+
+ nodeLock sync.RWMutex
+ nodes []*nodeState // Known nodes
+ nodeMap map[string]*nodeState // Maps Node.Name -> NodeState
+ nodeTimers map[string]*suspicion // Maps Node.Name -> suspicion timer
+ awareness *awareness
+
+ tickerLock sync.Mutex
+ tickers []*time.Ticker
+ stopTick chan struct{}
+ probeIndex int
+
+ ackLock sync.Mutex
+ ackHandlers map[uint32]*ackHandler
+
+ broadcasts *TransmitLimitedQueue
+
+ logger *log.Logger
+
+ // metricLabels is the slice of labels to put on all emitted metrics
+ metricLabels []metrics.Label
+}
+
+// BuildVsnArray creates the array of Vsn
+func (conf *Config) BuildVsnArray() []uint8 {
+ return []uint8{
+ ProtocolVersionMin, ProtocolVersionMax, conf.ProtocolVersion,
+ conf.DelegateProtocolMin, conf.DelegateProtocolMax,
+ conf.DelegateProtocolVersion,
+ }
+}
+
+// newMemberlist creates the network listeners.
+// Does not schedule execution of background maintenance.
+func newMemberlist(conf *Config) (*Memberlist, error) {
+ if conf.ProtocolVersion < ProtocolVersionMin {
+ return nil, fmt.Errorf("protocol version '%d' too low. Must be in range: [%d, %d]",
+ conf.ProtocolVersion, ProtocolVersionMin, ProtocolVersionMax)
+ } else if conf.ProtocolVersion > ProtocolVersionMax {
+ return nil, fmt.Errorf("protocol version '%d' too high. Must be in range: [%d, %d]",
+ conf.ProtocolVersion, ProtocolVersionMin, ProtocolVersionMax)
+ }
+
+ if len(conf.SecretKey) > 0 {
+ if conf.Keyring == nil {
+ keyring, err := NewKeyring(nil, conf.SecretKey)
+ if err != nil {
+ return nil, err
+ }
+ conf.Keyring = keyring
+ } else {
+ if err := conf.Keyring.AddKey(conf.SecretKey); err != nil {
+ return nil, err
+ }
+ if err := conf.Keyring.UseKey(conf.SecretKey); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ if conf.LogOutput != nil && conf.Logger != nil {
+ return nil, fmt.Errorf("cannot specify both LogOutput and Logger; please choose a single log configuration setting")
+ }
+
+ logDest := conf.LogOutput
+ if logDest == nil {
+ logDest = os.Stderr
+ }
+
+ logger := conf.Logger
+ if logger == nil {
+ logger = log.New(logDest, "", log.LstdFlags)
+ }
+
+ // Set up a network transport by default if a custom one wasn't given
+ // by the config.
+ transport := conf.Transport
+ if transport == nil {
+ nc := &NetTransportConfig{
+ BindAddrs: []string{conf.BindAddr},
+ BindPort: conf.BindPort,
+ Logger: logger,
+ MetricLabels: conf.MetricLabels,
+ }
+
+ // See comment below for details about the retry in here.
+ makeNetRetry := func(limit int) (*NetTransport, error) {
+ var err error
+ for try := 0; try < limit; try++ {
+ var nt *NetTransport
+ if nt, err = NewNetTransport(nc); err == nil {
+ return nt, nil
+ }
+ if strings.Contains(err.Error(), "address already in use") {
+ logger.Printf("[DEBUG] memberlist: Got bind error: %v", err)
+ continue
+ }
+ }
+
+ return nil, fmt.Errorf("failed to obtain an address: %v", err)
+ }
+
+ // The dynamic bind port operation is inherently racy because
+ // even though we are using the kernel to find a port for us, we
+ // are attempting to bind multiple protocols (and potentially
+ // multiple addresses) with the same port number. We build in a
+ // few retries here since this often gets transient errors in
+ // busy unit tests.
+ limit := 1
+ if conf.BindPort == 0 {
+ limit = 10
+ }
+
+ nt, err := makeNetRetry(limit)
+ if err != nil {
+ return nil, fmt.Errorf("could not set up network transport: %v", err)
+ }
+ if conf.BindPort == 0 {
+ port := nt.GetAutoBindPort()
+ conf.BindPort = port
+ conf.AdvertisePort = port
+ logger.Printf("[DEBUG] memberlist: Using dynamic bind port %d", port)
+ }
+ transport = nt
+ }
+
+ nodeAwareTransport, ok := transport.(NodeAwareTransport)
+ if !ok {
+ logger.Printf("[DEBUG] memberlist: configured Transport is not a NodeAwareTransport and some features may not work as desired")
+ nodeAwareTransport = &shimNodeAwareTransport{transport}
+ }
+
+ if len(conf.Label) > LabelMaxSize {
+ return nil, fmt.Errorf("could not use %q as a label: too long", conf.Label)
+ }
+
+ if conf.Label != "" {
+ nodeAwareTransport = &labelWrappedTransport{
+ label: conf.Label,
+ NodeAwareTransport: nodeAwareTransport,
+ }
+ }
+
+ m := &Memberlist{
+ config: conf,
+ shutdownCh: make(chan struct{}),
+ leaveBroadcast: make(chan struct{}, 1),
+ transport: nodeAwareTransport,
+ handoffCh: make(chan struct{}, 1),
+ highPriorityMsgQueue: list.New(),
+ lowPriorityMsgQueue: list.New(),
+ nodeMap: make(map[string]*nodeState),
+ nodeTimers: make(map[string]*suspicion),
+ awareness: newAwareness(conf.AwarenessMaxMultiplier, conf.MetricLabels),
+ ackHandlers: make(map[uint32]*ackHandler),
+ broadcasts: &TransmitLimitedQueue{RetransmitMult: conf.RetransmitMult},
+ logger: logger,
+ metricLabels: conf.MetricLabels,
+ }
+ m.broadcasts.NumNodes = func() int {
+ return m.estNumNodes()
+ }
+
+ // Get the final advertise address from the transport, which may need
+ // to see which address we bound to. We'll refresh this each time we
+ // send out an alive message.
+ if _, _, err := m.refreshAdvertise(); err != nil {
+ return nil, err
+ }
+
+ go m.streamListen()
+ go m.packetListen()
+ go m.packetHandler()
+ go m.checkBroadcastQueueDepth()
+ return m, nil
+}
+
+// Create will create a new Memberlist using the given configuration.
+// This will not connect to any other node (see Join) yet, but will start
+// all the listeners to allow other nodes to join this memberlist.
+// After creating a Memberlist, the configuration given should not be
+// modified by the user anymore.
+func Create(conf *Config) (*Memberlist, error) {
+ m, err := newMemberlist(conf)
+ if err != nil {
+ return nil, err
+ }
+ if err := m.setAlive(); err != nil {
+ _ = m.Shutdown()
+ return nil, err
+ }
+ m.schedule()
+ return m, nil
+}
+
+// Join is used to take an existing Memberlist and attempt to join a cluster
+// by contacting all the given hosts and performing a state sync. Initially,
+// the Memberlist only contains our own state, so doing this will cause
+// remote nodes to become aware of the existence of this node, effectively
+// joining the cluster.
+//
+// This returns the number of hosts successfully contacted and an error if
+// none could be reached. If an error is returned, the node did not successfully
+// join the cluster.
+func (m *Memberlist) Join(existing []string) (int, error) {
+ numSuccess := 0
+ var errs error
+ for _, exist := range existing {
+ addrs, err := m.resolveAddr(exist)
+ if err != nil {
+ err = fmt.Errorf("failed to resolve %s: %v", exist, err)
+ errs = multierror.Append(errs, err)
+ m.logger.Printf("[WARN] memberlist: %v", err)
+ continue
+ }
+
+ for _, addr := range addrs {
+ hp := joinHostPort(addr.ip.String(), addr.port)
+ a := Address{Addr: hp, Name: addr.nodeName}
+ if err := m.pushPullNode(a, true); err != nil {
+ err = fmt.Errorf("failed to join %s: %v", a.Addr, err)
+ errs = multierror.Append(errs, err)
+ m.logger.Printf("[DEBUG] memberlist: %v", err)
+ continue
+ }
+ numSuccess++
+ }
+
+ }
+ if numSuccess > 0 {
+ errs = nil
+ }
+ return numSuccess, errs
+}
+
+// ipPort holds information about a node we want to try to join.
+type ipPort struct {
+ ip net.IP
+ port uint16
+ nodeName string // optional
+}
+
+// tcpLookupIP is a helper to initiate a TCP-based DNS lookup for the given host.
+// The built-in Go resolver will do a UDP lookup first, and will only use TCP if
+// the response has the truncate bit set, which isn't common on DNS servers like
+// Consul's. By doing the TCP lookup directly, we get the best chance for the
+// largest list of hosts to join. Since joins are relatively rare events, it's ok
+// to do this rather expensive operation.
+func (m *Memberlist) tcpLookupIP(host string, defaultPort uint16, nodeName string) ([]ipPort, error) {
+ // Don't attempt any TCP lookups against non-fully qualified domain
+ // names, since those will likely come from the resolv.conf file.
+ if !strings.Contains(host, ".") {
+ return nil, nil
+ }
+
+ // Make sure the domain name is terminated with a dot (we know there's
+ // at least one character at this point).
+ dn := host
+ if dn[len(dn)-1] != '.' {
+ dn = dn + "."
+ }
+
+ // See if we can find a server to try.
+ cc, err := dns.ClientConfigFromFile(m.config.DNSConfigPath)
+ if err != nil {
+ return nil, err
+ }
+ if len(cc.Servers) > 0 {
+ // We support host:port in the DNS config, but need to add the
+ // default port if one is not supplied.
+ server := cc.Servers[0]
+ if !hasPort(server) {
+ server = net.JoinHostPort(server, cc.Port)
+ }
+
+ // Do the lookup.
+ c := new(dns.Client)
+ c.Net = "tcp"
+ msg := new(dns.Msg)
+ msg.SetQuestion(dn, dns.TypeANY)
+ in, _, err := c.Exchange(msg, server)
+ if err != nil {
+ return nil, err
+ }
+
+ // Handle any IPs we get back that we can attempt to join.
+ var ips []ipPort
+ for _, r := range in.Answer {
+ switch rr := r.(type) {
+ case (*dns.A):
+ ips = append(ips, ipPort{ip: rr.A, port: defaultPort, nodeName: nodeName})
+ case (*dns.AAAA):
+ ips = append(ips, ipPort{ip: rr.AAAA, port: defaultPort, nodeName: nodeName})
+ case (*dns.CNAME):
+ m.logger.Printf("[DEBUG] memberlist: Ignoring CNAME RR in TCP-first answer for '%s'", host)
+ }
+ }
+ return ips, nil
+ }
+
+ return nil, nil
+}
+
+// resolveAddr is used to resolve the address into an address,
+// port, and error. If no port is given, use the default
+func (m *Memberlist) resolveAddr(hostStr string) ([]ipPort, error) {
+ // First peel off any leading node name. This is optional.
+ nodeName := ""
+ if slashIdx := strings.Index(hostStr, "/"); slashIdx >= 0 {
+ if slashIdx == 0 {
+ return nil, fmt.Errorf("empty node name provided")
+ }
+ nodeName = hostStr[0:slashIdx]
+ hostStr = hostStr[slashIdx+1:]
+ }
+
+ // This captures the supplied port, or the default one.
+ hostStr = ensurePort(hostStr, m.config.BindPort)
+ host, sport, err := net.SplitHostPort(hostStr)
+ if err != nil {
+ return nil, err
+ }
+ lport, err := strconv.ParseUint(sport, 10, 16)
+ if err != nil {
+ return nil, err
+ }
+ port := uint16(lport)
+
+ // If it looks like an IP address we are done. The SplitHostPort() above
+ // will make sure the host part is in good shape for parsing, even for
+ // IPv6 addresses.
+ if ip := net.ParseIP(host); ip != nil {
+ return []ipPort{
+ ipPort{ip: ip, port: port, nodeName: nodeName},
+ }, nil
+ }
+
+ // First try TCP so we have the best chance for the largest list of
+ // hosts to join. If this fails it's not fatal since this isn't a standard
+ // way to query DNS, and we have a fallback below.
+ ips, err := m.tcpLookupIP(host, port, nodeName)
+ if err != nil {
+ m.logger.Printf("[DEBUG] memberlist: TCP-first lookup failed for '%s', falling back to UDP: %s", hostStr, err)
+ }
+ if len(ips) > 0 {
+ return ips, nil
+ }
+
+ // If TCP didn't yield anything then use the normal Go resolver which
+ // will try UDP, then might possibly try TCP again if the UDP response
+ // indicates it was truncated.
+ ans, err := net.LookupIP(host)
+ if err != nil {
+ return nil, err
+ }
+ ips = make([]ipPort, 0, len(ans))
+ for _, ip := range ans {
+ ips = append(ips, ipPort{ip: ip, port: port, nodeName: nodeName})
+ }
+ return ips, nil
+}
+
+// setAlive is used to mark this node as being alive. This is the same
+// as if we received an alive notification our own network channel for
+// ourself.
+func (m *Memberlist) setAlive() error {
+ // Get the final advertise address from the transport, which may need
+ // to see which address we bound to.
+ addr, port, err := m.refreshAdvertise()
+ if err != nil {
+ return err
+ }
+
+ // Check if this is a public address without encryption
+ ipAddr, err := sockaddr.NewIPAddr(addr.String())
+ if err != nil {
+ return fmt.Errorf("failed to parse interface addresses: %v", err)
+ }
+ ifAddrs := []sockaddr.IfAddr{
+ sockaddr.IfAddr{
+ SockAddr: ipAddr,
+ },
+ }
+ _, publicIfs, _ := sockaddr.IfByRFC("6890", ifAddrs)
+
+ if len(publicIfs) > 0 && !m.config.EncryptionEnabled() {
+ m.logger.Printf("[WARN] memberlist: Binding to public address without encryption!")
+ }
+
+ // Set any metadata from the delegate.
+ var meta []byte
+ if m.config.Delegate != nil {
+ meta = m.config.Delegate.NodeMeta(MetaMaxSize)
+ if len(meta) > MetaMaxSize {
+ panic("Node meta data provided is longer than the limit")
+ }
+ }
+
+ a := alive{
+ Incarnation: m.nextIncarnation(),
+ Node: m.config.Name,
+ Addr: addr,
+ Port: uint16(port),
+ Meta: meta,
+ Vsn: m.config.BuildVsnArray(),
+ }
+ m.aliveNode(&a, nil, true)
+
+ return nil
+}
+
+func (m *Memberlist) getAdvertise() (net.IP, uint16) {
+ m.advertiseLock.RLock()
+ defer m.advertiseLock.RUnlock()
+ return m.advertiseAddr, m.advertisePort
+}
+
+func (m *Memberlist) setAdvertise(addr net.IP, port int) {
+ m.advertiseLock.Lock()
+ defer m.advertiseLock.Unlock()
+ m.advertiseAddr = addr
+ m.advertisePort = uint16(port)
+}
+
+func (m *Memberlist) refreshAdvertise() (net.IP, int, error) {
+ addr, port, err := m.transport.FinalAdvertiseAddr(
+ m.config.AdvertiseAddr, m.config.AdvertisePort)
+ if err != nil {
+ return nil, 0, fmt.Errorf("failed to get final advertise address: %v", err)
+ }
+ m.setAdvertise(addr, port)
+ return addr, port, nil
+}
+
+// LocalNode is used to return the local Node
+func (m *Memberlist) LocalNode() *Node {
+ m.nodeLock.RLock()
+ defer m.nodeLock.RUnlock()
+ state := m.nodeMap[m.config.Name]
+ return &state.Node
+}
+
+// UpdateNode is used to trigger re-advertising the local node. This is
+// primarily used with a Delegate to support dynamic updates to the local
+// meta data. This will block until the update message is successfully
+// broadcasted to a member of the cluster, if any exist or until a specified
+// timeout is reached.
+func (m *Memberlist) UpdateNode(timeout time.Duration) error {
+ // Get the node meta data
+ var meta []byte
+ if m.config.Delegate != nil {
+ meta = m.config.Delegate.NodeMeta(MetaMaxSize)
+ if len(meta) > MetaMaxSize {
+ panic("Node meta data provided is longer than the limit")
+ }
+ }
+
+ // Get the existing node
+ m.nodeLock.RLock()
+ state := m.nodeMap[m.config.Name]
+ m.nodeLock.RUnlock()
+
+ // Format a new alive message
+ a := alive{
+ Incarnation: m.nextIncarnation(),
+ Node: m.config.Name,
+ Addr: state.Addr,
+ Port: state.Port,
+ Meta: meta,
+ Vsn: m.config.BuildVsnArray(),
+ }
+ notifyCh := make(chan struct{})
+ m.aliveNode(&a, notifyCh, true)
+
+ // Wait for the broadcast or a timeout
+ if m.anyAlive() {
+ var timeoutCh <-chan time.Time
+ if timeout > 0 {
+ timeoutCh = time.After(timeout)
+ }
+ select {
+ case <-notifyCh:
+ case <-timeoutCh:
+ return fmt.Errorf("timeout waiting for update broadcast")
+ }
+ }
+ return nil
+}
+
+// Deprecated: SendTo is deprecated in favor of SendBestEffort, which requires a node to
+// target. If you don't have a node then use SendToAddress.
+func (m *Memberlist) SendTo(to net.Addr, msg []byte) error {
+ a := Address{Addr: to.String(), Name: ""}
+ return m.SendToAddress(a, msg)
+}
+
+func (m *Memberlist) SendToAddress(a Address, msg []byte) error {
+ // Encode as a user message
+ buf := make([]byte, 1, len(msg)+1)
+ buf[0] = byte(userMsg)
+ buf = append(buf, msg...)
+
+ // Send the message
+ return m.rawSendMsgPacket(a, nil, buf)
+}
+
+// Deprecated: SendToUDP is deprecated in favor of SendBestEffort.
+func (m *Memberlist) SendToUDP(to *Node, msg []byte) error {
+ return m.SendBestEffort(to, msg)
+}
+
+// Deprecated: SendToTCP is deprecated in favor of SendReliable.
+func (m *Memberlist) SendToTCP(to *Node, msg []byte) error {
+ return m.SendReliable(to, msg)
+}
+
+// SendBestEffort uses the unreliable packet-oriented interface of the transport
+// to target a user message at the given node (this does not use the gossip
+// mechanism). The maximum size of the message depends on the configured
+// UDPBufferSize for this memberlist instance.
+func (m *Memberlist) SendBestEffort(to *Node, msg []byte) error {
+ // Encode as a user message
+ buf := make([]byte, 1, len(msg)+1)
+ buf[0] = byte(userMsg)
+ buf = append(buf, msg...)
+
+ // Send the message
+ a := Address{Addr: to.Address(), Name: to.Name}
+ return m.rawSendMsgPacket(a, to, buf)
+}
+
+// SendReliable uses the reliable stream-oriented interface of the transport to
+// target a user message at the given node (this does not use the gossip
+// mechanism). Delivery is guaranteed if no error is returned, and there is no
+// limit on the size of the message.
+func (m *Memberlist) SendReliable(to *Node, msg []byte) error {
+ return m.sendUserMsg(to.FullAddress(), msg)
+}
+
+// Members returns a list of all known live nodes. The node structures
+// returned must not be modified. If you wish to modify a Node, make a
+// copy first.
+func (m *Memberlist) Members() []*Node {
+ m.nodeLock.RLock()
+ defer m.nodeLock.RUnlock()
+
+ nodes := make([]*Node, 0, len(m.nodes))
+ for _, n := range m.nodes {
+ if !n.DeadOrLeft() {
+ nodes = append(nodes, &n.Node)
+ }
+ }
+
+ return nodes
+}
+
+// NumMembers returns the number of alive nodes currently known. Between
+// the time of calling this and calling Members, the number of alive nodes
+// may have changed, so this shouldn't be used to determine how many
+// members will be returned by Members.
+func (m *Memberlist) NumMembers() (alive int) {
+ m.nodeLock.RLock()
+ defer m.nodeLock.RUnlock()
+
+ for _, n := range m.nodes {
+ if !n.DeadOrLeft() {
+ alive++
+ }
+ }
+
+ return
+}
+
+// Leave will broadcast a leave message but will not shutdown the background
+// listeners, meaning the node will continue participating in gossip and state
+// updates.
+//
+// This will block until the leave message is successfully broadcasted to
+// a member of the cluster, if any exist or until a specified timeout
+// is reached.
+//
+// This method is safe to call multiple times, but must not be called
+// after the cluster is already shut down.
+func (m *Memberlist) Leave(timeout time.Duration) error {
+ m.leaveLock.Lock()
+ defer m.leaveLock.Unlock()
+
+ if m.hasShutdown() {
+ panic("leave after shutdown")
+ }
+
+ if !m.hasLeft() {
+ atomic.StoreInt32(&m.leave, 1)
+
+ m.nodeLock.Lock()
+ state, ok := m.nodeMap[m.config.Name]
+ m.nodeLock.Unlock()
+ if !ok {
+ m.logger.Printf("[WARN] memberlist: Leave but we're not in the node map.")
+ return nil
+ }
+
+ // This dead message is special, because Node and From are the
+ // same. This helps other nodes figure out that a node left
+ // intentionally. When Node equals From, other nodes know for
+ // sure this node is gone.
+ d := dead{
+ Incarnation: state.Incarnation,
+ Node: state.Name,
+ From: state.Name,
+ }
+ m.deadNode(&d)
+
+ // Block until the broadcast goes out
+ if m.anyAlive() {
+ var timeoutCh <-chan time.Time
+ if timeout > 0 {
+ timeoutCh = time.After(timeout)
+ }
+ select {
+ case <-m.leaveBroadcast:
+ case <-timeoutCh:
+ return fmt.Errorf("timeout waiting for leave broadcast")
+ }
+ }
+ }
+
+ return nil
+}
+
+// Check for any other alive node.
+func (m *Memberlist) anyAlive() bool {
+ m.nodeLock.RLock()
+ defer m.nodeLock.RUnlock()
+ for _, n := range m.nodes {
+ if !n.DeadOrLeft() && n.Name != m.config.Name {
+ return true
+ }
+ }
+ return false
+}
+
+// GetHealthScore gives this instance's idea of how well it is meeting the soft
+// real-time requirements of the protocol. Lower numbers are better, and zero
+// means "totally healthy".
+func (m *Memberlist) GetHealthScore() int {
+ return m.awareness.GetHealthScore()
+}
+
+// ProtocolVersion returns the protocol version currently in use by
+// this memberlist.
+func (m *Memberlist) ProtocolVersion() uint8 {
+ // NOTE: This method exists so that in the future we can control
+ // any locking if necessary, if we change the protocol version at
+ // runtime, etc.
+ return m.config.ProtocolVersion
+}
+
+// Shutdown will stop any background maintenance of network activity
+// for this memberlist, causing it to appear "dead". A leave message
+// will not be broadcasted prior, so the cluster being left will have
+// to detect this node's shutdown using probing. If you wish to more
+// gracefully exit the cluster, call Leave prior to shutting down.
+//
+// This method is safe to call multiple times.
+func (m *Memberlist) Shutdown() error {
+ m.shutdownLock.Lock()
+ defer m.shutdownLock.Unlock()
+
+ if m.hasShutdown() {
+ return nil
+ }
+
+ // Shut down the transport first, which should block until it's
+ // completely torn down. If we kill the memberlist-side handlers
+ // those I/O handlers might get stuck.
+ if err := m.transport.Shutdown(); err != nil {
+ m.logger.Printf("[ERR] Failed to shutdown transport: %v", err)
+ }
+
+ // Now tear down everything else.
+ atomic.StoreInt32(&m.shutdown, 1)
+ close(m.shutdownCh)
+ m.deschedule()
+ return nil
+}
+
+func (m *Memberlist) hasShutdown() bool {
+ return atomic.LoadInt32(&m.shutdown) == 1
+}
+
+func (m *Memberlist) hasLeft() bool {
+ return atomic.LoadInt32(&m.leave) == 1
+}
+
+func (m *Memberlist) getNodeState(addr string) NodeStateType {
+ m.nodeLock.RLock()
+ defer m.nodeLock.RUnlock()
+
+ n := m.nodeMap[addr]
+ return n.State
+}
+
+func (m *Memberlist) getNodeStateChange(addr string) time.Time {
+ m.nodeLock.RLock()
+ defer m.nodeLock.RUnlock()
+
+ n := m.nodeMap[addr]
+ return n.StateChange
+}
+
+func (m *Memberlist) changeNode(addr string, f func(*nodeState)) {
+ m.nodeLock.Lock()
+ defer m.nodeLock.Unlock()
+
+ n := m.nodeMap[addr]
+ f(n)
+}
+
+// checkBroadcastQueueDepth periodically checks the size of the broadcast queue
+// to see if it is too large
+func (m *Memberlist) checkBroadcastQueueDepth() {
+ for {
+ select {
+ case <-time.After(m.config.QueueCheckInterval):
+ numq := m.broadcasts.NumQueued()
+ metrics.AddSampleWithLabels([]string{"memberlist", "queue", "broadcasts"}, float32(numq), m.metricLabels)
+ case <-m.shutdownCh:
+ return
+ }
+ }
+}
diff --git a/vendor/github.com/hashicorp/memberlist/merge_delegate.go b/vendor/github.com/hashicorp/memberlist/merge_delegate.go
new file mode 100644
index 00000000000..12e852b7a48
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/merge_delegate.go
@@ -0,0 +1,17 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+// MergeDelegate is used to involve a client in
+// a potential cluster merge operation. Namely, when
+// a node does a TCP push/pull (as part of a join),
+// the delegate is involved and allowed to cancel the join
+// based on custom logic. The merge delegate is NOT invoked
+// as part of the push-pull anti-entropy.
+type MergeDelegate interface {
+ // NotifyMerge is invoked when a merge could take place.
+ // Provides a list of the nodes known by the peer. If
+ // the return value is non-nil, the merge is canceled.
+ NotifyMerge(peers []*Node) error
+}
diff --git a/vendor/github.com/hashicorp/memberlist/mock_transport.go b/vendor/github.com/hashicorp/memberlist/mock_transport.go
new file mode 100644
index 00000000000..e884958bc53
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/mock_transport.go
@@ -0,0 +1,200 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "net"
+ "strconv"
+ "time"
+)
+
+// MockNetwork is used as a factory that produces MockTransport instances which
+// are uniquely addressed and wired up to talk to each other.
+type MockNetwork struct {
+ transportsByAddr map[string]*MockTransport
+ transportsByName map[string]*MockTransport
+ port int
+}
+
+// NewTransport returns a new MockTransport with a unique address, wired up to
+// talk to the other transports in the MockNetwork.
+func (n *MockNetwork) NewTransport(name string) *MockTransport {
+ n.port += 1
+ addr := fmt.Sprintf("127.0.0.1:%d", n.port)
+ transport := &MockTransport{
+ net: n,
+ addr: &MockAddress{addr, name},
+ packetCh: make(chan *Packet),
+ streamCh: make(chan net.Conn),
+ }
+
+ if n.transportsByAddr == nil {
+ n.transportsByAddr = make(map[string]*MockTransport)
+ }
+ n.transportsByAddr[addr] = transport
+
+ if n.transportsByName == nil {
+ n.transportsByName = make(map[string]*MockTransport)
+ }
+ n.transportsByName[name] = transport
+
+ return transport
+}
+
+// MockAddress is a wrapper which adds the net.Addr interface to our mock
+// address scheme.
+type MockAddress struct {
+ addr string
+ name string
+}
+
+// See net.Addr.
+func (a *MockAddress) Network() string {
+ return "mock"
+}
+
+// See net.Addr.
+func (a *MockAddress) String() string {
+ return a.addr
+}
+
+// MockTransport directly plumbs messages to other transports its MockNetwork.
+type MockTransport struct {
+ net *MockNetwork
+ addr *MockAddress
+ packetCh chan *Packet
+ streamCh chan net.Conn
+}
+
+var _ NodeAwareTransport = (*MockTransport)(nil)
+
+// See Transport.
+func (t *MockTransport) FinalAdvertiseAddr(string, int) (net.IP, int, error) {
+ host, portStr, err := net.SplitHostPort(t.addr.String())
+ if err != nil {
+ return nil, 0, err
+ }
+
+ ip := net.ParseIP(host)
+ if ip == nil {
+ return nil, 0, fmt.Errorf("failed to parse IP %q", host)
+ }
+
+ port, err := strconv.ParseInt(portStr, 10, 16)
+ if err != nil {
+ return nil, 0, err
+ }
+
+ return ip, int(port), nil
+}
+
+// See Transport.
+func (t *MockTransport) WriteTo(b []byte, addr string) (time.Time, error) {
+ a := Address{Addr: addr, Name: ""}
+ return t.WriteToAddress(b, a)
+}
+
+// See NodeAwareTransport.
+func (t *MockTransport) WriteToAddress(b []byte, a Address) (time.Time, error) {
+ dest, err := t.getPeer(a)
+ if err != nil {
+ return time.Time{}, err
+ }
+
+ now := time.Now()
+ dest.packetCh <- &Packet{
+ Buf: b,
+ From: t.addr,
+ Timestamp: now,
+ }
+ return now, nil
+}
+
+// See Transport.
+func (t *MockTransport) PacketCh() <-chan *Packet {
+ return t.packetCh
+}
+
+// See NodeAwareTransport.
+func (t *MockTransport) IngestPacket(conn net.Conn, addr net.Addr, now time.Time, shouldClose bool) error {
+ if shouldClose {
+ defer func() {
+ _ = conn.Close()
+ }()
+ }
+
+ // Copy everything from the stream into packet buffer.
+ var buf bytes.Buffer
+ if _, err := io.Copy(&buf, conn); err != nil {
+ return fmt.Errorf("failed to read packet: %v", err)
+ }
+
+ // Check the length - it needs to have at least one byte to be a proper
+ // message. This is checked elsewhere for writes coming in directly from
+ // the UDP socket.
+ if n := buf.Len(); n < 1 {
+ return fmt.Errorf("packet too short (%d bytes) %s", n, LogAddress(addr))
+ }
+
+ // Inject the packet.
+ t.packetCh <- &Packet{
+ Buf: buf.Bytes(),
+ From: addr,
+ Timestamp: now,
+ }
+ return nil
+}
+
+// See Transport.
+func (t *MockTransport) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) {
+ a := Address{Addr: addr, Name: ""}
+ return t.DialAddressTimeout(a, timeout)
+}
+
+// See NodeAwareTransport.
+func (t *MockTransport) DialAddressTimeout(a Address, timeout time.Duration) (net.Conn, error) {
+ dest, err := t.getPeer(a)
+ if err != nil {
+ return nil, err
+ }
+
+ p1, p2 := net.Pipe()
+ dest.streamCh <- p1
+ return p2, nil
+}
+
+// See Transport.
+func (t *MockTransport) StreamCh() <-chan net.Conn {
+ return t.streamCh
+}
+
+// See NodeAwareTransport.
+func (t *MockTransport) IngestStream(conn net.Conn) error {
+ t.streamCh <- conn
+ return nil
+}
+
+// See Transport.
+func (t *MockTransport) Shutdown() error {
+ return nil
+}
+
+func (t *MockTransport) getPeer(a Address) (*MockTransport, error) {
+ var (
+ dest *MockTransport
+ ok bool
+ )
+ if a.Name != "" {
+ dest, ok = t.net.transportsByName[a.Name]
+ } else {
+ dest, ok = t.net.transportsByAddr[a.Addr]
+ }
+ if !ok {
+ return nil, fmt.Errorf("no route to %s", a)
+ }
+ return dest, nil
+}
diff --git a/vendor/github.com/hashicorp/memberlist/net.go b/vendor/github.com/hashicorp/memberlist/net.go
new file mode 100644
index 00000000000..2077ea870b5
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/net.go
@@ -0,0 +1,1393 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "hash/crc32"
+ "io"
+ "math"
+ "net"
+ "sync/atomic"
+ "time"
+
+ metrics "github.com/hashicorp/go-metrics/compat"
+ "github.com/hashicorp/go-msgpack/v2/codec"
+)
+
+// This is the minimum and maximum protocol version that we can
+// _understand_. We're allowed to speak at any version within this
+// range. This range is inclusive.
+const (
+ ProtocolVersionMin uint8 = 1
+
+ // Version 3 added support for TCP pings but we kept the default
+ // protocol version at 2 to ease transition to this new feature.
+ // A memberlist speaking version 2 of the protocol will attempt
+ // to TCP ping another memberlist who understands version 3 or
+ // greater.
+ //
+ // Version 4 added support for nacks as part of indirect probes.
+ // A memberlist speaking version 2 of the protocol will expect
+ // nacks from another memberlist who understands version 4 or
+ // greater, and likewise nacks will be sent to memberlists who
+ // understand version 4 or greater.
+ ProtocolVersion2Compatible = 2
+
+ ProtocolVersionMax = 5
+)
+
+// messageType is an integer ID of a type of message that can be received
+// on network channels from other members.
+type messageType uint8
+
+// The list of available message types.
+//
+// WARNING: ONLY APPEND TO THIS LIST! The numeric values are part of the
+// protocol itself.
+const (
+ pingMsg messageType = iota
+ indirectPingMsg
+ ackRespMsg
+ suspectMsg
+ aliveMsg
+ deadMsg
+ pushPullMsg
+ compoundMsg
+ userMsg // User mesg, not handled by us
+ compressMsg
+ encryptMsg
+ nackRespMsg
+ hasCrcMsg
+ errMsg
+)
+
+const (
+ // hasLabelMsg has a deliberately high value so that you can disambiguate
+ // it from the encryptionVersion header which is either 0/1 right now and
+ // also any of the existing messageTypes
+ hasLabelMsg messageType = 244
+)
+
+// compressionType is used to specify the compression algorithm
+type compressionType uint8
+
+const (
+ lzwAlgo compressionType = iota
+)
+
+const (
+ MetaMaxSize = 512 // Maximum size for node meta data
+ compoundHeaderOverhead = 2 // Assumed header overhead
+ compoundOverhead = 2 // Assumed overhead per entry in compoundHeader
+ userMsgOverhead = 1
+ blockingWarning = 10 * time.Millisecond // Warn if a UDP packet takes this long to process
+ maxPushStateBytes = 20 * 1024 * 1024
+ maxPushPullRequests = 128 // Maximum number of concurrent push/pull requests
+)
+
+// ping request sent directly to node
+type ping struct {
+ SeqNo uint32
+
+ // Node is sent so the target can verify they are
+ // the intended recipient. This is to protect again an agent
+ // restart with a new name.
+ Node string
+
+ SourceAddr []byte `codec:",omitempty"` // Source address, used for a direct reply
+ SourcePort uint16 `codec:",omitempty"` // Source port, used for a direct reply
+ SourceNode string `codec:",omitempty"` // Source name, used for a direct reply
+}
+
+// indirect ping sent to an indirect node
+type indirectPingReq struct {
+ SeqNo uint32
+ Target []byte
+ Port uint16
+
+ // Node is sent so the target can verify they are
+ // the intended recipient. This is to protect against an agent
+ // restart with a new name.
+ Node string
+
+ Nack bool // true if we'd like a nack back
+
+ SourceAddr []byte `codec:",omitempty"` // Source address, used for a direct reply
+ SourcePort uint16 `codec:",omitempty"` // Source port, used for a direct reply
+ SourceNode string `codec:",omitempty"` // Source name, used for a direct reply
+}
+
+// ack response is sent for a ping
+type ackResp struct {
+ SeqNo uint32
+ Payload []byte
+}
+
+// nack response is sent for an indirect ping when the pinger doesn't hear from
+// the ping-ee within the configured timeout. This lets the original node know
+// that the indirect ping attempt happened but didn't succeed.
+type nackResp struct {
+ SeqNo uint32
+}
+
+// err response is sent to relay the error from the remote end
+type errResp struct {
+ Error string
+}
+
+// suspect is broadcast when we suspect a node is dead
+type suspect struct {
+ Incarnation uint32
+ Node string
+ From string // Include who is suspecting
+}
+
+// alive is broadcast when we know a node is alive.
+// Overloaded for nodes joining
+type alive struct {
+ Incarnation uint32
+ Node string
+ Addr []byte
+ Port uint16
+ Meta []byte
+
+ // The versions of the protocol/delegate that are being spoken, order:
+ // pmin, pmax, pcur, dmin, dmax, dcur
+ Vsn []uint8
+}
+
+// dead is broadcast when we confirm a node is dead
+// Overloaded for nodes leaving
+type dead struct {
+ Incarnation uint32
+ Node string
+ From string // Include who is suspecting
+}
+
+// pushPullHeader is used to inform the
+// otherside how many states we are transferring
+type pushPullHeader struct {
+ Nodes int
+ UserStateLen int // Encodes the byte lengh of user state
+ Join bool // Is this a join request or a anti-entropy run
+}
+
+// userMsgHeader is used to encapsulate a userMsg
+type userMsgHeader struct {
+ UserMsgLen int // Encodes the byte lengh of user state
+}
+
+// pushNodeState is used for pushPullReq when we are
+// transferring out node states
+type pushNodeState struct {
+ Name string
+ Addr []byte
+ Port uint16
+ Meta []byte
+ Incarnation uint32
+ State NodeStateType
+ Vsn []uint8 // Protocol versions
+}
+
+// compress is used to wrap an underlying payload
+// using a specified compression algorithm
+type compress struct {
+ Algo compressionType
+ Buf []byte
+}
+
+// msgHandoff is used to transfer a message between goroutines
+type msgHandoff struct {
+ msgType messageType
+ buf []byte
+ from net.Addr
+}
+
+// encryptionVersion returns the encryption version to use
+func (m *Memberlist) encryptionVersion() encryptionVersion {
+ switch m.ProtocolVersion() {
+ case 1:
+ return 0
+ default:
+ return 1
+ }
+}
+
+// streamListen is a long running goroutine that pulls incoming streams from the
+// transport and hands them off for processing.
+func (m *Memberlist) streamListen() {
+ for {
+ select {
+ case conn := <-m.transport.StreamCh():
+ go m.handleConn(conn)
+
+ case <-m.shutdownCh:
+ return
+ }
+ }
+}
+
+// handleConn handles a single incoming stream connection from the transport.
+func (m *Memberlist) handleConn(conn net.Conn) {
+ m.logger.Printf("[DEBUG] memberlist: Stream connection %s", LogConn(conn))
+
+ metrics.IncrCounterWithLabels([]string{"memberlist", "tcp", "accept"}, 1, m.metricLabels)
+
+ if err := conn.SetDeadline(time.Now().Add(m.config.TCPTimeout)); err != nil {
+ m.logger.Printf("Err: Could not set the deadline: %s", err)
+ }
+
+ var (
+ streamLabel string
+ err error
+ // Store the original conn, because the code below shadows it.
+ // If reading the label header from the stream fail, we should still close the connection.
+ origConn = conn
+ )
+ conn, streamLabel, err = RemoveLabelHeaderFromStream(conn)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: failed to receive and remove the stream label header: %s %s", err, LogConn(origConn))
+ _ = origConn.Close()
+ return
+ }
+
+ defer func() {
+ // Always close the wrapped connection, that we got after removing the label header.
+ _ = conn.Close()
+ }()
+
+ if m.config.SkipInboundLabelCheck {
+ if streamLabel != "" {
+ m.logger.Printf("[ERR] memberlist: unexpected double stream label header: %s", LogConn(conn))
+ return
+ }
+ // Set this from config so that the auth data assertions work below.
+ streamLabel = m.config.Label
+ }
+
+ if m.config.Label != streamLabel {
+ m.logger.Printf("[ERR] memberlist: discarding stream with unacceptable label %q: %s", streamLabel, LogConn(conn))
+ return
+ }
+
+ msgType, bufConn, dec, err := m.readStream(conn, streamLabel)
+ if err != nil {
+ if err != io.EOF {
+ m.logger.Printf("[ERR] memberlist: failed to receive: %s %s", err, LogConn(conn))
+
+ resp := errResp{err.Error()}
+ out, err := encode(errMsg, &resp, m.config.MsgpackUseNewTimeFormat)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to encode error response: %s", err)
+ return
+ }
+
+ err = m.rawSendMsgStream(conn, out.Bytes(), streamLabel)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to send error: %s %s", err, LogConn(conn))
+ return
+ }
+ }
+ return
+ }
+
+ switch msgType {
+ case userMsg:
+ if err := m.readUserMsg(bufConn, dec); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to receive user message: %s %s", err, LogConn(conn))
+ }
+ case pushPullMsg:
+ // Increment counter of pending push/pulls
+ numConcurrent := atomic.AddUint32(&m.pushPullReq, 1)
+ defer atomic.AddUint32(&m.pushPullReq, ^uint32(0))
+
+ // Check if we have too many open push/pull requests
+ if numConcurrent >= maxPushPullRequests {
+ m.logger.Printf("[ERR] memberlist: Too many pending push/pull requests")
+ return
+ }
+
+ join, remoteNodes, userState, err := m.readRemoteState(bufConn, dec)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to read remote state: %s %s", err, LogConn(conn))
+ return
+ }
+
+ if err := m.sendLocalState(conn, join, streamLabel); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to push local state: %s %s", err, LogConn(conn))
+ return
+ }
+
+ if err := m.mergeRemoteState(join, remoteNodes, userState); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed push/pull merge: %s %s", err, LogConn(conn))
+ return
+ }
+ case pingMsg:
+ var p ping
+ if err := dec.Decode(&p); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to decode ping: %s %s", err, LogConn(conn))
+ return
+ }
+
+ if p.Node != "" && p.Node != m.config.Name {
+ m.logger.Printf("[WARN] memberlist: Got ping for unexpected node %s %s", p.Node, LogConn(conn))
+ return
+ }
+
+ ack := ackResp{p.SeqNo, nil}
+ out, err := encode(ackRespMsg, &ack, m.config.MsgpackUseNewTimeFormat)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to encode ack: %s", err)
+ return
+ }
+
+ err = m.rawSendMsgStream(conn, out.Bytes(), streamLabel)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to send ack: %s %s", err, LogConn(conn))
+ return
+ }
+ default:
+ m.logger.Printf("[ERR] memberlist: Received invalid msgType (%d) %s", msgType, LogConn(conn))
+ }
+}
+
+// packetListen is a long running goroutine that pulls packets out of the
+// transport and hands them off for processing.
+func (m *Memberlist) packetListen() {
+ for {
+ select {
+ case packet := <-m.transport.PacketCh():
+ m.ingestPacket(packet.Buf, packet.From, packet.Timestamp)
+
+ case <-m.shutdownCh:
+ return
+ }
+ }
+}
+
+func (m *Memberlist) ingestPacket(buf []byte, from net.Addr, timestamp time.Time) {
+ var (
+ packetLabel string
+ err error
+ )
+ buf, packetLabel, err = RemoveLabelHeaderFromPacket(buf)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: %v %s", err, LogAddress(from))
+ return
+ }
+
+ if m.config.SkipInboundLabelCheck {
+ if packetLabel != "" {
+ m.logger.Printf("[ERR] memberlist: unexpected double packet label header: %s", LogAddress(from))
+ return
+ }
+ // Set this from config so that the auth data assertions work below.
+ packetLabel = m.config.Label
+ }
+
+ if m.config.Label != packetLabel {
+ m.logger.Printf("[ERR] memberlist: discarding packet with unacceptable label %q: %s", packetLabel, LogAddress(from))
+ return
+ }
+
+ // Check if encryption is enabled
+ if m.config.EncryptionEnabled() {
+ // Decrypt the payload
+ authData := []byte(packetLabel)
+ plain, err := decryptPayload(m.config.Keyring.GetKeys(), buf, authData)
+ if err != nil {
+ if !m.config.GossipVerifyIncoming {
+ // Treat the message as plaintext
+ plain = buf
+ } else {
+ m.logger.Printf("[ERR] memberlist: Decrypt packet failed: %v %s", err, LogAddress(from))
+ return
+ }
+ }
+
+ // Continue processing the plaintext buffer
+ buf = plain
+ }
+
+ // See if there's a checksum included to verify the contents of the message
+ if len(buf) >= 5 && messageType(buf[0]) == hasCrcMsg {
+ crc := crc32.ChecksumIEEE(buf[5:])
+ expected := binary.BigEndian.Uint32(buf[1:5])
+ if crc != expected {
+ m.logger.Printf("[WARN] memberlist: Got invalid checksum for UDP packet: %x, %x", crc, expected)
+ return
+ }
+ m.handleCommand(buf[5:], from, timestamp)
+ } else {
+ m.handleCommand(buf, from, timestamp)
+ }
+}
+
+func (m *Memberlist) handleCommand(buf []byte, from net.Addr, timestamp time.Time) {
+ if len(buf) < 1 {
+ m.logger.Printf("[ERR] memberlist: missing message type byte %s", LogAddress(from))
+ return
+ }
+ // Decode the message type
+ msgType := messageType(buf[0])
+ buf = buf[1:]
+
+ // Switch on the msgType
+ switch msgType {
+ case compoundMsg:
+ m.handleCompound(buf, from, timestamp)
+ case compressMsg:
+ m.handleCompressed(buf, from, timestamp)
+
+ case pingMsg:
+ m.handlePing(buf, from)
+ case indirectPingMsg:
+ m.handleIndirectPing(buf, from)
+ case ackRespMsg:
+ m.handleAck(buf, from, timestamp)
+ case nackRespMsg:
+ m.handleNack(buf, from)
+
+ case suspectMsg:
+ fallthrough
+ case aliveMsg:
+ fallthrough
+ case deadMsg:
+ fallthrough
+ case userMsg:
+ // Determine the message queue, prioritize alive
+ queue := m.lowPriorityMsgQueue
+ if msgType == aliveMsg {
+ queue = m.highPriorityMsgQueue
+ }
+
+ // Check for overflow and append if not full
+ m.msgQueueLock.Lock()
+ if queue.Len() >= m.config.HandoffQueueDepth {
+ m.logger.Printf("[WARN] memberlist: handler queue full, dropping message (%d) %s", msgType, LogAddress(from))
+ } else {
+ queue.PushBack(msgHandoff{msgType, buf, from})
+ }
+ m.msgQueueLock.Unlock()
+
+ // Notify of pending message
+ select {
+ case m.handoffCh <- struct{}{}:
+ default:
+ }
+
+ default:
+ m.logger.Printf("[ERR] memberlist: msg type (%d) not supported %s", msgType, LogAddress(from))
+ }
+}
+
+// getNextMessage returns the next message to process in priority order, using LIFO
+func (m *Memberlist) getNextMessage() (msgHandoff, bool) {
+ m.msgQueueLock.Lock()
+ defer m.msgQueueLock.Unlock()
+
+ if el := m.highPriorityMsgQueue.Back(); el != nil {
+ m.highPriorityMsgQueue.Remove(el)
+ msg := el.Value.(msgHandoff)
+ return msg, true
+ } else if el := m.lowPriorityMsgQueue.Back(); el != nil {
+ m.lowPriorityMsgQueue.Remove(el)
+ msg := el.Value.(msgHandoff)
+ return msg, true
+ }
+ return msgHandoff{}, false
+}
+
+// packetHandler is a long running goroutine that processes messages received
+// over the packet interface, but is decoupled from the listener to avoid
+// blocking the listener which may cause ping/ack messages to be delayed.
+func (m *Memberlist) packetHandler() {
+ for {
+ select {
+ case <-m.handoffCh:
+ for {
+ msg, ok := m.getNextMessage()
+ if !ok {
+ break
+ }
+ msgType := msg.msgType
+ buf := msg.buf
+ from := msg.from
+
+ switch msgType {
+ case suspectMsg:
+ m.handleSuspect(buf, from)
+ case aliveMsg:
+ m.handleAlive(buf, from)
+ case deadMsg:
+ m.handleDead(buf, from)
+ case userMsg:
+ m.handleUser(buf, from)
+ default:
+ m.logger.Printf("[ERR] memberlist: Message type (%d) not supported %s (packet handler)", msgType, LogAddress(from))
+ }
+ }
+
+ case <-m.shutdownCh:
+ return
+ }
+ }
+}
+
+func (m *Memberlist) handleCompound(buf []byte, from net.Addr, timestamp time.Time) {
+ // Decode the parts
+ trunc, parts, err := decodeCompoundMessage(buf)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to decode compound request: %s %s", err, LogAddress(from))
+ return
+ }
+
+ // Log any truncation
+ if trunc > 0 {
+ m.logger.Printf("[WARN] memberlist: Compound request had %d truncated messages %s", trunc, LogAddress(from))
+ }
+
+ // Handle each message
+ for _, part := range parts {
+ m.handleCommand(part, from, timestamp)
+ }
+}
+
+func (m *Memberlist) handlePing(buf []byte, from net.Addr) {
+ var p ping
+ if err := decode(buf, &p); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to decode ping request: %s %s", err, LogAddress(from))
+ return
+ }
+ // If node is provided, verify that it is for us
+ if p.Node != "" && p.Node != m.config.Name {
+ m.logger.Printf("[WARN] memberlist: Got ping for unexpected node '%s' %s", p.Node, LogAddress(from))
+ return
+ }
+ var ack ackResp
+ ack.SeqNo = p.SeqNo
+ if m.config.Ping != nil {
+ ack.Payload = m.config.Ping.AckPayload()
+ }
+
+ addr := ""
+ if len(p.SourceAddr) > 0 && p.SourcePort > 0 {
+ addr = joinHostPort(net.IP(p.SourceAddr).String(), p.SourcePort)
+ } else {
+ addr = from.String()
+ }
+
+ a := Address{
+ Addr: addr,
+ Name: p.SourceNode,
+ }
+ if err := m.encodeAndSendMsg(a, ackRespMsg, &ack); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to send ack: %s %s", err, LogAddress(from))
+ }
+}
+
+func (m *Memberlist) handleIndirectPing(buf []byte, from net.Addr) {
+ var ind indirectPingReq
+ if err := decode(buf, &ind); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to decode indirect ping request: %s %s", err, LogAddress(from))
+ return
+ }
+
+ // For proto versions < 2, there is no port provided. Mask old
+ // behavior by using the configured port.
+ if m.ProtocolVersion() < 2 || ind.Port == 0 {
+ ind.Port = uint16(m.config.BindPort)
+ }
+
+ // Send a ping to the correct host.
+ localSeqNo := m.nextSeqNo()
+ selfAddr, selfPort := m.getAdvertise()
+ ping := ping{
+ SeqNo: localSeqNo,
+ Node: ind.Node,
+ // The outbound message is addressed FROM us.
+ SourceAddr: selfAddr,
+ SourcePort: selfPort,
+ SourceNode: m.config.Name,
+ }
+
+ // Forward the ack back to the requestor. If the request encodes an origin
+ // use that otherwise assume that the other end of the UDP socket is
+ // usable.
+ indAddr := ""
+ if len(ind.SourceAddr) > 0 && ind.SourcePort > 0 {
+ indAddr = joinHostPort(net.IP(ind.SourceAddr).String(), ind.SourcePort)
+ } else {
+ indAddr = from.String()
+ }
+
+ // Setup a response handler to relay the ack
+ cancelCh := make(chan struct{})
+ respHandler := func(payload []byte, timestamp time.Time) {
+ // Try to prevent the nack if we've caught it in time.
+ close(cancelCh)
+
+ ack := ackResp{ind.SeqNo, nil}
+ a := Address{
+ Addr: indAddr,
+ Name: ind.SourceNode,
+ }
+ if err := m.encodeAndSendMsg(a, ackRespMsg, &ack); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to forward ack: %s %s", err, LogStringAddress(indAddr))
+ }
+ }
+ m.setAckHandler(localSeqNo, respHandler, m.config.ProbeTimeout)
+
+ // Send the ping.
+ addr := joinHostPort(net.IP(ind.Target).String(), ind.Port)
+ a := Address{
+ Addr: addr,
+ Name: ind.Node,
+ }
+ if err := m.encodeAndSendMsg(a, pingMsg, &ping); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to send indirect ping: %s %s", err, LogStringAddress(indAddr))
+ }
+
+ // Setup a timer to fire off a nack if no ack is seen in time.
+ if ind.Nack {
+ go func() {
+ select {
+ case <-cancelCh:
+ return
+ case <-time.After(m.config.ProbeTimeout):
+ nack := nackResp{ind.SeqNo}
+ a := Address{
+ Addr: indAddr,
+ Name: ind.SourceNode,
+ }
+ if err := m.encodeAndSendMsg(a, nackRespMsg, &nack); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to send nack: %s %s", err, LogStringAddress(indAddr))
+ }
+ }
+ }()
+ }
+}
+
+func (m *Memberlist) handleAck(buf []byte, from net.Addr, timestamp time.Time) {
+ var ack ackResp
+ if err := decode(buf, &ack); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to decode ack response: %s %s", err, LogAddress(from))
+ return
+ }
+ m.invokeAckHandler(ack, timestamp)
+}
+
+func (m *Memberlist) handleNack(buf []byte, from net.Addr) {
+ var nack nackResp
+ if err := decode(buf, &nack); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to decode nack response: %s %s", err, LogAddress(from))
+ return
+ }
+ m.invokeNackHandler(nack)
+}
+
+func (m *Memberlist) handleSuspect(buf []byte, from net.Addr) {
+ var sus suspect
+ if err := decode(buf, &sus); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to decode suspect message: %s %s", err, LogAddress(from))
+ return
+ }
+ m.suspectNode(&sus)
+}
+
+// ensureCanConnect return the IP from a RemoteAddress
+// return error if this client must not connect
+func (m *Memberlist) ensureCanConnect(from net.Addr) error {
+ if !m.config.IPMustBeChecked() {
+ return nil
+ }
+ source := from.String()
+ if source == "pipe" {
+ return nil
+ }
+ host, _, err := net.SplitHostPort(source)
+ if err != nil {
+ return err
+ }
+
+ ip := net.ParseIP(host)
+ if ip == nil {
+ return fmt.Errorf("cannot parse IP from %s", host)
+ }
+ return m.config.IPAllowed(ip)
+}
+
+func (m *Memberlist) handleAlive(buf []byte, from net.Addr) {
+ if err := m.ensureCanConnect(from); err != nil {
+ m.logger.Printf("[DEBUG] memberlist: Blocked alive message: %s %s", err, LogAddress(from))
+ return
+ }
+ var live alive
+ if err := decode(buf, &live); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to decode alive message: %s %s", err, LogAddress(from))
+ return
+ }
+ if m.config.IPMustBeChecked() {
+ innerIP := net.IP(live.Addr)
+ if innerIP != nil {
+ if err := m.config.IPAllowed(innerIP); err != nil {
+ m.logger.Printf("[DEBUG] memberlist: Blocked alive.Addr=%s message from: %s %s", innerIP.String(), err, LogAddress(from))
+ return
+ }
+ }
+ }
+
+ // For proto versions < 2, there is no port provided. Mask old
+ // behavior by using the configured port
+ if m.ProtocolVersion() < 2 || live.Port == 0 {
+ live.Port = uint16(m.config.BindPort)
+ }
+
+ m.aliveNode(&live, nil, false)
+}
+
+func (m *Memberlist) handleDead(buf []byte, from net.Addr) {
+ var d dead
+ if err := decode(buf, &d); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to decode dead message: %s %s", err, LogAddress(from))
+ return
+ }
+ m.deadNode(&d)
+}
+
+// handleUser is used to notify channels of incoming user data
+func (m *Memberlist) handleUser(buf []byte, from net.Addr) {
+ d := m.config.Delegate
+ if d != nil {
+ d.NotifyMsg(buf)
+ }
+}
+
+// handleCompressed is used to unpack a compressed message
+func (m *Memberlist) handleCompressed(buf []byte, from net.Addr, timestamp time.Time) {
+ // Try to decode the payload
+ payload, err := decompressPayload(buf)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to decompress payload: %v %s", err, LogAddress(from))
+ return
+ }
+
+ // Recursively handle the payload
+ m.handleCommand(payload, from, timestamp)
+}
+
+// encodeAndSendMsg is used to combine the encoding and sending steps
+func (m *Memberlist) encodeAndSendMsg(a Address, msgType messageType, msg interface{}) error {
+ out, err := encode(msgType, msg, m.config.MsgpackUseNewTimeFormat)
+ if err != nil {
+ return err
+ }
+ if err := m.sendMsg(a, out.Bytes()); err != nil {
+ return err
+ }
+ return nil
+}
+
+// sendMsg is used to send a message via packet to another host. It will
+// opportunistically create a compoundMsg and piggy back other broadcasts.
+func (m *Memberlist) sendMsg(a Address, msg []byte) error {
+ // Check if we can piggy back any messages
+ bytesAvail := m.config.UDPBufferSize - len(msg) - compoundHeaderOverhead - labelOverhead(m.config.Label)
+ if m.config.EncryptionEnabled() && m.config.GossipVerifyOutgoing {
+ bytesAvail -= encryptOverhead(m.encryptionVersion())
+ }
+ extra := m.getBroadcasts(compoundOverhead, bytesAvail)
+
+ // Fast path if nothing to piggypack
+ if len(extra) == 0 {
+ return m.rawSendMsgPacket(a, nil, msg)
+ }
+
+ // Join all the messages
+ msgs := make([][]byte, 0, 1+len(extra))
+ msgs = append(msgs, msg)
+ msgs = append(msgs, extra...)
+
+ // Create a compound message
+ compound := makeCompoundMessage(msgs)
+
+ // Send the message
+ return m.rawSendMsgPacket(a, nil, compound.Bytes())
+}
+
+// rawSendMsgPacket is used to send message via packet to another host without
+// modification, other than compression or encryption if enabled.
+func (m *Memberlist) rawSendMsgPacket(a Address, node *Node, msg []byte) error {
+ if a.Name == "" && m.config.RequireNodeNames {
+ return errNodeNamesAreRequired
+ }
+
+ // Check if we have compression enabled
+ if m.config.EnableCompression {
+ buf, err := compressPayload(msg, m.config.MsgpackUseNewTimeFormat)
+ if err != nil {
+ m.logger.Printf("[WARN] memberlist: Failed to compress payload: %v", err)
+ } else {
+ // Only use compression if it reduced the size
+ if buf.Len() < len(msg) {
+ msg = buf.Bytes()
+ }
+ }
+ }
+
+ // Try to look up the destination node. Note this will only work if the
+ // bare ip address is used as the node name, which is not guaranteed.
+ if node == nil {
+ toAddr, _, err := net.SplitHostPort(a.Addr)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to parse address %q: %v", a.Addr, err)
+ return err
+ }
+ m.nodeLock.RLock()
+ nodeState, ok := m.nodeMap[toAddr]
+ m.nodeLock.RUnlock()
+ if ok {
+ node = &nodeState.Node
+ }
+ }
+
+ // Add a CRC to the end of the payload if the recipient understands
+ // ProtocolVersion >= 5
+ if node != nil && node.PMax >= 5 {
+ crc := crc32.ChecksumIEEE(msg)
+ header := make([]byte, 5, 5+len(msg))
+ header[0] = byte(hasCrcMsg)
+ binary.BigEndian.PutUint32(header[1:], crc)
+ msg = append(header, msg...)
+ }
+
+ // Check if we have encryption enabled
+ if m.config.EncryptionEnabled() && m.config.GossipVerifyOutgoing {
+ // Encrypt the payload
+ var (
+ primaryKey = m.config.Keyring.GetPrimaryKey()
+ packetLabel = []byte(m.config.Label)
+ buf bytes.Buffer
+ )
+ err := encryptPayload(m.encryptionVersion(), primaryKey, msg, packetLabel, &buf)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: Encryption of message failed: %v", err)
+ return err
+ }
+ msg = buf.Bytes()
+ }
+
+ metrics.IncrCounterWithLabels([]string{"memberlist", "udp", "sent"}, float32(len(msg)), m.metricLabels)
+ _, err := m.transport.WriteToAddress(msg, a)
+ return err
+}
+
+// rawSendMsgStream is used to stream a message to another host without
+// modification, other than applying compression and encryption if enabled.
+func (m *Memberlist) rawSendMsgStream(conn net.Conn, sendBuf []byte, streamLabel string) error {
+ // Check if compression is enabled
+ if m.config.EnableCompression {
+ compBuf, err := compressPayload(sendBuf, m.config.MsgpackUseNewTimeFormat)
+ if err != nil {
+ m.logger.Printf("[ERROR] memberlist: Failed to compress payload: %v", err)
+ } else {
+ sendBuf = compBuf.Bytes()
+ }
+ }
+
+ // Check if encryption is enabled
+ if m.config.EncryptionEnabled() && m.config.GossipVerifyOutgoing {
+ crypt, err := m.encryptLocalState(sendBuf, streamLabel)
+ if err != nil {
+ m.logger.Printf("[ERROR] memberlist: Failed to encrypt local state: %v", err)
+ return err
+ }
+ sendBuf = crypt
+ }
+
+ // Write out the entire send buffer
+ metrics.IncrCounterWithLabels([]string{"memberlist", "tcp", "sent"}, float32(len(sendBuf)), m.metricLabels)
+
+ if n, err := conn.Write(sendBuf); err != nil {
+ return err
+ } else if n != len(sendBuf) {
+ return fmt.Errorf("only %d of %d bytes written", n, len(sendBuf))
+ }
+
+ return nil
+}
+
+// sendUserMsg is used to stream a user message to another host.
+func (m *Memberlist) sendUserMsg(a Address, sendBuf []byte) error {
+ if a.Name == "" && m.config.RequireNodeNames {
+ return errNodeNamesAreRequired
+ }
+
+ conn, err := m.transport.DialAddressTimeout(a, m.config.TCPTimeout)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ _ = conn.Close()
+ }()
+
+ bufConn := bytes.NewBuffer(nil)
+ if err := bufConn.WriteByte(byte(userMsg)); err != nil {
+ return err
+ }
+
+ header := userMsgHeader{UserMsgLen: len(sendBuf)}
+ hd := codec.MsgpackHandle{}
+ hd.TimeNotBuiltin = !m.config.MsgpackUseNewTimeFormat
+
+ enc := codec.NewEncoder(bufConn, &hd)
+ if err := enc.Encode(&header); err != nil {
+ return err
+ }
+ if _, err := bufConn.Write(sendBuf); err != nil {
+ return err
+ }
+
+ return m.rawSendMsgStream(conn, bufConn.Bytes(), m.config.Label)
+}
+
+// sendAndReceiveState is used to initiate a push/pull over a stream with a
+// remote host.
+func (m *Memberlist) sendAndReceiveState(a Address, join bool) ([]pushNodeState, []byte, error) {
+ if a.Name == "" && m.config.RequireNodeNames {
+ return nil, nil, errNodeNamesAreRequired
+ }
+
+ // Attempt to connect
+ conn, err := m.transport.DialAddressTimeout(a, m.config.TCPTimeout)
+ if err != nil {
+ return nil, nil, err
+ }
+ defer func() {
+ _ = conn.Close()
+ }()
+ m.logger.Printf("[DEBUG] memberlist: Initiating push/pull sync with: %s %s", a.Name, conn.RemoteAddr())
+ metrics.IncrCounterWithLabels([]string{"memberlist", "tcp", "connect"}, 1, m.metricLabels)
+
+ // Send our state
+ if err := m.sendLocalState(conn, join, m.config.Label); err != nil {
+ return nil, nil, err
+ }
+
+ if err := conn.SetDeadline(time.Now().Add(m.config.TCPTimeout)); err != nil {
+ m.logger.Printf("Err: Could not set the deadline: %s", err)
+ }
+ msgType, bufConn, dec, err := m.readStream(conn, m.config.Label)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if msgType == errMsg {
+ var resp errResp
+ if err := dec.Decode(&resp); err != nil {
+ return nil, nil, err
+ }
+ return nil, nil, fmt.Errorf("remote error: %v", resp.Error)
+ }
+
+ // Quit if not push/pull
+ if msgType != pushPullMsg {
+ err := fmt.Errorf("received invalid msgType (%d), expected pushPullMsg (%d) %s", msgType, pushPullMsg, LogConn(conn))
+ return nil, nil, err
+ }
+
+ // Read remote state
+ _, remoteNodes, userState, err := m.readRemoteState(bufConn, dec)
+ return remoteNodes, userState, err
+}
+
+// sendLocalState is invoked to send our local state over a stream connection.
+func (m *Memberlist) sendLocalState(conn net.Conn, join bool, streamLabel string) error {
+ // Setup a deadline
+ if err := conn.SetDeadline(time.Now().Add(m.config.TCPTimeout)); err != nil {
+ m.logger.Printf("Err: Could not set the deadline: %s", err)
+ }
+
+ // Prepare the local node state
+ m.nodeLock.RLock()
+ localNodes := make([]pushNodeState, len(m.nodes))
+ for idx, n := range m.nodes {
+ localNodes[idx].Name = n.Name
+ localNodes[idx].Addr = n.Addr
+ localNodes[idx].Port = n.Port
+ localNodes[idx].Incarnation = n.Incarnation
+ localNodes[idx].State = n.State
+ localNodes[idx].Meta = n.Meta
+ localNodes[idx].Vsn = []uint8{
+ n.PMin, n.PMax, n.PCur,
+ n.DMin, n.DMax, n.DCur,
+ }
+ }
+ m.nodeLock.RUnlock()
+
+ nodeStateCounts := make(map[string]int)
+ nodeStateCounts[StateAlive.metricsString()] = 0
+ nodeStateCounts[StateLeft.metricsString()] = 0
+ nodeStateCounts[StateDead.metricsString()] = 0
+ nodeStateCounts[StateSuspect.metricsString()] = 0
+
+ for _, n := range localNodes {
+ nodeStateCounts[n.State.metricsString()]++
+ }
+
+ for nodeState, cnt := range nodeStateCounts {
+ metrics.SetGaugeWithLabels([]string{"memberlist", "node", "instances"},
+ float32(cnt),
+ append(m.metricLabels, metrics.Label{Name: "node_state", Value: nodeState}))
+ }
+
+ // Get the delegate state
+ var userData []byte
+ if m.config.Delegate != nil {
+ userData = m.config.Delegate.LocalState(join)
+ }
+
+ // Create a bytes buffer writer
+ bufConn := bytes.NewBuffer(nil)
+
+ // Send our node state
+ header := pushPullHeader{Nodes: len(localNodes), UserStateLen: len(userData), Join: join}
+ hd := codec.MsgpackHandle{}
+ enc := codec.NewEncoder(bufConn, &hd)
+
+ // Begin state push
+ if _, err := bufConn.Write([]byte{byte(pushPullMsg)}); err != nil {
+ return err
+ }
+
+ if err := enc.Encode(&header); err != nil {
+ return err
+ }
+ for i := 0; i < header.Nodes; i++ {
+ if err := enc.Encode(&localNodes[i]); err != nil {
+ return err
+ }
+ }
+
+ // Write the user state as well
+ if userData != nil {
+ if _, err := bufConn.Write(userData); err != nil {
+ return err
+ }
+ }
+
+ moreBytes := binary.BigEndian.Uint32(bufConn.Bytes()[1:5])
+ metrics.SetGaugeWithLabels([]string{"memberlist", "size", "local"}, float32(moreBytes), m.metricLabels)
+
+ // Get the send buffer
+ return m.rawSendMsgStream(conn, bufConn.Bytes(), streamLabel)
+}
+
+// encryptLocalState is used to help encrypt local state before sending
+func (m *Memberlist) encryptLocalState(sendBuf []byte, streamLabel string) ([]byte, error) {
+ var buf bytes.Buffer
+
+ // Write the encryptMsg byte
+ buf.WriteByte(byte(encryptMsg))
+
+ // Write the size of the message
+ sizeBuf := make([]byte, 4)
+ encVsn := m.encryptionVersion()
+ encLen := encryptedLength(encVsn, len(sendBuf))
+ binary.BigEndian.PutUint32(sizeBuf, uint32(encLen))
+ buf.Write(sizeBuf)
+
+ // Authenticated Data is:
+ //
+ // [messageType; byte] [messageLength; uint32] [stream_label; optional]
+ //
+ dataBytes := appendBytes(buf.Bytes()[:5], []byte(streamLabel))
+
+ // Write the encrypted cipher text to the buffer
+ key := m.config.Keyring.GetPrimaryKey()
+ err := encryptPayload(encVsn, key, sendBuf, dataBytes, &buf)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// decryptRemoteState is used to help decrypt the remote state
+func (m *Memberlist) decryptRemoteState(bufConn io.Reader, streamLabel string) ([]byte, error) {
+ // Read in enough to determine message length
+ cipherText := bytes.NewBuffer(nil)
+ cipherText.WriteByte(byte(encryptMsg))
+ _, err := io.CopyN(cipherText, bufConn, 4)
+ if err != nil {
+ return nil, err
+ }
+
+ // Ensure we aren't asked to download too much. This is to guard against
+ // an attack vector where a huge amount of state is sent
+ moreBytes := binary.BigEndian.Uint32(cipherText.Bytes()[1:5])
+ metrics.AddSampleWithLabels([]string{"memberlist", "size", "remote"}, float32(moreBytes), m.metricLabels)
+
+ if moreBytes > maxPushStateBytes {
+ return nil, fmt.Errorf("remote node state is larger than limit (%d)", moreBytes)
+
+ }
+
+ //Start reporting the size before you cross the limit
+ if moreBytes > uint32(math.Floor(.6*maxPushStateBytes)) {
+ m.logger.Printf("[WARN] memberlist: Remote node state size is (%d) limit is (%d)", moreBytes, maxPushStateBytes)
+ }
+
+ // Read in the rest of the payload
+ _, err = io.CopyN(cipherText, bufConn, int64(moreBytes))
+ if err != nil {
+ return nil, err
+ }
+
+ // Decrypt the cipherText with some authenticated data
+ //
+ // Authenticated Data is:
+ //
+ // [messageType; byte] [messageLength; uint32] [label_data; optional]
+ //
+ dataBytes := appendBytes(cipherText.Bytes()[:5], []byte(streamLabel))
+ cipherBytes := cipherText.Bytes()[5:]
+
+ // Decrypt the payload
+ keys := m.config.Keyring.GetKeys()
+ return decryptPayload(keys, cipherBytes, dataBytes)
+}
+
+// readStream is used to read messages from a stream connection, decrypting and
+// decompressing the stream if necessary.
+//
+// The provided streamLabel if present will be authenticated during decryption
+// of each message.
+func (m *Memberlist) readStream(conn net.Conn, streamLabel string) (messageType, io.Reader, *codec.Decoder, error) {
+ // Created a buffered reader
+ var bufConn io.Reader = bufio.NewReader(conn)
+
+ // Read the message type
+ buf := [1]byte{0}
+ if _, err := io.ReadFull(bufConn, buf[:]); err != nil {
+ return 0, nil, nil, err
+ }
+ msgType := messageType(buf[0])
+
+ // Check if the message is encrypted
+ if msgType == encryptMsg {
+ if !m.config.EncryptionEnabled() {
+ return 0, nil, nil,
+ fmt.Errorf("remote state is encrypted and encryption is not configured")
+ }
+
+ plain, err := m.decryptRemoteState(bufConn, streamLabel)
+ if err != nil {
+ return 0, nil, nil, err
+ }
+
+ // Reset message type and bufConn
+ msgType = messageType(plain[0])
+ bufConn = bytes.NewReader(plain[1:])
+ } else if m.config.EncryptionEnabled() && m.config.GossipVerifyIncoming {
+ return 0, nil, nil,
+ fmt.Errorf("encryption is configured but remote state is not encrypted")
+ }
+
+ // Get the msgPack decoders
+ hd := codec.MsgpackHandle{}
+ dec := codec.NewDecoder(bufConn, &hd)
+
+ // Check if we have a compressed message
+ if msgType == compressMsg {
+ var c compress
+ if err := dec.Decode(&c); err != nil {
+ return 0, nil, nil, err
+ }
+ decomp, err := decompressBuffer(&c)
+ if err != nil {
+ return 0, nil, nil, err
+ }
+
+ // Reset the message type
+ msgType = messageType(decomp[0])
+
+ // Create a new bufConn
+ bufConn = bytes.NewReader(decomp[1:])
+
+ // Create a new decoder
+ dec = codec.NewDecoder(bufConn, &hd)
+ }
+
+ return msgType, bufConn, dec, nil
+}
+
+// readRemoteState is used to read the remote state from a connection
+func (m *Memberlist) readRemoteState(bufConn io.Reader, dec *codec.Decoder) (bool, []pushNodeState, []byte, error) {
+ // Read the push/pull header
+ var header pushPullHeader
+ if err := dec.Decode(&header); err != nil {
+ return false, nil, nil, err
+ }
+
+ // Allocate space for the transfer
+ remoteNodes := make([]pushNodeState, header.Nodes)
+
+ // Try to decode all the states
+ for i := 0; i < header.Nodes; i++ {
+ if err := dec.Decode(&remoteNodes[i]); err != nil {
+ return false, nil, nil, err
+ }
+ }
+
+ // Read the remote user state into a buffer
+ var userBuf []byte
+ if header.UserStateLen > 0 {
+ userBuf = make([]byte, header.UserStateLen)
+ bytes, err := io.ReadAtLeast(bufConn, userBuf, header.UserStateLen)
+ if err == nil && bytes != header.UserStateLen {
+ err = fmt.Errorf(
+ "failed to read full user state (%d / %d)",
+ bytes, header.UserStateLen)
+ }
+ if err != nil {
+ return false, nil, nil, err
+ }
+ }
+
+ // For proto versions < 2, there is no port provided. Mask old
+ // behavior by using the configured port
+ for idx := range remoteNodes {
+ if m.ProtocolVersion() < 2 || remoteNodes[idx].Port == 0 {
+ remoteNodes[idx].Port = uint16(m.config.BindPort)
+ }
+ }
+
+ return header.Join, remoteNodes, userBuf, nil
+}
+
+// mergeRemoteState is used to merge the remote state with our local state
+func (m *Memberlist) mergeRemoteState(join bool, remoteNodes []pushNodeState, userBuf []byte) error {
+ if err := m.verifyProtocol(remoteNodes); err != nil {
+ return err
+ }
+
+ // Invoke the merge delegate if any
+ if join && m.config.Merge != nil {
+ nodes := make([]*Node, len(remoteNodes))
+ for idx, n := range remoteNodes {
+ nodes[idx] = &Node{
+ Name: n.Name,
+ Addr: n.Addr,
+ Port: n.Port,
+ Meta: n.Meta,
+ State: n.State,
+ PMin: n.Vsn[0],
+ PMax: n.Vsn[1],
+ PCur: n.Vsn[2],
+ DMin: n.Vsn[3],
+ DMax: n.Vsn[4],
+ DCur: n.Vsn[5],
+ }
+ }
+ if err := m.config.Merge.NotifyMerge(nodes); err != nil {
+ return err
+ }
+ }
+
+ // Merge the membership state
+ m.mergeState(remoteNodes)
+
+ // Invoke the delegate for user state
+ if userBuf != nil && m.config.Delegate != nil {
+ m.config.Delegate.MergeRemoteState(userBuf, join)
+ }
+ return nil
+}
+
+// readUserMsg is used to decode a userMsg from a stream.
+func (m *Memberlist) readUserMsg(bufConn io.Reader, dec *codec.Decoder) error {
+ // Read the user message header
+ var header userMsgHeader
+ if err := dec.Decode(&header); err != nil {
+ return err
+ }
+
+ // Read the user message into a buffer
+ var userBuf []byte
+ if header.UserMsgLen > 0 {
+ userBuf = make([]byte, header.UserMsgLen)
+ bytes, err := io.ReadAtLeast(bufConn, userBuf, header.UserMsgLen)
+ if err == nil && bytes != header.UserMsgLen {
+ err = fmt.Errorf(
+ "failed to read full user message (%d / %d)",
+ bytes, header.UserMsgLen)
+ }
+ if err != nil {
+ return err
+ }
+
+ d := m.config.Delegate
+ if d != nil {
+ d.NotifyMsg(userBuf)
+ }
+ }
+
+ return nil
+}
+
+// sendPingAndWaitForAck makes a stream connection to the given address, sends
+// a ping, and waits for an ack. All of this is done as a series of blocking
+// operations, given the deadline. The bool return parameter is true if we
+// we able to round trip a ping to the other node.
+func (m *Memberlist) sendPingAndWaitForAck(a Address, ping ping, deadline time.Time) (bool, error) {
+ if a.Name == "" && m.config.RequireNodeNames {
+ return false, errNodeNamesAreRequired
+ }
+
+ conn, err := m.transport.DialAddressTimeout(a, time.Until(deadline))
+ if err != nil {
+ // If the node is actually dead we expect this to fail, so we
+ // shouldn't spam the logs with it. After this point, errors
+ // with the connection are real, unexpected errors and should
+ // get propagated up.
+ return false, nil
+ }
+ defer func() {
+ _ = conn.Close()
+ }()
+ _ = conn.SetDeadline(deadline)
+
+ out, err := encode(pingMsg, &ping, m.config.MsgpackUseNewTimeFormat)
+ if err != nil {
+ return false, err
+ }
+
+ if err = m.rawSendMsgStream(conn, out.Bytes(), m.config.Label); err != nil {
+ return false, err
+ }
+
+ msgType, _, dec, err := m.readStream(conn, m.config.Label)
+ if err != nil {
+ return false, err
+ }
+
+ if msgType != ackRespMsg {
+ return false, fmt.Errorf("unexpected msgType (%d) from ping %s", msgType, LogConn(conn))
+ }
+
+ var ack ackResp
+ if err = dec.Decode(&ack); err != nil {
+ return false, err
+ }
+
+ if ack.SeqNo != ping.SeqNo {
+ return false, fmt.Errorf("sequence number from ack (%d) doesn't match ping (%d)", ack.SeqNo, ping.SeqNo)
+ }
+
+ return true, nil
+}
diff --git a/vendor/github.com/hashicorp/memberlist/net_transport.go b/vendor/github.com/hashicorp/memberlist/net_transport.go
new file mode 100644
index 00000000000..aade880a595
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/net_transport.go
@@ -0,0 +1,378 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ metrics "github.com/hashicorp/go-metrics/compat"
+ sockaddr "github.com/hashicorp/go-sockaddr"
+)
+
+const (
+ // udpPacketBufSize is used to buffer incoming packets during read
+ // operations.
+ udpPacketBufSize = 65536
+
+ // udpRecvBufSize is a large buffer size that we attempt to set UDP
+ // sockets to in order to handle a large volume of messages.
+ udpRecvBufSize = 2 * 1024 * 1024
+)
+
+// NetTransportConfig is used to configure a net transport.
+type NetTransportConfig struct {
+ // BindAddrs is a list of addresses to bind to for both TCP and UDP
+ // communications.
+ BindAddrs []string
+
+ // BindPort is the port to listen on, for each address above.
+ BindPort int
+
+ // Logger is a logger for operator messages.
+ Logger *log.Logger
+
+ // MetricLabels is a map of optional labels to apply to all metrics
+ // emitted by this transport.
+ MetricLabels []metrics.Label
+}
+
+// NetTransport is a Transport implementation that uses connectionless UDP for
+// packet operations, and ad-hoc TCP connections for stream operations.
+type NetTransport struct {
+ config *NetTransportConfig
+ packetCh chan *Packet
+ streamCh chan net.Conn
+ logger *log.Logger
+ wg sync.WaitGroup
+ tcpListeners []*net.TCPListener
+ udpListeners []*net.UDPConn
+ shutdown int32
+
+ metricLabels []metrics.Label
+}
+
+var _ NodeAwareTransport = (*NetTransport)(nil)
+
+// NewNetTransport returns a net transport with the given configuration. On
+// success all the network listeners will be created and listening.
+func NewNetTransport(config *NetTransportConfig) (*NetTransport, error) {
+ // If we reject the empty list outright we can assume that there's at
+ // least one listener of each type later during operation.
+ if len(config.BindAddrs) == 0 {
+ return nil, fmt.Errorf("at least one bind address is required")
+ }
+
+ // Build out the new transport.
+ var ok bool
+ t := NetTransport{
+ config: config,
+ packetCh: make(chan *Packet),
+ streamCh: make(chan net.Conn),
+ logger: config.Logger,
+ metricLabels: config.MetricLabels,
+ }
+
+ // Clean up listeners if there's an error.
+ defer func() {
+ if !ok {
+ _ = t.Shutdown()
+ }
+ }()
+
+ // Build all the TCP and UDP listeners.
+ port := config.BindPort
+ for _, addr := range config.BindAddrs {
+ ip := net.ParseIP(addr)
+
+ tcpAddr := &net.TCPAddr{IP: ip, Port: port}
+ tcpLn, err := net.ListenTCP("tcp", tcpAddr)
+ if err != nil {
+ return nil, fmt.Errorf("failed to start TCP listener on %q port %d: %v", addr, port, err)
+ }
+ t.tcpListeners = append(t.tcpListeners, tcpLn)
+
+ // If the config port given was zero, use the first TCP listener
+ // to pick an available port and then apply that to everything
+ // else.
+ if port == 0 {
+ port = tcpLn.Addr().(*net.TCPAddr).Port
+ }
+
+ udpAddr := &net.UDPAddr{IP: ip, Port: port}
+ udpLn, err := net.ListenUDP("udp", udpAddr)
+ if err != nil {
+ return nil, fmt.Errorf("failed to start UDP listener on %q port %d: %v", addr, port, err)
+ }
+ if err := setUDPRecvBuf(udpLn); err != nil {
+ return nil, fmt.Errorf("failed to resize UDP buffer: %v", err)
+ }
+ t.udpListeners = append(t.udpListeners, udpLn)
+ }
+
+ // Fire them up now that we've been able to create them all.
+ for i := 0; i < len(config.BindAddrs); i++ {
+ t.wg.Add(2)
+ go t.tcpListen(t.tcpListeners[i])
+ go t.udpListen(t.udpListeners[i])
+ }
+
+ ok = true
+ return &t, nil
+}
+
+// GetAutoBindPort returns the bind port that was automatically given by the
+// kernel, if a bind port of 0 was given.
+func (t *NetTransport) GetAutoBindPort() int {
+ // We made sure there's at least one TCP listener, and that one's
+ // port was applied to all the others for the dynamic bind case.
+ return t.tcpListeners[0].Addr().(*net.TCPAddr).Port
+}
+
+// See Transport.
+func (t *NetTransport) FinalAdvertiseAddr(ip string, port int) (net.IP, int, error) {
+ var advertiseAddr net.IP
+ var advertisePort int
+ if ip != "" {
+ // If they've supplied an address, use that.
+ advertiseAddr = net.ParseIP(ip)
+ if advertiseAddr == nil {
+ return nil, 0, fmt.Errorf("failed to parse advertise address %q", ip)
+ }
+
+ // Ensure IPv4 conversion if necessary.
+ if ip4 := advertiseAddr.To4(); ip4 != nil {
+ advertiseAddr = ip4
+ }
+ advertisePort = port
+ } else {
+ if t.config.BindAddrs[0] == "0.0.0.0" {
+ // Otherwise, if we're not bound to a specific IP, let's
+ // use a suitable private IP address.
+ var err error
+ ip, err = sockaddr.GetPrivateIP()
+ if err != nil {
+ return nil, 0, fmt.Errorf("failed to get interface addresses: %v", err)
+ }
+ if ip == "" {
+ return nil, 0, fmt.Errorf("no private IP address found, and explicit IP not provided")
+ }
+
+ advertiseAddr = net.ParseIP(ip)
+ if advertiseAddr == nil {
+ return nil, 0, fmt.Errorf("failed to parse advertise address: %q", ip)
+ }
+ } else {
+ // Use the IP that we're bound to, based on the first
+ // TCP listener, which we already ensure is there.
+ advertiseAddr = t.tcpListeners[0].Addr().(*net.TCPAddr).IP
+ }
+
+ // Use the port we are bound to.
+ advertisePort = t.GetAutoBindPort()
+ }
+
+ return advertiseAddr, advertisePort, nil
+}
+
+// See Transport.
+func (t *NetTransport) WriteTo(b []byte, addr string) (time.Time, error) {
+ a := Address{Addr: addr, Name: ""}
+ return t.WriteToAddress(b, a)
+}
+
+// See NodeAwareTransport.
+func (t *NetTransport) WriteToAddress(b []byte, a Address) (time.Time, error) {
+ addr := a.Addr
+
+ udpAddr, err := net.ResolveUDPAddr("udp", addr)
+ if err != nil {
+ return time.Time{}, err
+ }
+
+ // We made sure there's at least one UDP listener, so just use the
+ // packet sending interface on the first one. Take the time after the
+ // write call comes back, which will underestimate the time a little,
+ // but help account for any delays before the write occurs.
+ _, err = t.udpListeners[0].WriteTo(b, udpAddr)
+ return time.Now(), err
+}
+
+// See Transport.
+func (t *NetTransport) PacketCh() <-chan *Packet {
+ return t.packetCh
+}
+
+// See IngestionAwareTransport.
+func (t *NetTransport) IngestPacket(conn net.Conn, addr net.Addr, now time.Time, shouldClose bool) error {
+ if shouldClose {
+ defer func() {
+ _ = conn.Close()
+ }()
+ }
+
+ // Copy everything from the stream into packet buffer.
+ var buf bytes.Buffer
+ if _, err := io.Copy(&buf, conn); err != nil {
+ return fmt.Errorf("failed to read packet: %v", err)
+ }
+
+ // Check the length - it needs to have at least one byte to be a proper
+ // message. This is checked elsewhere for writes coming in directly from
+ // the UDP socket.
+ if n := buf.Len(); n < 1 {
+ return fmt.Errorf("packet too short (%d bytes) %s", n, LogAddress(addr))
+ }
+
+ // Inject the packet.
+ t.packetCh <- &Packet{
+ Buf: buf.Bytes(),
+ From: addr,
+ Timestamp: now,
+ }
+ return nil
+}
+
+// See Transport.
+func (t *NetTransport) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) {
+ a := Address{Addr: addr, Name: ""}
+ return t.DialAddressTimeout(a, timeout)
+}
+
+// See NodeAwareTransport.
+func (t *NetTransport) DialAddressTimeout(a Address, timeout time.Duration) (net.Conn, error) {
+ addr := a.Addr
+
+ dialer := net.Dialer{Timeout: timeout}
+ return dialer.Dial("tcp", addr)
+}
+
+// See Transport.
+func (t *NetTransport) StreamCh() <-chan net.Conn {
+ return t.streamCh
+}
+
+// See IngestionAwareTransport.
+func (t *NetTransport) IngestStream(conn net.Conn) error {
+ t.streamCh <- conn
+ return nil
+}
+
+// See Transport.
+func (t *NetTransport) Shutdown() error {
+ // This will avoid log spam about errors when we shut down.
+ atomic.StoreInt32(&t.shutdown, 1)
+
+ // Rip through all the connections and shut them down.
+ for _, conn := range t.tcpListeners {
+ _ = conn.Close()
+ }
+ for _, conn := range t.udpListeners {
+ _ = conn.Close()
+ }
+
+ // Block until all the listener threads have died.
+ t.wg.Wait()
+ return nil
+}
+
+// tcpListen is a long running goroutine that accepts incoming TCP connections
+// and hands them off to the stream channel.
+func (t *NetTransport) tcpListen(tcpLn *net.TCPListener) {
+ defer t.wg.Done()
+
+ // baseDelay is the initial delay after an AcceptTCP() error before attempting again
+ const baseDelay = 5 * time.Millisecond
+
+ // maxDelay is the maximum delay after an AcceptTCP() error before attempting again.
+ // In the case that tcpListen() is error-looping, it will delay the shutdown check.
+ // Therefore, changes to maxDelay may have an effect on the latency of shutdown.
+ const maxDelay = 1 * time.Second
+
+ var loopDelay time.Duration
+ for {
+ conn, err := tcpLn.AcceptTCP()
+ if err != nil {
+ if s := atomic.LoadInt32(&t.shutdown); s == 1 {
+ break
+ }
+
+ if loopDelay == 0 {
+ loopDelay = baseDelay
+ } else {
+ loopDelay *= 2
+ }
+
+ if loopDelay > maxDelay {
+ loopDelay = maxDelay
+ }
+
+ t.logger.Printf("[ERR] memberlist: Error accepting TCP connection: %v", err)
+ time.Sleep(loopDelay)
+ continue
+ }
+ // No error, reset loop delay
+ loopDelay = 0
+
+ t.streamCh <- conn
+ }
+}
+
+// udpListen is a long running goroutine that accepts incoming UDP packets and
+// hands them off to the packet channel.
+func (t *NetTransport) udpListen(udpLn *net.UDPConn) {
+ defer t.wg.Done()
+ for {
+ // Do a blocking read into a fresh buffer. Grab a time stamp as
+ // close as possible to the I/O.
+ buf := make([]byte, udpPacketBufSize)
+ n, addr, err := udpLn.ReadFrom(buf)
+ ts := time.Now()
+ if err != nil {
+ if s := atomic.LoadInt32(&t.shutdown); s == 1 {
+ break
+ }
+
+ t.logger.Printf("[ERR] memberlist: Error reading UDP packet: %v", err)
+ continue
+ }
+
+ // Check the length - it needs to have at least one byte to be a
+ // proper message.
+ if n < 1 {
+ t.logger.Printf("[ERR] memberlist: UDP packet too short (%d bytes) %s",
+ len(buf), LogAddress(addr))
+ continue
+ }
+
+ // Ingest the packet.
+ metrics.IncrCounterWithLabels([]string{"memberlist", "udp", "received"}, float32(n), t.metricLabels)
+ t.packetCh <- &Packet{
+ Buf: buf[:n],
+ From: addr,
+ Timestamp: ts,
+ }
+ }
+}
+
+// setUDPRecvBuf is used to resize the UDP receive window. The function
+// attempts to set the read buffer to `udpRecvBuf` but backs off until
+// the read buffer can be set.
+func setUDPRecvBuf(c *net.UDPConn) error {
+ size := udpRecvBufSize
+ var err error
+ for size > 0 {
+ if err = c.SetReadBuffer(size); err == nil {
+ return nil
+ }
+ size = size / 2
+ }
+ return err
+}
diff --git a/vendor/github.com/hashicorp/memberlist/peeked_conn.go b/vendor/github.com/hashicorp/memberlist/peeked_conn.go
new file mode 100644
index 00000000000..3181d90cec0
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/peeked_conn.go
@@ -0,0 +1,48 @@
+// Copyright 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Originally from: https://github.com/google/tcpproxy/blob/master/tcpproxy.go
+// at f5c09fbedceb69e4b238dec52cdf9f2fe9a815e2
+
+package memberlist
+
+import "net"
+
+// peekedConn is an incoming connection that has had some bytes read from it
+// to determine how to route the connection. The Read method stitches
+// the peeked bytes and unread bytes back together.
+type peekedConn struct {
+ // Peeked are the bytes that have been read from Conn for the
+ // purposes of route matching, but have not yet been consumed
+ // by Read calls. It set to nil by Read when fully consumed.
+ Peeked []byte
+
+ // Conn is the underlying connection.
+ // It can be type asserted against *net.TCPConn or other types
+ // as needed. It should not be read from directly unless
+ // Peeked is nil.
+ net.Conn
+}
+
+func (c *peekedConn) Read(p []byte) (n int, err error) {
+ if len(c.Peeked) > 0 {
+ n = copy(p, c.Peeked)
+ c.Peeked = c.Peeked[n:]
+ if len(c.Peeked) == 0 {
+ c.Peeked = nil
+ }
+ return n, nil
+ }
+ return c.Conn.Read(p)
+}
diff --git a/vendor/github.com/hashicorp/memberlist/ping_delegate.go b/vendor/github.com/hashicorp/memberlist/ping_delegate.go
new file mode 100644
index 00000000000..ca2616ff27a
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/ping_delegate.go
@@ -0,0 +1,17 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import "time"
+
+// PingDelegate is used to notify an observer how long it took for a ping message to
+// complete a round trip. It can also be used for writing arbitrary byte slices
+// into ack messages. Note that in order to be meaningful for RTT estimates, this
+// delegate does not apply to indirect pings, nor fallback pings sent over TCP.
+type PingDelegate interface {
+ // AckPayload is invoked when an ack is being sent; the returned bytes will be appended to the ack
+ AckPayload() []byte
+ // NotifyPing is invoked when an ack for a ping is received
+ NotifyPingComplete(other *Node, rtt time.Duration, payload []byte)
+}
diff --git a/vendor/github.com/hashicorp/memberlist/queue.go b/vendor/github.com/hashicorp/memberlist/queue.go
new file mode 100644
index 00000000000..5b5ca06762d
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/queue.go
@@ -0,0 +1,425 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "math"
+ "sync"
+
+ "github.com/google/btree"
+)
+
+// TransmitLimitedQueue is used to queue messages to broadcast to
+// the cluster (via gossip) but limits the number of transmits per
+// message. It also prioritizes messages with lower transmit counts
+// (hence newer messages).
+type TransmitLimitedQueue struct {
+ // NumNodes returns the number of nodes in the cluster. This is
+ // used to determine the retransmit count, which is calculated
+ // based on the log of this.
+ NumNodes func() int
+
+ // RetransmitMult is the multiplier used to determine the maximum
+ // number of retransmissions attempted.
+ RetransmitMult int
+
+ mu sync.Mutex
+ tq *btree.BTree // stores *limitedBroadcast as btree.Item
+ tm map[string]*limitedBroadcast
+ idGen int64
+}
+
+type limitedBroadcast struct {
+ transmits int // btree-key[0]: Number of transmissions attempted.
+ msgLen int64 // btree-key[1]: copied from len(b.Message())
+ id int64 // btree-key[2]: unique incrementing id stamped at submission time
+ b Broadcast
+
+ name string // set if Broadcast is a NamedBroadcast
+}
+
+// Less tests whether the current item is less than the given argument.
+//
+// This must provide a strict weak ordering.
+// If !a.Less(b) && !b.Less(a), we treat this to mean a == b (i.e. we can only
+// hold one of either a or b in the tree).
+//
+// default ordering is
+// - [transmits=0, ..., transmits=inf]
+// - [transmits=0:len=999, ..., transmits=0:len=2, ...]
+// - [transmits=0:len=999,id=999, ..., transmits=0:len=999:id=1, ...]
+func (b *limitedBroadcast) Less(than btree.Item) bool {
+ o := than.(*limitedBroadcast)
+ if b.transmits < o.transmits {
+ return true
+ } else if b.transmits > o.transmits {
+ return false
+ }
+ if b.msgLen > o.msgLen {
+ return true
+ } else if b.msgLen < o.msgLen {
+ return false
+ }
+ return b.id > o.id
+}
+
+// for testing; emits in transmit order if reverse=false
+func (q *TransmitLimitedQueue) orderedView(reverse bool) []*limitedBroadcast {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+
+ out := make([]*limitedBroadcast, 0, q.lenLocked())
+ q.walkReadOnlyLocked(reverse, func(cur *limitedBroadcast) bool {
+ out = append(out, cur)
+ return true
+ })
+
+ return out
+}
+
+// walkReadOnlyLocked calls f for each item in the queue traversing it in
+// natural order (by Less) when reverse=false and the opposite when true. You
+// must hold the mutex.
+//
+// This method panics if you attempt to mutate the item during traversal. The
+// underlying btree should also not be mutated during traversal.
+func (q *TransmitLimitedQueue) walkReadOnlyLocked(reverse bool, f func(*limitedBroadcast) bool) {
+ if q.lenLocked() == 0 {
+ return
+ }
+
+ iter := func(item btree.Item) bool {
+ cur := item.(*limitedBroadcast)
+
+ prevTransmits := cur.transmits
+ prevMsgLen := cur.msgLen
+ prevID := cur.id
+
+ keepGoing := f(cur)
+
+ if prevTransmits != cur.transmits || prevMsgLen != cur.msgLen || prevID != cur.id {
+ panic("edited queue while walking read only")
+ }
+
+ return keepGoing
+ }
+
+ if reverse {
+ q.tq.Descend(iter) // end with transmit 0
+ } else {
+ q.tq.Ascend(iter) // start with transmit 0
+ }
+}
+
+// Broadcast is something that can be broadcasted via gossip to
+// the memberlist cluster.
+type Broadcast interface {
+ // Invalidates checks if enqueuing the current broadcast
+ // invalidates a previous broadcast
+ Invalidates(b Broadcast) bool
+
+ // Returns a byte form of the message
+ Message() []byte
+
+ // Finished is invoked when the message will no longer
+ // be broadcast, either due to invalidation or to the
+ // transmit limit being reached
+ Finished()
+}
+
+// NamedBroadcast is an optional extension of the Broadcast interface that
+// gives each message a unique string name, and that is used to optimize
+//
+// You shoud ensure that Invalidates() checks the same uniqueness as the
+// example below:
+//
+// func (b *foo) Invalidates(other Broadcast) bool {
+// nb, ok := other.(NamedBroadcast)
+// if !ok {
+// return false
+// }
+// return b.Name() == nb.Name()
+// }
+//
+// Invalidates() isn't currently used for NamedBroadcasts, but that may change
+// in the future.
+type NamedBroadcast interface {
+ Broadcast
+ // The unique identity of this broadcast message.
+ Name() string
+}
+
+// UniqueBroadcast is an optional interface that indicates that each message is
+// intrinsically unique and there is no need to scan the broadcast queue for
+// duplicates.
+//
+// You should ensure that Invalidates() always returns false if implementing
+// this interface. Invalidates() isn't currently used for UniqueBroadcasts, but
+// that may change in the future.
+type UniqueBroadcast interface {
+ Broadcast
+ // UniqueBroadcast is just a marker method for this interface.
+ UniqueBroadcast()
+}
+
+// QueueBroadcast is used to enqueue a broadcast
+func (q *TransmitLimitedQueue) QueueBroadcast(b Broadcast) {
+ q.queueBroadcast(b, 0)
+}
+
+// lazyInit initializes internal data structures the first time they are
+// needed. You must already hold the mutex.
+func (q *TransmitLimitedQueue) lazyInit() {
+ if q.tq == nil {
+ q.tq = btree.New(32)
+ }
+ if q.tm == nil {
+ q.tm = make(map[string]*limitedBroadcast)
+ }
+}
+
+// queueBroadcast is like QueueBroadcast but you can use a nonzero value for
+// the initial transmit tier assigned to the message. This is meant to be used
+// for unit testing.
+func (q *TransmitLimitedQueue) queueBroadcast(b Broadcast, initialTransmits int) {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+
+ q.lazyInit()
+
+ if q.idGen == math.MaxInt64 {
+ // it's super duper unlikely to wrap around within the retransmit limit
+ q.idGen = 1
+ } else {
+ q.idGen++
+ }
+ id := q.idGen
+
+ lb := &limitedBroadcast{
+ transmits: initialTransmits,
+ msgLen: int64(len(b.Message())),
+ id: id,
+ b: b,
+ }
+ unique := false
+ if nb, ok := b.(NamedBroadcast); ok {
+ lb.name = nb.Name()
+ } else if _, ok := b.(UniqueBroadcast); ok {
+ unique = true
+ }
+
+ // Check if this message invalidates another.
+ if lb.name != "" {
+ if old, ok := q.tm[lb.name]; ok {
+ old.b.Finished()
+ q.deleteItem(old)
+ }
+ } else if !unique {
+ // Slow path, hopefully nothing hot hits this.
+ var remove []*limitedBroadcast
+ q.tq.Ascend(func(item btree.Item) bool {
+ cur := item.(*limitedBroadcast)
+
+ // Special Broadcasts can only invalidate each other.
+ switch cur.b.(type) {
+ case NamedBroadcast:
+ // noop
+ case UniqueBroadcast:
+ // noop
+ default:
+ if b.Invalidates(cur.b) {
+ cur.b.Finished()
+ remove = append(remove, cur)
+ }
+ }
+ return true
+ })
+ for _, cur := range remove {
+ q.deleteItem(cur)
+ }
+ }
+
+ // Append to the relevant queue.
+ q.addItem(lb)
+}
+
+// deleteItem removes the given item from the overall datastructure. You
+// must already hold the mutex.
+func (q *TransmitLimitedQueue) deleteItem(cur *limitedBroadcast) {
+ _ = q.tq.Delete(cur)
+ if cur.name != "" {
+ delete(q.tm, cur.name)
+ }
+
+ if q.tq.Len() == 0 {
+ // At idle there's no reason to let the id generator keep going
+ // indefinitely.
+ q.idGen = 0
+ }
+}
+
+// addItem adds the given item into the overall datastructure. You must already
+// hold the mutex.
+func (q *TransmitLimitedQueue) addItem(cur *limitedBroadcast) {
+ _ = q.tq.ReplaceOrInsert(cur)
+ if cur.name != "" {
+ q.tm[cur.name] = cur
+ }
+}
+
+// getTransmitRange returns a pair of min/max values for transmit values
+// represented by the current queue contents. Both values represent actual
+// transmit values on the interval [0, len). You must already hold the mutex.
+func (q *TransmitLimitedQueue) getTransmitRange() (minTransmit, maxTransmit int) {
+ if q.lenLocked() == 0 {
+ return 0, 0
+ }
+ minItem, maxItem := q.tq.Min(), q.tq.Max()
+ if minItem == nil || maxItem == nil {
+ return 0, 0
+ }
+
+ min := minItem.(*limitedBroadcast).transmits
+ max := maxItem.(*limitedBroadcast).transmits
+
+ return min, max
+}
+
+// GetBroadcasts is used to get a number of broadcasts, up to a byte limit
+// and applying a per-message overhead as provided.
+func (q *TransmitLimitedQueue) GetBroadcasts(overhead, limit int) [][]byte {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+
+ // Fast path the default case
+ if q.lenLocked() == 0 {
+ return nil
+ }
+
+ transmitLimit := retransmitLimit(q.RetransmitMult, q.NumNodes())
+
+ var (
+ bytesUsed int
+ toSend [][]byte
+ reinsert []*limitedBroadcast
+ )
+
+ // Visit fresher items first, but only look at stuff that will fit.
+ // We'll go tier by tier, grabbing the largest items first.
+ minTr, maxTr := q.getTransmitRange()
+ for transmits := minTr; transmits <= maxTr; /*do not advance automatically*/ {
+ free := int64(limit - bytesUsed - overhead)
+ if free <= 0 {
+ break // bail out early
+ }
+
+ // Search for the least element on a given tier (by transmit count) as
+ // defined in the limitedBroadcast.Less function that will fit into our
+ // remaining space.
+ greaterOrEqual := &limitedBroadcast{
+ transmits: transmits,
+ msgLen: free,
+ id: math.MaxInt64,
+ }
+ lessThan := &limitedBroadcast{
+ transmits: transmits + 1,
+ msgLen: math.MaxInt64,
+ id: math.MaxInt64,
+ }
+ var keep *limitedBroadcast
+ q.tq.AscendRange(greaterOrEqual, lessThan, func(item btree.Item) bool {
+ cur := item.(*limitedBroadcast)
+ // Check if this is within our limits
+ if int64(len(cur.b.Message())) > free {
+ // If this happens it's a bug in the datastructure or
+ // surrounding use doing something like having len(Message())
+ // change over time. There's enough going on here that it's
+ // probably sane to just skip it and move on for now.
+ return true
+ }
+ keep = cur
+ return false
+ })
+ if keep == nil {
+ // No more items of an appropriate size in the tier.
+ transmits++
+ continue
+ }
+
+ msg := keep.b.Message()
+
+ // Add to slice to send
+ bytesUsed += overhead + len(msg)
+ toSend = append(toSend, msg)
+
+ // Check if we should stop transmission
+ q.deleteItem(keep)
+ if keep.transmits+1 >= transmitLimit {
+ keep.b.Finished()
+ } else {
+ // We need to bump this item down to another transmit tier, but
+ // because it would be in the same direction that we're walking the
+ // tiers, we will have to delay the reinsertion until we are
+ // finished our search. Otherwise we'll possibly re-add the message
+ // when we ascend to the next tier.
+ keep.transmits++
+ reinsert = append(reinsert, keep)
+ }
+ }
+
+ for _, cur := range reinsert {
+ q.addItem(cur)
+ }
+
+ return toSend
+}
+
+// NumQueued returns the number of queued messages
+func (q *TransmitLimitedQueue) NumQueued() int {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+ return q.lenLocked()
+}
+
+// lenLocked returns the length of the overall queue datastructure. You must
+// hold the mutex.
+func (q *TransmitLimitedQueue) lenLocked() int {
+ if q.tq == nil {
+ return 0
+ }
+ return q.tq.Len()
+}
+
+// Reset clears all the queued messages. Should only be used for tests.
+func (q *TransmitLimitedQueue) Reset() {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+
+ q.walkReadOnlyLocked(false, func(cur *limitedBroadcast) bool {
+ cur.b.Finished()
+ return true
+ })
+
+ q.tq = nil
+ q.tm = nil
+ q.idGen = 0
+}
+
+// Prune will retain the maxRetain latest messages, and the rest
+// will be discarded. This can be used to prevent unbounded queue sizes
+func (q *TransmitLimitedQueue) Prune(maxRetain int) {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+
+ // Do nothing if queue size is less than the limit
+ for q.tq.Len() > maxRetain {
+ item := q.tq.Max()
+ if item == nil {
+ break
+ }
+ cur := item.(*limitedBroadcast)
+ cur.b.Finished()
+ q.deleteItem(cur)
+ }
+}
diff --git a/vendor/github.com/hashicorp/memberlist/security.go b/vendor/github.com/hashicorp/memberlist/security.go
new file mode 100644
index 00000000000..2a6c99cda04
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/security.go
@@ -0,0 +1,221 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rand"
+ "fmt"
+ "io"
+)
+
+/*
+Encrypted messages are prefixed with an encryptionVersion byte
+that is used for us to be able to properly encode/decode. We
+currently support the following versions:
+
+ 0 - AES-GCM 128, using PKCS7 padding
+ 1 - AES-GCM 128, no padding. Padding not needed, caused bloat.
+*/
+type encryptionVersion uint8
+
+const (
+ minEncryptionVersion encryptionVersion = 0
+ maxEncryptionVersion encryptionVersion = 1
+)
+
+const (
+ versionSize = 1
+ nonceSize = 12
+ tagSize = 16
+ maxPadOverhead = 16
+ blockSize = aes.BlockSize
+)
+
+// pkcs7encode is used to pad a byte buffer to a specific block size using
+// the PKCS7 algorithm. "Ignores" some bytes to compensate for IV
+func pkcs7encode(buf *bytes.Buffer, ignore, blockSize int) {
+ n := buf.Len() - ignore
+ more := blockSize - (n % blockSize)
+ for i := 0; i < more; i++ {
+ buf.WriteByte(byte(more))
+ }
+}
+
+// pkcs7decode is used to decode a buffer that has been padded
+func pkcs7decode(buf []byte, blockSize int) []byte {
+ if len(buf) == 0 {
+ panic("Cannot decode a PKCS7 buffer of zero length")
+ }
+ n := len(buf)
+ last := buf[n-1]
+ n -= int(last)
+ return buf[:n]
+}
+
+// encryptOverhead returns the maximum possible overhead of encryption by version
+func encryptOverhead(vsn encryptionVersion) int {
+ switch vsn {
+ case 0:
+ return 45 // Version: 1, IV: 12, Padding: 16, Tag: 16
+ case 1:
+ return 29 // Version: 1, IV: 12, Tag: 16
+ default:
+ panic("unsupported version")
+ }
+}
+
+// encryptedLength is used to compute the buffer size needed
+// for a message of given length
+func encryptedLength(vsn encryptionVersion, inp int) int {
+ // If we are on version 1, there is no padding
+ if vsn >= 1 {
+ return versionSize + nonceSize + inp + tagSize
+ }
+
+ // Determine the padding size
+ padding := blockSize - (inp % blockSize)
+
+ // Sum the extra parts to get total size
+ return versionSize + nonceSize + inp + padding + tagSize
+}
+
+// encryptPayload is used to encrypt a message with a given key.
+// We make use of AES-128 in GCM mode. New byte buffer is the version,
+// nonce, ciphertext and tag
+func encryptPayload(vsn encryptionVersion, key []byte, msg []byte, data []byte, dst *bytes.Buffer) error {
+ // Get the AES block cipher
+ aesBlock, err := aes.NewCipher(key)
+ if err != nil {
+ return err
+ }
+
+ // Get the GCM cipher mode
+ gcm, err := cipher.NewGCM(aesBlock)
+ if err != nil {
+ return err
+ }
+
+ // Grow the buffer to make room for everything
+ offset := dst.Len()
+ dst.Grow(encryptedLength(vsn, len(msg)))
+
+ // Write the encryption version
+ dst.WriteByte(byte(vsn))
+
+ // Add a random nonce
+ _, err = io.CopyN(dst, rand.Reader, nonceSize)
+ if err != nil {
+ return err
+ }
+ afterNonce := dst.Len()
+
+ // Ensure we are correctly padded (only version 0)
+ if vsn == 0 {
+ _, _ = io.Copy(dst, bytes.NewReader(msg))
+ pkcs7encode(dst, offset+versionSize+nonceSize, aes.BlockSize)
+ }
+
+ // Encrypt message using GCM
+ slice := dst.Bytes()[offset:]
+ nonce := slice[versionSize : versionSize+nonceSize]
+
+ // Message source depends on the encryption version.
+ // Version 0 uses padding, version 1 does not
+ var src []byte
+ if vsn == 0 {
+ src = slice[versionSize+nonceSize:]
+ } else {
+ src = msg
+ }
+ out := gcm.Seal(nil, nonce, src, data)
+
+ // Truncate the plaintext, and write the cipher text
+ dst.Truncate(afterNonce)
+ dst.Write(out)
+ return nil
+}
+
+// decryptMessage performs the actual decryption of ciphertext. This is in its
+// own function to allow it to be called on all keys easily.
+func decryptMessage(key, msg []byte, data []byte) ([]byte, error) {
+ // Get the AES block cipher
+ aesBlock, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+
+ // Get the GCM cipher mode
+ gcm, err := cipher.NewGCM(aesBlock)
+ if err != nil {
+ return nil, err
+ }
+
+ // Decrypt the message
+ nonce := msg[versionSize : versionSize+nonceSize]
+ ciphertext := msg[versionSize+nonceSize:]
+ plain, err := gcm.Open(nil, nonce, ciphertext, data)
+ if err != nil {
+ return nil, err
+ }
+
+ // Success!
+ return plain, nil
+}
+
+// decryptPayload is used to decrypt a message with a given key,
+// and verify it's contents. Any padding will be removed, and a
+// slice to the plaintext is returned. Decryption is done IN PLACE!
+func decryptPayload(keys [][]byte, msg []byte, data []byte) ([]byte, error) {
+ // Ensure we have at least one byte
+ if len(msg) == 0 {
+ return nil, fmt.Errorf("cannot decrypt empty payload")
+ }
+
+ // Verify the version
+ vsn := encryptionVersion(msg[0])
+ if vsn > maxEncryptionVersion {
+ return nil, fmt.Errorf("unsupported encryption version %d", msg[0])
+ }
+
+ // Ensure the length is sane
+ if len(msg) < encryptedLength(vsn, 0) {
+ return nil, fmt.Errorf("payload is too small to decrypt: %d", len(msg))
+ }
+
+ for _, key := range keys {
+ plain, err := decryptMessage(key, msg, data)
+ if err == nil {
+ // Remove the PKCS7 padding for vsn 0
+ if vsn == 0 {
+ return pkcs7decode(plain, aes.BlockSize), nil
+ } else {
+ return plain, nil
+ }
+ }
+ }
+
+ return nil, fmt.Errorf("no installed keys could decrypt the message")
+}
+
+func appendBytes(first []byte, second []byte) []byte {
+ hasFirst := len(first) > 0
+ hasSecond := len(second) > 0
+
+ switch {
+ case hasFirst && hasSecond:
+ out := make([]byte, 0, len(first)+len(second))
+ out = append(out, first...)
+ out = append(out, second...)
+ return out
+ case hasFirst:
+ return first
+ case hasSecond:
+ return second
+ default:
+ return nil
+ }
+}
diff --git a/vendor/github.com/hashicorp/memberlist/state.go b/vendor/github.com/hashicorp/memberlist/state.go
new file mode 100644
index 00000000000..81c3bceca6d
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/state.go
@@ -0,0 +1,1340 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "bytes"
+ "fmt"
+ "math"
+ "math/rand"
+ "net"
+ "strings"
+ "sync/atomic"
+ "time"
+
+ metrics "github.com/hashicorp/go-metrics/compat"
+)
+
+type NodeStateType int
+
+func (t NodeStateType) metricsString() string {
+ switch t {
+ case StateAlive:
+ return "alive"
+ case StateDead:
+ return "dead"
+ case StateSuspect:
+ return "suspect"
+ case StateLeft:
+ return "left"
+ default:
+ return fmt.Sprintf("unhandled-value-%d", t)
+ }
+}
+
+const (
+ StateAlive NodeStateType = iota
+ StateSuspect
+ StateDead
+ StateLeft
+)
+
+// Node represents a node in the cluster.
+type Node struct {
+ Name string
+ Addr net.IP
+ Port uint16
+ Meta []byte // Metadata from the delegate for this node.
+ State NodeStateType // State of the node.
+ PMin uint8 // Minimum protocol version this understands
+ PMax uint8 // Maximum protocol version this understands
+ PCur uint8 // Current version node is speaking
+ DMin uint8 // Min protocol version for the delegate to understand
+ DMax uint8 // Max protocol version for the delegate to understand
+ DCur uint8 // Current version delegate is speaking
+}
+
+// Address returns the host:port form of a node's address, suitable for use
+// with a transport.
+func (n *Node) Address() string {
+ return joinHostPort(n.Addr.String(), n.Port)
+}
+
+// FullAddress returns the node name and host:port form of a node's address,
+// suitable for use with a transport.
+func (n *Node) FullAddress() Address {
+ return Address{
+ Addr: joinHostPort(n.Addr.String(), n.Port),
+ Name: n.Name,
+ }
+}
+
+// String returns the node name
+func (n *Node) String() string {
+ return n.Name
+}
+
+// NodeState is used to manage our state view of another node
+type nodeState struct {
+ Node
+ Incarnation uint32 // Last known incarnation number
+ State NodeStateType // Current state
+ StateChange time.Time // Time last state change happened
+}
+
+// Address returns the host:port form of a node's address, suitable for use
+// with a transport.
+func (n *nodeState) Address() string {
+ return n.Node.Address()
+}
+
+// FullAddress returns the node name and host:port form of a node's address,
+// suitable for use with a transport.
+func (n *nodeState) FullAddress() Address {
+ return n.Node.FullAddress()
+}
+
+func (n *nodeState) DeadOrLeft() bool {
+ return n.State == StateDead || n.State == StateLeft
+}
+
+// ackHandler is used to register handlers for incoming acks and nacks.
+type ackHandler struct {
+ ackFn func([]byte, time.Time)
+ nackFn func()
+ timer *time.Timer
+}
+
+// NoPingResponseError is used to indicate a 'ping' packet was
+// successfully issued but no response was received
+type NoPingResponseError struct {
+ node string
+}
+
+func (f NoPingResponseError) Error() string {
+ return fmt.Sprintf("No response from node %s", f.node)
+}
+
+// Schedule is used to ensure the Tick is performed periodically. This
+// function is safe to call multiple times. If the memberlist is already
+// scheduled, then it won't do anything.
+func (m *Memberlist) schedule() {
+ m.tickerLock.Lock()
+ defer m.tickerLock.Unlock()
+
+ // If we already have tickers, then don't do anything, since we're
+ // scheduled
+ if len(m.tickers) > 0 {
+ return
+ }
+
+ // Create the stop tick channel, a blocking channel. We close this
+ // when we should stop the tickers.
+ stopCh := make(chan struct{})
+
+ // Create a new probeTicker
+ if m.config.ProbeInterval > 0 {
+ t := time.NewTicker(m.config.ProbeInterval)
+ go m.triggerFunc(m.config.ProbeInterval, t.C, stopCh, m.probe)
+ m.tickers = append(m.tickers, t)
+ }
+
+ // Create a push pull ticker if needed
+ if m.config.PushPullInterval > 0 {
+ go m.pushPullTrigger(stopCh)
+ }
+
+ // Create a gossip ticker if needed
+ if m.config.GossipInterval > 0 && m.config.GossipNodes > 0 {
+ t := time.NewTicker(m.config.GossipInterval)
+ go m.triggerFunc(m.config.GossipInterval, t.C, stopCh, m.gossip)
+ m.tickers = append(m.tickers, t)
+ }
+
+ // If we made any tickers, then record the stopTick channel for
+ // later.
+ if len(m.tickers) > 0 {
+ m.stopTick = stopCh
+ }
+}
+
+// triggerFunc is used to trigger a function call each time a
+// message is received until a stop tick arrives.
+func (m *Memberlist) triggerFunc(stagger time.Duration, C <-chan time.Time, stop <-chan struct{}, f func()) {
+ // Use a random stagger to avoid syncronizing
+ randStagger := time.Duration(uint64(rand.Int63()) % uint64(stagger))
+ select {
+ case <-time.After(randStagger):
+ case <-stop:
+ return
+ }
+ for {
+ select {
+ case <-C:
+ f()
+ case <-stop:
+ return
+ }
+ }
+}
+
+// pushPullTrigger is used to periodically trigger a push/pull until
+// a stop tick arrives. We don't use triggerFunc since the push/pull
+// timer is dynamically scaled based on cluster size to avoid network
+// saturation
+func (m *Memberlist) pushPullTrigger(stop <-chan struct{}) {
+ interval := m.config.PushPullInterval
+
+ // Use a random stagger to avoid syncronizing
+ randStagger := time.Duration(uint64(rand.Int63()) % uint64(interval))
+ select {
+ case <-time.After(randStagger):
+ case <-stop:
+ return
+ }
+
+ // Tick using a dynamic timer
+ for {
+ tickTime := pushPullScale(interval, m.estNumNodes())
+ select {
+ case <-time.After(tickTime):
+ m.pushPull()
+ case <-stop:
+ return
+ }
+ }
+}
+
+// Deschedule is used to stop the background maintenance. This is safe
+// to call multiple times.
+func (m *Memberlist) deschedule() {
+ m.tickerLock.Lock()
+ defer m.tickerLock.Unlock()
+
+ // If we have no tickers, then we aren't scheduled.
+ if len(m.tickers) == 0 {
+ return
+ }
+
+ // Close the stop channel so all the ticker listeners stop.
+ close(m.stopTick)
+
+ // Explicitly stop all the tickers themselves so they don't take
+ // up any more resources, and get rid of the list.
+ for _, t := range m.tickers {
+ t.Stop()
+ }
+ m.tickers = nil
+}
+
+// Tick is used to perform a single round of failure detection and gossip
+func (m *Memberlist) probe() {
+ // Track the number of indexes we've considered probing
+ numCheck := 0
+START:
+ m.nodeLock.RLock()
+
+ // Make sure we don't wrap around infinitely
+ if numCheck >= len(m.nodes) {
+ m.nodeLock.RUnlock()
+ return
+ }
+
+ // Handle the wrap around case
+ if m.probeIndex >= len(m.nodes) {
+ m.nodeLock.RUnlock()
+ m.resetNodes()
+ m.probeIndex = 0
+ numCheck++
+ goto START
+ }
+
+ // Determine if we should probe this node
+ skip := false
+ node := *m.nodes[m.probeIndex]
+
+ if node.Name == m.config.Name {
+ skip = true
+ } else if node.DeadOrLeft() {
+ skip = true
+ }
+
+ // Potentially skip
+ m.nodeLock.RUnlock()
+ m.probeIndex++
+ if skip {
+ numCheck++
+ goto START
+ }
+
+ // Probe the specific node
+ m.probeNode(&node)
+}
+
+// probeNodeByAddr just safely calls probeNode given only the address of the node (for tests)
+func (m *Memberlist) probeNodeByAddr(addr string) {
+ m.nodeLock.RLock()
+ n := m.nodeMap[addr]
+ m.nodeLock.RUnlock()
+
+ m.probeNode(n)
+}
+
+// failedRemote checks the error and decides if it indicates a failure on the
+// other end.
+func failedRemote(err error) bool {
+ switch t := err.(type) {
+ case *net.OpError:
+ if strings.HasPrefix(t.Net, "tcp") {
+ switch t.Op {
+ case "dial", "read", "write":
+ return true
+ }
+ } else if strings.HasPrefix(t.Net, "udp") {
+ switch t.Op {
+ case "write":
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// probeNode handles a single round of failure checking on a node.
+func (m *Memberlist) probeNode(node *nodeState) {
+ defer metrics.MeasureSinceWithLabels([]string{"memberlist", "probeNode"}, time.Now(), m.metricLabels)
+
+ // We use our health awareness to scale the overall probe interval, so we
+ // slow down if we detect problems. The ticker that calls us can handle
+ // us running over the base interval, and will skip missed ticks.
+ probeInterval := m.awareness.ScaleTimeout(m.config.ProbeInterval)
+ if probeInterval > m.config.ProbeInterval {
+ metrics.IncrCounterWithLabels([]string{"memberlist", "degraded", "probe"}, 1, m.metricLabels)
+ }
+
+ // Prepare a ping message and setup an ack handler.
+ selfAddr, selfPort := m.getAdvertise()
+ ping := ping{
+ SeqNo: m.nextSeqNo(),
+ Node: node.Name,
+ SourceAddr: selfAddr,
+ SourcePort: selfPort,
+ SourceNode: m.config.Name,
+ }
+ ackCh := make(chan ackMessage, m.config.IndirectChecks+1)
+ nackCh := make(chan struct{}, m.config.IndirectChecks+1)
+ m.setProbeChannels(ping.SeqNo, ackCh, nackCh, probeInterval)
+
+ // Mark the sent time here, which should be after any pre-processing but
+ // before system calls to do the actual send. This probably over-reports
+ // a bit, but it's the best we can do. We had originally put this right
+ // after the I/O, but that would sometimes give negative RTT measurements
+ // which was not desirable.
+ sent := time.Now()
+
+ // Send a ping to the node. If this node looks like it's suspect or dead,
+ // also tack on a suspect message so that it has a chance to refute as
+ // soon as possible.
+ deadline := sent.Add(probeInterval)
+ addr := node.Address()
+
+ // Arrange for our self-awareness to get updated.
+ var awarenessDelta int
+ defer func() {
+ m.awareness.ApplyDelta(awarenessDelta)
+ }()
+ if node.State == StateAlive {
+ if err := m.encodeAndSendMsg(node.FullAddress(), pingMsg, &ping); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to send UDP ping: %s", err)
+ if failedRemote(err) {
+ goto HANDLE_REMOTE_FAILURE
+ } else {
+ return
+ }
+ }
+ } else {
+ var msgs [][]byte
+ if buf, err := encode(pingMsg, &ping, m.config.MsgpackUseNewTimeFormat); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to encode UDP ping message: %s", err)
+ return
+ } else {
+ msgs = append(msgs, buf.Bytes())
+ }
+ s := suspect{Incarnation: node.Incarnation, Node: node.Name, From: m.config.Name}
+ if buf, err := encode(suspectMsg, &s, m.config.MsgpackUseNewTimeFormat); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to encode suspect message: %s", err)
+ return
+ } else {
+ msgs = append(msgs, buf.Bytes())
+ }
+
+ compound := makeCompoundMessage(msgs)
+ if err := m.rawSendMsgPacket(node.FullAddress(), &node.Node, compound.Bytes()); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to send UDP compound ping and suspect message to %s: %s", addr, err)
+ if failedRemote(err) {
+ goto HANDLE_REMOTE_FAILURE
+ } else {
+ return
+ }
+ }
+ }
+
+ // Arrange for our self-awareness to get updated. At this point we've
+ // sent the ping, so any return statement means the probe succeeded
+ // which will improve our health until we get to the failure scenarios
+ // at the end of this function, which will alter this delta variable
+ // accordingly.
+ awarenessDelta = -1
+
+ // Wait for response or round-trip-time.
+ select {
+ case v := <-ackCh:
+ if v.Complete {
+ if m.config.Ping != nil {
+ rtt := v.Timestamp.Sub(sent)
+ m.config.Ping.NotifyPingComplete(&node.Node, rtt, v.Payload)
+ }
+ return
+ }
+
+ // As an edge case, if we get a timeout, we need to re-enqueue it
+ // here to break out of the select below.
+ if !v.Complete {
+ ackCh <- v
+ }
+ case <-time.After(m.config.ProbeTimeout):
+ // Note that we don't scale this timeout based on awareness and
+ // the health score. That's because we don't really expect waiting
+ // longer to help get UDP through. Since health does extend the
+ // probe interval it will give the TCP fallback more time, which
+ // is more active in dealing with lost packets, and it gives more
+ // time to wait for indirect acks/nacks.
+ m.logger.Printf("[DEBUG] memberlist: Failed UDP ping: %s (timeout reached)", node.Name)
+ }
+
+HANDLE_REMOTE_FAILURE:
+ // Get some random live nodes.
+ m.nodeLock.RLock()
+ kNodes := kRandomNodes(m.config.IndirectChecks, m.nodes, func(n *nodeState) bool {
+ return n.Name == m.config.Name ||
+ n.Name == node.Name ||
+ n.State != StateAlive
+ })
+ m.nodeLock.RUnlock()
+
+ // Attempt an indirect ping.
+ expectedNacks := 0
+ selfAddr, selfPort = m.getAdvertise()
+ ind := indirectPingReq{
+ SeqNo: ping.SeqNo,
+ Target: node.Addr,
+ Port: node.Port,
+ Node: node.Name,
+ SourceAddr: selfAddr,
+ SourcePort: selfPort,
+ SourceNode: m.config.Name,
+ }
+ for _, peer := range kNodes {
+ // We only expect nack to be sent from peers who understand
+ // version 4 of the protocol.
+ if ind.Nack = peer.PMax >= 4; ind.Nack {
+ expectedNacks++
+ }
+
+ if err := m.encodeAndSendMsg(peer.FullAddress(), indirectPingMsg, &ind); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to send indirect UDP ping: %s", err)
+ }
+ }
+
+ // Also make an attempt to contact the node directly over TCP. This
+ // helps prevent confused clients who get isolated from UDP traffic
+ // but can still speak TCP (which also means they can possibly report
+ // misinformation to other nodes via anti-entropy), avoiding flapping in
+ // the cluster.
+ //
+ // This is a little unusual because we will attempt a TCP ping to any
+ // member who understands version 3 of the protocol, regardless of
+ // which protocol version we are speaking. That's why we've included a
+ // config option to turn this off if desired.
+ fallbackCh := make(chan bool, 1)
+
+ disableTcpPings := m.config.DisableTcpPings ||
+ (m.config.DisableTcpPingsForNode != nil && m.config.DisableTcpPingsForNode(node.Name))
+ if (!disableTcpPings) && (node.PMax >= 3) {
+ go func() {
+ defer close(fallbackCh)
+ didContact, err := m.sendPingAndWaitForAck(node.FullAddress(), ping, deadline)
+ if err != nil {
+ var to string
+ if ne, ok := err.(net.Error); ok && ne.Timeout() {
+ to = fmt.Sprintf("timeout %s: ", probeInterval)
+ }
+ m.logger.Printf("[ERR] memberlist: Failed fallback TCP ping: %s%s", to, err)
+ } else {
+ fallbackCh <- didContact
+ }
+ }()
+ } else {
+ close(fallbackCh)
+ }
+
+ // Wait for the acks or timeout. Note that we don't check the fallback
+ // channel here because we want to issue a warning below if that's the
+ // *only* way we hear back from the peer, so we have to let this time
+ // out first to allow the normal UDP-based acks to come in.
+ v := <-ackCh
+ if v.Complete {
+ return
+ }
+
+ // Finally, poll the fallback channel. The timeouts are set such that
+ // the channel will have something or be closed without having to wait
+ // any additional time here.
+ for didContact := range fallbackCh {
+ if didContact {
+ m.logger.Printf("[WARN] memberlist: Was able to connect to %s over TCP but UDP probes failed, network may be misconfigured", node.Name)
+ return
+ }
+ }
+
+ // Update our self-awareness based on the results of this failed probe.
+ // If we don't have peers who will send nacks then we penalize for any
+ // failed probe as a simple health metric. If we do have peers to nack
+ // verify, then we can use that as a more sophisticated measure of self-
+ // health because we assume them to be working, and they can help us
+ // decide if the probed node was really dead or if it was something wrong
+ // with ourselves.
+ awarenessDelta = 0
+ if expectedNacks > 0 {
+ if nackCount := len(nackCh); nackCount < expectedNacks {
+ awarenessDelta += (expectedNacks - nackCount)
+ }
+ } else {
+ awarenessDelta += 1
+ }
+
+ // No acks received from target, suspect it as failed.
+ m.logger.Printf("[INFO] memberlist: Suspect %s has failed, no acks received", node.Name)
+ s := suspect{Incarnation: node.Incarnation, Node: node.Name, From: m.config.Name}
+ m.suspectNode(&s)
+}
+
+// Ping initiates a ping to the node with the specified name.
+func (m *Memberlist) Ping(node string, addr net.Addr) (time.Duration, error) {
+ // Prepare a ping message and setup an ack handler.
+ selfAddr, selfPort := m.getAdvertise()
+ ping := ping{
+ SeqNo: m.nextSeqNo(),
+ Node: node,
+ SourceAddr: selfAddr,
+ SourcePort: selfPort,
+ SourceNode: m.config.Name,
+ }
+ ackCh := make(chan ackMessage, m.config.IndirectChecks+1)
+ m.setProbeChannels(ping.SeqNo, ackCh, nil, m.config.ProbeInterval)
+
+ a := Address{Addr: addr.String(), Name: node}
+
+ // Send a ping to the node.
+ if err := m.encodeAndSendMsg(a, pingMsg, &ping); err != nil {
+ return 0, err
+ }
+
+ // Mark the sent time here, which should be after any pre-processing and
+ // system calls to do the actual send. This probably under-reports a bit,
+ // but it's the best we can do.
+ sent := time.Now()
+
+ // Wait for response or timeout.
+ select {
+ case v := <-ackCh:
+ if v.Complete {
+ return v.Timestamp.Sub(sent), nil
+ }
+ case <-time.After(m.config.ProbeTimeout):
+ // Timeout, return an error below.
+ }
+
+ m.logger.Printf("[DEBUG] memberlist: Failed UDP ping: %v (timeout reached)", node)
+ return 0, NoPingResponseError{ping.Node}
+}
+
+// resetNodes is used when the tick wraps around. It will reap the
+// dead nodes and shuffle the node list.
+func (m *Memberlist) resetNodes() {
+ m.nodeLock.Lock()
+ defer m.nodeLock.Unlock()
+
+ // Move dead nodes, but respect gossip to the dead interval
+ deadIdx := moveDeadNodes(m.nodes, m.config.GossipToTheDeadTime)
+
+ // Deregister the dead nodes
+ for i := deadIdx; i < len(m.nodes); i++ {
+ delete(m.nodeMap, m.nodes[i].Name)
+ m.nodes[i] = nil
+ }
+
+ // Trim the nodes to exclude the dead nodes
+ m.nodes = m.nodes[0:deadIdx]
+
+ // Update numNodes after we've trimmed the dead nodes
+ atomic.StoreUint32(&m.numNodes, uint32(deadIdx))
+
+ // Shuffle live nodes
+ shuffleNodes(m.nodes)
+}
+
+// gossip is invoked every GossipInterval period to broadcast our gossip
+// messages to a few random nodes.
+func (m *Memberlist) gossip() {
+ defer metrics.MeasureSinceWithLabels([]string{"memberlist", "gossip"}, time.Now(), m.metricLabels)
+
+ // Get some random live, suspect, or recently dead nodes
+ m.nodeLock.RLock()
+ kNodes := kRandomNodes(m.config.GossipNodes, m.nodes, func(n *nodeState) bool {
+ if n.Name == m.config.Name {
+ return true
+ }
+
+ switch n.State {
+ case StateAlive, StateSuspect:
+ return false
+
+ case StateDead:
+ return time.Since(n.StateChange) > m.config.GossipToTheDeadTime
+
+ default:
+ return true
+ }
+ })
+ m.nodeLock.RUnlock()
+
+ // Compute the bytes available
+ bytesAvail := m.config.UDPBufferSize - compoundHeaderOverhead - labelOverhead(m.config.Label)
+ if m.config.EncryptionEnabled() {
+ bytesAvail -= encryptOverhead(m.encryptionVersion())
+ }
+
+ for _, node := range kNodes {
+ // Get any pending broadcasts
+ msgs := m.getBroadcasts(compoundOverhead, bytesAvail)
+ if len(msgs) == 0 {
+ return
+ }
+
+ addr := node.Address()
+ if len(msgs) == 1 {
+ // Send single message as is
+ if err := m.rawSendMsgPacket(node.FullAddress(), &node, msgs[0]); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to send gossip to %s: %s", addr, err)
+ }
+ } else {
+ // Otherwise create and send one or more compound messages
+ compounds := makeCompoundMessages(msgs)
+ for _, compound := range compounds {
+ if err := m.rawSendMsgPacket(node.FullAddress(), &node, compound.Bytes()); err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to send gossip to %s: %s", addr, err)
+ }
+ }
+ }
+ }
+}
+
+// pushPull is invoked periodically to randomly perform a complete state
+// exchange. Used to ensure a high level of convergence, but is also
+// reasonably expensive as the entire state of this node is exchanged
+// with the other node.
+func (m *Memberlist) pushPull() {
+ // Get a random live node
+ m.nodeLock.RLock()
+ nodes := kRandomNodes(1, m.nodes, func(n *nodeState) bool {
+ return n.Name == m.config.Name ||
+ n.State != StateAlive
+ })
+ m.nodeLock.RUnlock()
+
+ // If no nodes, bail
+ if len(nodes) == 0 {
+ return
+ }
+ node := nodes[0]
+
+ // Attempt a push pull
+ if err := m.pushPullNode(node.FullAddress(), false); err != nil {
+ m.logger.Printf("[ERR] memberlist: Push/Pull with %s failed: %s", node.Name, err)
+ }
+}
+
+// pushPullNode does a complete state exchange with a specific node.
+func (m *Memberlist) pushPullNode(a Address, join bool) error {
+ defer metrics.MeasureSinceWithLabels([]string{"memberlist", "pushPullNode"}, time.Now(), m.metricLabels)
+
+ // Attempt to send and receive with the node
+ remote, userState, err := m.sendAndReceiveState(a, join)
+ if err != nil {
+ return err
+ }
+
+ if err := m.mergeRemoteState(join, remote, userState); err != nil {
+ return err
+ }
+ return nil
+}
+
+// verifyProtocol verifies that all the remote nodes can speak with our
+// nodes and vice versa on both the core protocol as well as the
+// delegate protocol level.
+//
+// The verification works by finding the maximum minimum and
+// minimum maximum understood protocol and delegate versions. In other words,
+// it finds the common denominator of protocol and delegate version ranges
+// for the entire cluster.
+//
+// After this, it goes through the entire cluster (local and remote) and
+// verifies that everyone's speaking protocol versions satisfy this range.
+// If this passes, it means that every node can understand each other.
+func (m *Memberlist) verifyProtocol(remote []pushNodeState) error {
+ m.nodeLock.RLock()
+ defer m.nodeLock.RUnlock()
+
+ // Maximum minimum understood and minimum maximum understood for both
+ // the protocol and delegate versions. We use this to verify everyone
+ // can be understood.
+ var maxpmin, minpmax uint8
+ var maxdmin, mindmax uint8
+ minpmax = math.MaxUint8
+ mindmax = math.MaxUint8
+
+ for _, rn := range remote {
+ // If the node isn't alive, then skip it
+ if rn.State != StateAlive {
+ continue
+ }
+
+ // Skip nodes that don't have versions set, it just means
+ // their version is zero.
+ if len(rn.Vsn) == 0 {
+ continue
+ }
+
+ if rn.Vsn[0] > maxpmin {
+ maxpmin = rn.Vsn[0]
+ }
+
+ if rn.Vsn[1] < minpmax {
+ minpmax = rn.Vsn[1]
+ }
+
+ if rn.Vsn[3] > maxdmin {
+ maxdmin = rn.Vsn[3]
+ }
+
+ if rn.Vsn[4] < mindmax {
+ mindmax = rn.Vsn[4]
+ }
+ }
+
+ for _, n := range m.nodes {
+ // Ignore non-alive nodes
+ if n.State != StateAlive {
+ continue
+ }
+
+ if n.PMin > maxpmin {
+ maxpmin = n.PMin
+ }
+
+ if n.PMax < minpmax {
+ minpmax = n.PMax
+ }
+
+ if n.DMin > maxdmin {
+ maxdmin = n.DMin
+ }
+
+ if n.DMax < mindmax {
+ mindmax = n.DMax
+ }
+ }
+
+ // Now that we definitively know the minimum and maximum understood
+ // version that satisfies the whole cluster, we verify that every
+ // node in the cluster satisifies this.
+ for _, n := range remote {
+ var nPCur, nDCur uint8
+ if len(n.Vsn) > 0 {
+ nPCur = n.Vsn[2]
+ nDCur = n.Vsn[5]
+ }
+
+ if nPCur < maxpmin || nPCur > minpmax {
+ return fmt.Errorf(
+ "Node '%s' protocol version (%d) is incompatible: [%d, %d]",
+ n.Name, nPCur, maxpmin, minpmax)
+ }
+
+ if nDCur < maxdmin || nDCur > mindmax {
+ return fmt.Errorf(
+ "Node '%s' delegate protocol version (%d) is incompatible: [%d, %d]",
+ n.Name, nDCur, maxdmin, mindmax)
+ }
+ }
+
+ for _, n := range m.nodes {
+ nPCur := n.PCur
+ nDCur := n.DCur
+
+ if nPCur < maxpmin || nPCur > minpmax {
+ return fmt.Errorf(
+ "Node '%s' protocol version (%d) is incompatible: [%d, %d]",
+ n.Name, nPCur, maxpmin, minpmax)
+ }
+
+ if nDCur < maxdmin || nDCur > mindmax {
+ return fmt.Errorf(
+ "Node '%s' delegate protocol version (%d) is incompatible: [%d, %d]",
+ n.Name, nDCur, maxdmin, mindmax)
+ }
+ }
+
+ return nil
+}
+
+// nextSeqNo returns a usable sequence number in a thread safe way
+func (m *Memberlist) nextSeqNo() uint32 {
+ return atomic.AddUint32(&m.sequenceNum, 1)
+}
+
+// nextIncarnation returns the next incarnation number in a thread safe way
+func (m *Memberlist) nextIncarnation() uint32 {
+ return atomic.AddUint32(&m.incarnation, 1)
+}
+
+// skipIncarnation adds the positive offset to the incarnation number.
+func (m *Memberlist) skipIncarnation(offset uint32) uint32 {
+ return atomic.AddUint32(&m.incarnation, offset)
+}
+
+// estNumNodes is used to get the current estimate of the number of nodes
+func (m *Memberlist) estNumNodes() int {
+ return int(atomic.LoadUint32(&m.numNodes))
+}
+
+type ackMessage struct {
+ Complete bool
+ Payload []byte
+ Timestamp time.Time
+}
+
+// setProbeChannels is used to attach the ackCh to receive a message when an ack
+// with a given sequence number is received. The `complete` field of the message
+// will be false on timeout. Any nack messages will cause an empty struct to be
+// passed to the nackCh, which can be nil if not needed.
+func (m *Memberlist) setProbeChannels(seqNo uint32, ackCh chan ackMessage, nackCh chan struct{}, timeout time.Duration) {
+ // Create handler functions for acks and nacks
+ ackFn := func(payload []byte, timestamp time.Time) {
+ select {
+ case ackCh <- ackMessage{true, payload, timestamp}:
+ default:
+ }
+ }
+ nackFn := func() {
+ select {
+ case nackCh <- struct{}{}:
+ default:
+ }
+ }
+
+ // Add the handlers
+ ah := &ackHandler{ackFn, nackFn, nil}
+ m.ackLock.Lock()
+ m.ackHandlers[seqNo] = ah
+ m.ackLock.Unlock()
+
+ // Setup a reaping routing
+ ah.timer = time.AfterFunc(timeout, func() {
+ m.ackLock.Lock()
+ delete(m.ackHandlers, seqNo)
+ m.ackLock.Unlock()
+ select {
+ case ackCh <- ackMessage{false, nil, time.Now()}:
+ default:
+ }
+ })
+}
+
+// setAckHandler is used to attach a handler to be invoked when an ack with a
+// given sequence number is received. If a timeout is reached, the handler is
+// deleted. This is used for indirect pings so does not configure a function
+// for nacks.
+func (m *Memberlist) setAckHandler(seqNo uint32, ackFn func([]byte, time.Time), timeout time.Duration) {
+ // Add the handler
+ ah := &ackHandler{ackFn, nil, nil}
+ m.ackLock.Lock()
+ m.ackHandlers[seqNo] = ah
+ m.ackLock.Unlock()
+
+ // Setup a reaping routing
+ ah.timer = time.AfterFunc(timeout, func() {
+ m.ackLock.Lock()
+ delete(m.ackHandlers, seqNo)
+ m.ackLock.Unlock()
+ })
+}
+
+// Invokes an ack handler if any is associated, and reaps the handler immediately
+func (m *Memberlist) invokeAckHandler(ack ackResp, timestamp time.Time) {
+ m.ackLock.Lock()
+ ah, ok := m.ackHandlers[ack.SeqNo]
+ delete(m.ackHandlers, ack.SeqNo)
+ m.ackLock.Unlock()
+ if !ok {
+ return
+ }
+ ah.timer.Stop()
+ ah.ackFn(ack.Payload, timestamp)
+}
+
+// Invokes nack handler if any is associated.
+func (m *Memberlist) invokeNackHandler(nack nackResp) {
+ m.ackLock.Lock()
+ ah, ok := m.ackHandlers[nack.SeqNo]
+ m.ackLock.Unlock()
+ if !ok || ah.nackFn == nil {
+ return
+ }
+ ah.nackFn()
+}
+
+// refute gossips an alive message in response to incoming information that we
+// are suspect or dead. It will make sure the incarnation number beats the given
+// accusedInc value, or you can supply 0 to just get the next incarnation number.
+// This alters the node state that's passed in so this MUST be called while the
+// nodeLock is held.
+func (m *Memberlist) refute(me *nodeState, accusedInc uint32) {
+ // Make sure the incarnation number beats the accusation.
+ inc := m.nextIncarnation()
+ if accusedInc >= inc {
+ inc = m.skipIncarnation(accusedInc - inc + 1)
+ }
+ me.Incarnation = inc
+
+ // Decrease our health because we are being asked to refute a problem.
+ m.awareness.ApplyDelta(1)
+
+ // Format and broadcast an alive message.
+ a := alive{
+ Incarnation: inc,
+ Node: me.Name,
+ Addr: me.Addr,
+ Port: me.Port,
+ Meta: me.Meta,
+ Vsn: []uint8{
+ me.PMin, me.PMax, me.PCur,
+ me.DMin, me.DMax, me.DCur,
+ },
+ }
+ m.encodeAndBroadcast(me.Addr.String(), aliveMsg, a)
+}
+
+// aliveNode is invoked by the network layer when we get a message about a
+// live node.
+func (m *Memberlist) aliveNode(a *alive, notify chan struct{}, bootstrap bool) {
+ m.nodeLock.Lock()
+ defer m.nodeLock.Unlock()
+ state, ok := m.nodeMap[a.Node]
+
+ // It is possible that during a Leave(), there is already an aliveMsg
+ // in-queue to be processed but blocked by the locks above. If we let
+ // that aliveMsg process, it'll cause us to re-join the cluster. This
+ // ensures that we don't.
+ if m.hasLeft() && a.Node == m.config.Name {
+ return
+ }
+
+ if len(a.Vsn) >= 3 {
+ pMin := a.Vsn[0]
+ pMax := a.Vsn[1]
+ pCur := a.Vsn[2]
+ if pMin == 0 || pMax == 0 || pMin > pMax {
+ m.logger.Printf("[WARN] memberlist: Ignoring an alive message for '%s' (%v:%d) because protocol version(s) are wrong: %d <= %d <= %d should be >0", a.Node, net.IP(a.Addr), a.Port, pMin, pCur, pMax)
+ return
+ }
+ }
+
+ // Invoke the Alive delegate if any. This can be used to filter out
+ // alive messages based on custom logic. For example, using a cluster name.
+ // Using a merge delegate is not enough, as it is possible for passive
+ // cluster merging to still occur.
+ if m.config.Alive != nil {
+ if len(a.Vsn) < 6 {
+ m.logger.Printf("[WARN] memberlist: ignoring alive message for '%s' (%v:%d) because Vsn is not present",
+ a.Node, net.IP(a.Addr), a.Port)
+ return
+ }
+ node := &Node{
+ Name: a.Node,
+ Addr: a.Addr,
+ Port: a.Port,
+ Meta: a.Meta,
+ PMin: a.Vsn[0],
+ PMax: a.Vsn[1],
+ PCur: a.Vsn[2],
+ DMin: a.Vsn[3],
+ DMax: a.Vsn[4],
+ DCur: a.Vsn[5],
+ }
+ if err := m.config.Alive.NotifyAlive(node); err != nil {
+ m.logger.Printf("[WARN] memberlist: ignoring alive message for '%s': %s",
+ a.Node, err)
+ return
+ }
+ }
+
+ // Check if we've never seen this node before, and if not, then
+ // store this node in our node map.
+ var updatesNode bool
+ if !ok {
+ errCon := m.config.IPAllowed(a.Addr)
+ if errCon != nil {
+ m.logger.Printf("[WARN] memberlist: Rejected node %s (%v): %s", a.Node, net.IP(a.Addr), errCon)
+ return
+ }
+ state = &nodeState{
+ Node: Node{
+ Name: a.Node,
+ Addr: a.Addr,
+ Port: a.Port,
+ Meta: a.Meta,
+ },
+ State: StateDead,
+ }
+ if len(a.Vsn) > 5 {
+ state.PMin = a.Vsn[0]
+ state.PMax = a.Vsn[1]
+ state.PCur = a.Vsn[2]
+ state.DMin = a.Vsn[3]
+ state.DMax = a.Vsn[4]
+ state.DCur = a.Vsn[5]
+ }
+
+ // Add to map
+ m.nodeMap[a.Node] = state
+
+ // Get a random offset. This is important to ensure
+ // the failure detection bound is low on average. If all
+ // nodes did an append, failure detection bound would be
+ // very high.
+ n := len(m.nodes)
+ offset := randomOffset(n)
+
+ // Add at the end and swap with the node at the offset
+ m.nodes = append(m.nodes, state)
+ m.nodes[offset], m.nodes[n] = m.nodes[n], m.nodes[offset]
+
+ // Update numNodes after we've added a new node
+ atomic.AddUint32(&m.numNodes, 1)
+ } else {
+ // Check if this address is different than the existing node unless the old node is dead.
+ if !bytes.Equal([]byte(state.Addr), a.Addr) || state.Port != a.Port {
+ errCon := m.config.IPAllowed(a.Addr)
+ if errCon != nil {
+ m.logger.Printf("[WARN] memberlist: Rejected IP update from %v to %v for node %s: %s", a.Node, state.Addr, net.IP(a.Addr), errCon)
+ return
+ }
+ // If DeadNodeReclaimTime is configured, check if enough time has elapsed since the node died.
+ canReclaim := (m.config.DeadNodeReclaimTime > 0 &&
+ time.Since(state.StateChange) > m.config.DeadNodeReclaimTime)
+
+ // Allow the address to be updated if a dead node is being replaced.
+ if state.State == StateLeft || (state.State == StateDead && canReclaim) {
+ m.logger.Printf("[INFO] memberlist: Updating address for left or failed node %s from %v:%d to %v:%d",
+ state.Name, state.Addr, state.Port, net.IP(a.Addr), a.Port)
+ updatesNode = true
+ } else {
+ m.logger.Printf("[ERR] memberlist: Conflicting address for %s. Mine: %v:%d Theirs: %v:%d Old state: %v",
+ state.Name, state.Addr, state.Port, net.IP(a.Addr), a.Port, state.State)
+
+ // Inform the conflict delegate if provided
+ if m.config.Conflict != nil {
+ other := Node{
+ Name: a.Node,
+ Addr: a.Addr,
+ Port: a.Port,
+ Meta: a.Meta,
+ }
+ m.config.Conflict.NotifyConflict(&state.Node, &other)
+ }
+ return
+ }
+ }
+ }
+
+ // Bail if the incarnation number is older, and this is not about us
+ isLocalNode := state.Name == m.config.Name
+ if a.Incarnation <= state.Incarnation && !isLocalNode && !updatesNode {
+ return
+ }
+
+ // Bail if strictly less and this is about us
+ if a.Incarnation < state.Incarnation && isLocalNode {
+ return
+ }
+
+ // Clear out any suspicion timer that may be in effect.
+ delete(m.nodeTimers, a.Node)
+
+ // Store the old state and meta data
+ oldState := state.State
+ oldMeta := state.Meta
+
+ // If this is us we need to refute, otherwise re-broadcast
+ if !bootstrap && isLocalNode {
+ // Compute the version vector
+ versions := []uint8{
+ state.PMin, state.PMax, state.PCur,
+ state.DMin, state.DMax, state.DCur,
+ }
+
+ // If the Incarnation is the same, we need special handling, since it
+ // possible for the following situation to happen:
+ // 1) Start with configuration C, join cluster
+ // 2) Hard fail / Kill / Shutdown
+ // 3) Restart with configuration C', join cluster
+ //
+ // In this case, other nodes and the local node see the same incarnation,
+ // but the values may not be the same. For this reason, we always
+ // need to do an equality check for this Incarnation. In most cases,
+ // we just ignore, but we may need to refute.
+ //
+ if a.Incarnation == state.Incarnation &&
+ bytes.Equal(a.Meta, state.Meta) &&
+ bytes.Equal(a.Vsn, versions) {
+ return
+ }
+ m.refute(state, a.Incarnation)
+ m.logger.Printf("[WARN] memberlist: Refuting an alive message for '%s' (%v:%d) meta:(%v VS %v), vsn:(%v VS %v)", a.Node, net.IP(a.Addr), a.Port, a.Meta, state.Meta, a.Vsn, versions)
+ } else {
+ m.encodeBroadcastNotify(a.Node, aliveMsg, a, notify)
+
+ // Update protocol versions if it arrived
+ if len(a.Vsn) > 0 {
+ state.PMin = a.Vsn[0]
+ state.PMax = a.Vsn[1]
+ state.PCur = a.Vsn[2]
+ state.DMin = a.Vsn[3]
+ state.DMax = a.Vsn[4]
+ state.DCur = a.Vsn[5]
+ }
+
+ // Update the state and incarnation number
+ state.Incarnation = a.Incarnation
+ state.Meta = a.Meta
+ state.Addr = a.Addr
+ state.Port = a.Port
+ if state.State != StateAlive {
+ state.State = StateAlive
+ state.StateChange = time.Now()
+ }
+ }
+
+ // Update metrics
+ metrics.IncrCounterWithLabels([]string{"memberlist", "msg", "alive"}, 1, m.metricLabels)
+
+ // Notify the delegate of any relevant updates
+ if m.config.Events != nil {
+ if oldState == StateDead || oldState == StateLeft {
+ // if Dead/Left -> Alive, notify of join
+ m.config.Events.NotifyJoin(&state.Node)
+
+ } else if !bytes.Equal(oldMeta, state.Meta) {
+ // if Meta changed, trigger an update notification
+ m.config.Events.NotifyUpdate(&state.Node)
+ }
+ }
+}
+
+// suspectNode is invoked by the network layer when we get a message
+// about a suspect node
+func (m *Memberlist) suspectNode(s *suspect) {
+ m.nodeLock.Lock()
+ defer m.nodeLock.Unlock()
+ state, ok := m.nodeMap[s.Node]
+
+ // If we've never heard about this node before, ignore it
+ if !ok {
+ return
+ }
+
+ // Ignore old incarnation numbers
+ if s.Incarnation < state.Incarnation {
+ return
+ }
+
+ // See if there's a suspicion timer we can confirm. If the info is new
+ // to us we will go ahead and re-gossip it. This allows for multiple
+ // independent confirmations to flow even when a node probes a node
+ // that's already suspect.
+ if timer, ok := m.nodeTimers[s.Node]; ok {
+ if timer.Confirm(s.From) {
+ m.encodeAndBroadcast(s.Node, suspectMsg, s)
+ }
+ return
+ }
+
+ // Ignore non-alive nodes
+ if state.State != StateAlive {
+ return
+ }
+
+ // If this is us we need to refute, otherwise re-broadcast
+ if state.Name == m.config.Name {
+ m.refute(state, s.Incarnation)
+ m.logger.Printf("[WARN] memberlist: Refuting a suspect message (from: %s)", s.From)
+ return // Do not mark ourself suspect
+ } else {
+ m.encodeAndBroadcast(s.Node, suspectMsg, s)
+ }
+
+ // Update metrics
+ metrics.IncrCounterWithLabels([]string{"memberlist", "msg", "suspect"}, 1, m.metricLabels)
+
+ // Update the state
+ state.Incarnation = s.Incarnation
+ state.State = StateSuspect
+ changeTime := time.Now()
+ state.StateChange = changeTime
+
+ // Setup a suspicion timer. Given that we don't have any known phase
+ // relationship with our peers, we set up k such that we hit the nominal
+ // timeout two probe intervals short of what we expect given the suspicion
+ // multiplier.
+ k := m.config.SuspicionMult - 2
+
+ // If there aren't enough nodes to give the expected confirmations, just
+ // set k to 0 to say that we don't expect any. Note we subtract 2 from n
+ // here to take out ourselves and the node being probed.
+ n := m.estNumNodes()
+ if n-2 < k {
+ k = 0
+ }
+
+ // Compute the timeouts based on the size of the cluster.
+ min := suspicionTimeout(m.config.SuspicionMult, n, m.config.ProbeInterval)
+ max := time.Duration(m.config.SuspicionMaxTimeoutMult) * min
+ fn := func(numConfirmations int) {
+ var d *dead
+
+ m.nodeLock.Lock()
+ state, ok := m.nodeMap[s.Node]
+ timeout := ok && state.State == StateSuspect && state.StateChange.Equal(changeTime)
+ if timeout {
+ d = &dead{Incarnation: state.Incarnation, Node: state.Name, From: m.config.Name}
+ }
+ m.nodeLock.Unlock()
+
+ if timeout {
+ if k > 0 && numConfirmations < k {
+ metrics.IncrCounterWithLabels([]string{"memberlist", "degraded", "timeout"}, 1, m.metricLabels)
+ }
+
+ m.logger.Printf("[INFO] memberlist: Marking %s as failed, suspect timeout reached (%d peer confirmations)",
+ state.Name, numConfirmations)
+
+ m.deadNode(d)
+ }
+ }
+ m.nodeTimers[s.Node] = newSuspicion(s.From, k, min, max, fn)
+}
+
+// deadNode is invoked by the network layer when we get a message
+// about a dead node
+func (m *Memberlist) deadNode(d *dead) {
+ m.nodeLock.Lock()
+ defer m.nodeLock.Unlock()
+ state, ok := m.nodeMap[d.Node]
+
+ // If we've never heard about this node before, ignore it
+ if !ok {
+ return
+ }
+
+ // Ignore old incarnation numbers
+ if d.Incarnation < state.Incarnation {
+ return
+ }
+
+ // Clear out any suspicion timer that may be in effect.
+ delete(m.nodeTimers, d.Node)
+
+ // Ignore if node is already dead
+ if state.DeadOrLeft() {
+ return
+ }
+
+ // Check if this is us
+ if state.Name == m.config.Name {
+ // If we are not leaving we need to refute
+ if !m.hasLeft() {
+ m.refute(state, d.Incarnation)
+ m.logger.Printf("[WARN] memberlist: Refuting a dead message (from: %s)", d.From)
+ return // Do not mark ourself dead
+ }
+
+ // If we are leaving, we broadcast and wait
+ m.encodeBroadcastNotify(d.Node, deadMsg, d, m.leaveBroadcast)
+ } else {
+ m.encodeAndBroadcast(d.Node, deadMsg, d)
+ }
+
+ // Update metrics
+ metrics.IncrCounterWithLabels([]string{"memberlist", "msg", "dead"}, 1, m.metricLabels)
+
+ // Update the state
+ state.Incarnation = d.Incarnation
+
+ // If the dead message was send by the node itself, mark it is left
+ // instead of dead.
+ if d.Node == d.From {
+ state.State = StateLeft
+ } else {
+ state.State = StateDead
+ }
+ state.StateChange = time.Now()
+
+ // Notify of death
+ if m.config.Events != nil {
+ m.config.Events.NotifyLeave(&state.Node)
+ }
+}
+
+// mergeState is invoked by the network layer when we get a Push/Pull
+// state transfer
+func (m *Memberlist) mergeState(remote []pushNodeState) {
+ for _, r := range remote {
+ switch r.State {
+ case StateAlive:
+ a := alive{
+ Incarnation: r.Incarnation,
+ Node: r.Name,
+ Addr: r.Addr,
+ Port: r.Port,
+ Meta: r.Meta,
+ Vsn: r.Vsn,
+ }
+ m.aliveNode(&a, nil, false)
+
+ case StateLeft:
+ d := dead{Incarnation: r.Incarnation, Node: r.Name, From: r.Name}
+ m.deadNode(&d)
+ case StateDead:
+ // If the remote node believes a node is dead, we prefer to
+ // suspect that node instead of declaring it dead instantly
+ fallthrough
+ case StateSuspect:
+ s := suspect{Incarnation: r.Incarnation, Node: r.Name, From: m.config.Name}
+ m.suspectNode(&s)
+ }
+ }
+}
diff --git a/vendor/github.com/hashicorp/memberlist/suspicion.go b/vendor/github.com/hashicorp/memberlist/suspicion.go
new file mode 100644
index 00000000000..27132851668
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/suspicion.go
@@ -0,0 +1,133 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "math"
+ "sync/atomic"
+ "time"
+)
+
+// suspicion manages the suspect timer for a node and provides an interface
+// to accelerate the timeout as we get more independent confirmations that
+// a node is suspect.
+type suspicion struct {
+ // n is the number of independent confirmations we've seen. This must
+ // be updated using atomic instructions to prevent contention with the
+ // timer callback.
+ n int32
+
+ // k is the number of independent confirmations we'd like to see in
+ // order to drive the timer to its minimum value.
+ k int32
+
+ // min is the minimum timer value.
+ min time.Duration
+
+ // max is the maximum timer value.
+ max time.Duration
+
+ // start captures the timestamp when we began the timer. This is used
+ // so we can calculate durations to feed the timer during updates in
+ // a way the achieves the overall time we'd like.
+ start time.Time
+
+ // timer is the underlying timer that implements the timeout.
+ timer *time.Timer
+
+ // f is the function to call when the timer expires. We hold on to this
+ // because there are cases where we call it directly.
+ timeoutFn func()
+
+ // confirmations is a map of "from" nodes that have confirmed a given
+ // node is suspect. This prevents double counting.
+ confirmations map[string]struct{}
+}
+
+// newSuspicion returns a timer started with the max time, and that will drive
+// to the min time after seeing k or more confirmations. The from node will be
+// excluded from confirmations since we might get our own suspicion message
+// gossiped back to us. The minimum time will be used if no confirmations are
+// called for (k <= 0).
+func newSuspicion(from string, k int, min time.Duration, max time.Duration, fn func(int)) *suspicion {
+ s := &suspicion{
+ k: int32(k),
+ min: min,
+ max: max,
+ confirmations: make(map[string]struct{}),
+ }
+
+ // Exclude the from node from any confirmations.
+ s.confirmations[from] = struct{}{}
+
+ // Pass the number of confirmations into the timeout function for
+ // easy telemetry.
+ s.timeoutFn = func() {
+ fn(int(atomic.LoadInt32(&s.n)))
+ }
+
+ // If there aren't any confirmations to be made then take the min
+ // time from the start.
+ timeout := max
+ if k < 1 {
+ timeout = min
+ }
+ s.timer = time.AfterFunc(timeout, s.timeoutFn)
+
+ // Capture the start time right after starting the timer above so
+ // we should always err on the side of a little longer timeout if
+ // there's any preemption that separates this and the step above.
+ s.start = time.Now()
+ return s
+}
+
+// remainingSuspicionTime takes the state variables of the suspicion timer and
+// calculates the remaining time to wait before considering a node dead. The
+// return value can be negative, so be prepared to fire the timer immediately in
+// that case.
+func remainingSuspicionTime(n, k int32, elapsed time.Duration, min, max time.Duration) time.Duration {
+ frac := math.Log(float64(n)+1.0) / math.Log(float64(k)+1.0)
+ raw := max.Seconds() - frac*(max.Seconds()-min.Seconds())
+ timeout := time.Duration(math.Floor(1000.0*raw)) * time.Millisecond
+ if timeout < min {
+ timeout = min
+ }
+
+ // We have to take into account the amount of time that has passed so
+ // far, so we get the right overall timeout.
+ return timeout - elapsed
+}
+
+// Confirm registers that a possibly new peer has also determined the given
+// node is suspect. This returns true if this was new information, and false
+// if it was a duplicate confirmation, or if we've got enough confirmations to
+// hit the minimum.
+func (s *suspicion) Confirm(from string) bool {
+ // If we've got enough confirmations then stop accepting them.
+ if atomic.LoadInt32(&s.n) >= s.k {
+ return false
+ }
+
+ // Only allow one confirmation from each possible peer.
+ if _, ok := s.confirmations[from]; ok {
+ return false
+ }
+ s.confirmations[from] = struct{}{}
+
+ // Compute the new timeout given the current number of confirmations and
+ // adjust the timer. If the timeout becomes negative *and* we can cleanly
+ // stop the timer then we will call the timeout function directly from
+ // here.
+ n := atomic.AddInt32(&s.n, 1)
+ elapsed := time.Since(s.start)
+ remaining := remainingSuspicionTime(n, s.k, elapsed, s.min, s.max)
+ if s.timer.Stop() {
+ if remaining > 0 {
+ s.timer.Reset(remaining)
+ } else {
+ go s.timeoutFn()
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/hashicorp/memberlist/tag.sh b/vendor/github.com/hashicorp/memberlist/tag.sh
new file mode 100644
index 00000000000..7d21075985c
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/tag.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+# Copyright IBM Corp. 2013, 2025
+# SPDX-License-Identifier: MPL-2.0
+
+set -e
+
+# The version must be supplied from the environment. Do not include the
+# leading "v".
+if [ -z $VERSION ]; then
+ echo "Please specify a version."
+ exit 1
+fi
+
+# Generate the tag.
+echo "==> Tagging version $VERSION..."
+git commit --allow-empty -a --gpg-sign=348FFC4C -m "Release v$VERSION"
+git tag -a -m "Version $VERSION" -s -u 348FFC4C "v${VERSION}" master
+
+exit 0
diff --git a/vendor/github.com/hashicorp/memberlist/todo.md b/vendor/github.com/hashicorp/memberlist/todo.md
new file mode 100644
index 00000000000..009c1d647a1
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/todo.md
@@ -0,0 +1,6 @@
+# TODO
+* Dynamic RTT discovery
+ * Compute 99th percentile for ping/ack
+ * Better lower bound for ping/ack, faster failure detection
+* Dynamic MTU discovery
+ * Prevent lost updates, increases efficiency
diff --git a/vendor/github.com/hashicorp/memberlist/transport.go b/vendor/github.com/hashicorp/memberlist/transport.go
new file mode 100644
index 00000000000..e29942c966e
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/transport.go
@@ -0,0 +1,163 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "fmt"
+ "net"
+ "time"
+)
+
+// Packet is used to provide some metadata about incoming packets from peers
+// over a packet connection, as well as the packet payload.
+type Packet struct {
+ // Buf has the raw contents of the packet.
+ Buf []byte
+
+ // From has the address of the peer. This is an actual net.Addr so we
+ // can expose some concrete details about incoming packets.
+ From net.Addr
+
+ // Timestamp is the time when the packet was received. This should be
+ // taken as close as possible to the actual receipt time to help make an
+ // accurate RTT measurement during probes.
+ Timestamp time.Time
+}
+
+// Transport is used to abstract over communicating with other peers. The packet
+// interface is assumed to be best-effort and the stream interface is assumed to
+// be reliable.
+type Transport interface {
+ // FinalAdvertiseAddr is given the user's configured values (which
+ // might be empty) and returns the desired IP and port to advertise to
+ // the rest of the cluster.
+ FinalAdvertiseAddr(ip string, port int) (net.IP, int, error)
+
+ // WriteTo is a packet-oriented interface that fires off the given
+ // payload to the given address in a connectionless fashion. This should
+ // return a time stamp that's as close as possible to when the packet
+ // was transmitted to help make accurate RTT measurements during probes.
+ //
+ // This is similar to net.PacketConn, though we didn't want to expose
+ // that full set of required methods to keep assumptions about the
+ // underlying plumbing to a minimum. We also treat the address here as a
+ // string, similar to Dial, so it's network neutral, so this usually is
+ // in the form of "host:port".
+ WriteTo(b []byte, addr string) (time.Time, error)
+
+ // PacketCh returns a channel that can be read to receive incoming
+ // packets from other peers. How this is set up for listening is left as
+ // an exercise for the concrete transport implementations.
+ PacketCh() <-chan *Packet
+
+ // DialTimeout is used to create a connection that allows us to perform
+ // two-way communication with a peer. This is generally more expensive
+ // than packet connections so is used for more infrequent operations
+ // such as anti-entropy or fallback probes if the packet-oriented probe
+ // failed.
+ DialTimeout(addr string, timeout time.Duration) (net.Conn, error)
+
+ // StreamCh returns a channel that can be read to handle incoming stream
+ // connections from other peers. How this is set up for listening is
+ // left as an exercise for the concrete transport implementations.
+ StreamCh() <-chan net.Conn
+
+ // Shutdown is called when memberlist is shutting down; this gives the
+ // transport a chance to clean up any listeners.
+ Shutdown() error
+}
+
+type Address struct {
+ // Addr is a network address as a string, similar to Dial. This usually is
+ // in the form of "host:port". This is required.
+ Addr string
+
+ // Name is the name of the node being addressed. This is optional but
+ // transports may require it.
+ Name string
+}
+
+func (a *Address) String() string {
+ if a.Name != "" {
+ return fmt.Sprintf("%s (%s)", a.Name, a.Addr)
+ }
+ return a.Addr
+}
+
+// IngestionAwareTransport is not used.
+//
+// Deprecated: IngestionAwareTransport is not used and may be removed in a future
+// version. Define the interface locally instead of referencing this exported
+// interface.
+type IngestionAwareTransport interface {
+ IngestPacket(conn net.Conn, addr net.Addr, now time.Time, shouldClose bool) error
+ IngestStream(conn net.Conn) error
+}
+
+type NodeAwareTransport interface {
+ Transport
+ WriteToAddress(b []byte, addr Address) (time.Time, error)
+ DialAddressTimeout(addr Address, timeout time.Duration) (net.Conn, error)
+}
+
+type shimNodeAwareTransport struct {
+ Transport
+}
+
+var _ NodeAwareTransport = (*shimNodeAwareTransport)(nil)
+
+func (t *shimNodeAwareTransport) WriteToAddress(b []byte, addr Address) (time.Time, error) {
+ return t.WriteTo(b, addr.Addr)
+}
+
+func (t *shimNodeAwareTransport) DialAddressTimeout(addr Address, timeout time.Duration) (net.Conn, error) {
+ return t.DialTimeout(addr.Addr, timeout)
+}
+
+type labelWrappedTransport struct {
+ label string
+ NodeAwareTransport
+}
+
+var _ NodeAwareTransport = (*labelWrappedTransport)(nil)
+
+func (t *labelWrappedTransport) WriteToAddress(buf []byte, addr Address) (time.Time, error) {
+ var err error
+ buf, err = AddLabelHeaderToPacket(buf, t.label)
+ if err != nil {
+ return time.Time{}, fmt.Errorf("failed to add label header to packet: %w", err)
+ }
+ return t.NodeAwareTransport.WriteToAddress(buf, addr)
+}
+
+func (t *labelWrappedTransport) WriteTo(buf []byte, addr string) (time.Time, error) {
+ var err error
+ buf, err = AddLabelHeaderToPacket(buf, t.label)
+ if err != nil {
+ return time.Time{}, err
+ }
+ return t.NodeAwareTransport.WriteTo(buf, addr)
+}
+
+func (t *labelWrappedTransport) DialAddressTimeout(addr Address, timeout time.Duration) (net.Conn, error) {
+ conn, err := t.NodeAwareTransport.DialAddressTimeout(addr, timeout)
+ if err != nil {
+ return nil, err
+ }
+ if err := AddLabelHeaderToStream(conn, t.label); err != nil {
+ return nil, fmt.Errorf("failed to add label header to stream: %w", err)
+ }
+ return conn, nil
+}
+
+func (t *labelWrappedTransport) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) {
+ conn, err := t.NodeAwareTransport.DialTimeout(addr, timeout)
+ if err != nil {
+ return nil, err
+ }
+ if err := AddLabelHeaderToStream(conn, t.label); err != nil {
+ return nil, fmt.Errorf("failed to add label header to stream: %w", err)
+ }
+ return conn, nil
+}
diff --git a/vendor/github.com/hashicorp/memberlist/util.go b/vendor/github.com/hashicorp/memberlist/util.go
new file mode 100644
index 00000000000..3394ff841fa
--- /dev/null
+++ b/vendor/github.com/hashicorp/memberlist/util.go
@@ -0,0 +1,333 @@
+// Copyright IBM Corp. 2013, 2025
+// SPDX-License-Identifier: MPL-2.0
+
+package memberlist
+
+import (
+ "bytes"
+ "compress/lzw"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "math"
+ "math/rand"
+ "net"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/hashicorp/go-msgpack/v2/codec"
+ "github.com/sean-/seed"
+)
+
+// pushPullScale is the minimum number of nodes
+// before we start scaling the push/pull timing. The scale
+// effect is the log2(Nodes) - log2(pushPullScale). This means
+// that the 33rd node will cause us to double the interval,
+// while the 65th will triple it.
+const pushPullScaleThreshold = 32
+
+const (
+ // Constant litWidth 2-8
+ lzwLitWidth = 8
+)
+
+func init() {
+ _, _ = seed.Init()
+}
+
+// Decode reverses the encode operation on a byte slice input
+func decode(buf []byte, out interface{}) error {
+ r := bytes.NewReader(buf)
+ hd := codec.MsgpackHandle{}
+ dec := codec.NewDecoder(r, &hd)
+ return dec.Decode(out)
+}
+
+// Encode writes an encoded object to a new bytes buffer
+func encode(msgType messageType, in interface{}, msgpackUseNewTimeFormat bool) (*bytes.Buffer, error) {
+ buf := bytes.NewBuffer(nil)
+ buf.WriteByte(uint8(msgType))
+ hd := codec.MsgpackHandle{}
+ hd.TimeNotBuiltin = !msgpackUseNewTimeFormat
+
+ enc := codec.NewEncoder(buf, &hd)
+ err := enc.Encode(in)
+ return buf, err
+}
+
+// Returns a random offset between 0 and n
+func randomOffset(n int) int {
+ if n == 0 {
+ return 0
+ }
+ return int(rand.Uint32() % uint32(n))
+}
+
+// suspicionTimeout computes the timeout that should be used when
+// a node is suspected
+func suspicionTimeout(suspicionMult, n int, interval time.Duration) time.Duration {
+ nodeScale := math.Max(1.0, math.Log10(math.Max(1.0, float64(n))))
+ // multiply by 1000 to keep some precision because time.Duration is an int64 type
+ timeout := time.Duration(suspicionMult) * time.Duration(nodeScale*1000) * interval / 1000
+ return timeout
+}
+
+// retransmitLimit computes the limit of retransmissions
+func retransmitLimit(retransmitMult, n int) int {
+ nodeScale := math.Ceil(math.Log10(float64(n + 1)))
+ limit := retransmitMult * int(nodeScale)
+ return limit
+}
+
+// shuffleNodes randomly shuffles the input nodes using the Fisher-Yates shuffle
+func shuffleNodes(nodes []*nodeState) {
+ n := len(nodes)
+ rand.Shuffle(n, func(i, j int) {
+ nodes[i], nodes[j] = nodes[j], nodes[i]
+ })
+}
+
+// pushPushScale is used to scale the time interval at which push/pull
+// syncs take place. It is used to prevent network saturation as the
+// cluster size grows
+func pushPullScale(interval time.Duration, n int) time.Duration {
+ // Don't scale until we cross the threshold
+ if n <= pushPullScaleThreshold {
+ return interval
+ }
+
+ multiplier := math.Ceil(math.Log2(float64(n))-math.Log2(pushPullScaleThreshold)) + 1.0
+ return time.Duration(multiplier) * interval
+}
+
+// moveDeadNodes moves dead and left nodes that that have not changed during the gossipToTheDeadTime interval
+// to the end of the slice and returns the index of the first moved node.
+func moveDeadNodes(nodes []*nodeState, gossipToTheDeadTime time.Duration) int {
+ numDead := 0
+ n := len(nodes)
+ for i := 0; i < n-numDead; i++ {
+ if !nodes[i].DeadOrLeft() {
+ continue
+ }
+
+ // Respect the gossip to the dead interval
+ if time.Since(nodes[i].StateChange) <= gossipToTheDeadTime {
+ continue
+ }
+
+ // Move this node to the end
+ nodes[i], nodes[n-numDead-1] = nodes[n-numDead-1], nodes[i]
+ numDead++
+ i--
+ }
+ return n - numDead
+}
+
+// kRandomNodes is used to select up to k random Nodes, excluding any nodes where
+// the exclude function returns true. It is possible that less than k nodes are
+// returned.
+func kRandomNodes(k int, nodes []*nodeState, exclude func(*nodeState) bool) []Node {
+ n := len(nodes)
+ kNodes := make([]Node, 0, k)
+OUTER:
+ // Probe up to 3*n times, with large n this is not necessary
+ // since k << n, but with small n we want search to be
+ // exhaustive
+ for i := 0; i < 3*n && len(kNodes) < k; i++ {
+ // Get random nodeState
+ idx := randomOffset(n)
+ state := nodes[idx]
+
+ // Give the filter a shot at it.
+ if exclude != nil && exclude(state) {
+ continue OUTER
+ }
+
+ // Check if we have this node already
+ for j := 0; j < len(kNodes); j++ {
+ if state.Name == kNodes[j].Name {
+ continue OUTER
+ }
+ }
+
+ // Append the node
+ kNodes = append(kNodes, state.Node)
+ }
+ return kNodes
+}
+
+// makeCompoundMessages takes a list of messages and packs
+// them into one or multiple messages based on the limitations
+// of compound messages (255 messages each).
+func makeCompoundMessages(msgs [][]byte) []*bytes.Buffer {
+ const maxMsgs = 255
+ bufs := make([]*bytes.Buffer, 0, (len(msgs)+(maxMsgs-1))/maxMsgs)
+
+ for ; len(msgs) > maxMsgs; msgs = msgs[maxMsgs:] {
+ bufs = append(bufs, makeCompoundMessage(msgs[:maxMsgs]))
+ }
+ if len(msgs) > 0 {
+ bufs = append(bufs, makeCompoundMessage(msgs))
+ }
+
+ return bufs
+}
+
+// makeCompoundMessage takes a list of messages and generates
+// a single compound message containing all of them
+func makeCompoundMessage(msgs [][]byte) *bytes.Buffer {
+ // Create a local buffer
+ buf := bytes.NewBuffer(nil)
+
+ // Write out the type
+ buf.WriteByte(uint8(compoundMsg))
+
+ // Write out the number of message
+ buf.WriteByte(uint8(len(msgs)))
+
+ // Add the message lengths
+ for _, m := range msgs {
+ _ = binary.Write(buf, binary.BigEndian, uint16(len(m)))
+ }
+
+ // Append the messages
+ for _, m := range msgs {
+ buf.Write(m)
+ }
+
+ return buf
+}
+
+// decodeCompoundMessage splits a compound message and returns
+// the slices of individual messages. Also returns the number
+// of truncated messages and any potential error
+func decodeCompoundMessage(buf []byte) (trunc int, parts [][]byte, err error) {
+ if len(buf) < 1 {
+ err = fmt.Errorf("missing compound length byte")
+ return
+ }
+ numParts := int(buf[0])
+ buf = buf[1:]
+
+ // Check we have enough bytes
+ if len(buf) < numParts*2 {
+ err = fmt.Errorf("truncated len slice")
+ return
+ }
+
+ // Decode the lengths
+ lengths := make([]uint16, numParts)
+ for i := 0; i < numParts; i++ {
+ lengths[i] = binary.BigEndian.Uint16(buf[i*2 : i*2+2])
+ }
+ buf = buf[numParts*2:]
+
+ // Split each message
+ for idx, msgLen := range lengths {
+ if len(buf) < int(msgLen) {
+ trunc = numParts - idx
+ return
+ }
+
+ // Extract the slice, seek past on the buffer
+ slice := buf[:msgLen]
+ buf = buf[msgLen:]
+ parts = append(parts, slice)
+ }
+ return
+}
+
+// compressPayload takes an opaque input buffer, compresses it
+// and wraps it in a compress{} message that is encoded.
+func compressPayload(inp []byte, msgpackUseNewTimeFormat bool) (*bytes.Buffer, error) {
+ var buf bytes.Buffer
+ compressor := lzw.NewWriter(&buf, lzw.LSB, lzwLitWidth)
+
+ _, err := compressor.Write(inp)
+ if err != nil {
+ return nil, err
+ }
+
+ // Ensure we flush everything out
+ if err := compressor.Close(); err != nil {
+ return nil, err
+ }
+
+ // Create a compressed message
+ c := compress{
+ Algo: lzwAlgo,
+ Buf: buf.Bytes(),
+ }
+ return encode(compressMsg, &c, msgpackUseNewTimeFormat)
+}
+
+// decompressPayload is used to unpack an encoded compress{}
+// message and return its payload uncompressed
+func decompressPayload(msg []byte) ([]byte, error) {
+ // Decode the message
+ var c compress
+ if err := decode(msg, &c); err != nil {
+ return nil, err
+ }
+ return decompressBuffer(&c)
+}
+
+// decompressBuffer is used to decompress the buffer of
+// a single compress message, handling multiple algorithms
+func decompressBuffer(c *compress) ([]byte, error) {
+ // Verify the algorithm
+ if c.Algo != lzwAlgo {
+ return nil, fmt.Errorf("cannot decompress unknown algorithm %d", c.Algo)
+ }
+
+ // Create a uncompressor
+ uncomp := lzw.NewReader(bytes.NewReader(c.Buf), lzw.LSB, lzwLitWidth)
+ defer func() {
+ _ = uncomp.Close()
+ }()
+
+ // Read all the data
+ var b bytes.Buffer
+ _, err := io.Copy(&b, uncomp)
+ if err != nil {
+ return nil, err
+ }
+
+ // Return the uncompressed bytes
+ return b.Bytes(), nil
+}
+
+// joinHostPort returns the host:port form of an address, for use with a
+// transport.
+func joinHostPort(host string, port uint16) string {
+ return net.JoinHostPort(host, strconv.Itoa(int(port)))
+}
+
+// hasPort is given a string of the form "host", "host:port", "ipv6::address",
+// or "[ipv6::address]:port", and returns true if the string includes a port.
+func hasPort(s string) bool {
+ // IPv6 address in brackets.
+ if strings.LastIndex(s, "[") == 0 {
+ return strings.LastIndex(s, ":") > strings.LastIndex(s, "]")
+ }
+
+ // Otherwise the presence of a single colon determines if there's a port
+ // since IPv6 addresses outside of brackets (count > 1) can't have a
+ // port.
+ return strings.Count(s, ":") == 1
+}
+
+// ensurePort makes sure the given string has a port number on it, otherwise it
+// appends the given port as a default.
+func ensurePort(s string, port int) string {
+ if hasPort(s) {
+ return s
+ }
+
+ // If this is an IPv6 address, the join call will add another set of
+ // brackets, so we have to trim before we add the default port.
+ s = strings.Trim(s, "[]")
+ s = net.JoinHostPort(s, strconv.Itoa(port))
+ return s
+}
diff --git a/vendor/github.com/klauspost/compress/.gitattributes b/vendor/github.com/klauspost/compress/.gitattributes
new file mode 100644
index 00000000000..57aa6487c5b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/.gitattributes
@@ -0,0 +1,3 @@
+* -text
+*.bin -text -diff
+*.md text eol=lf
diff --git a/vendor/github.com/klauspost/compress/.gitignore b/vendor/github.com/klauspost/compress/.gitignore
new file mode 100644
index 00000000000..d31b3781527
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/.gitignore
@@ -0,0 +1,32 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+/s2/cmd/_s2sx/sfx-exe
+
+# Linux perf files
+perf.data
+perf.data.old
+
+# gdb history
+.gdb_history
diff --git a/vendor/github.com/klauspost/compress/.goreleaser.yml b/vendor/github.com/klauspost/compress/.goreleaser.yml
new file mode 100644
index 00000000000..804a2018167
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/.goreleaser.yml
@@ -0,0 +1,132 @@
+version: 2
+
+before:
+ hooks:
+ - ./gen.sh
+
+builds:
+ -
+ id: "s2c"
+ binary: s2c
+ main: ./s2/cmd/s2c/main.go
+ flags:
+ - -trimpath
+ env:
+ - CGO_ENABLED=0
+ goos:
+ - aix
+ - linux
+ - freebsd
+ - netbsd
+ - windows
+ - darwin
+ goarch:
+ - 386
+ - amd64
+ - arm
+ - arm64
+ - ppc64
+ - ppc64le
+ - mips64
+ - mips64le
+ goarm:
+ - 7
+ ignore:
+ - goos: windows
+ goarch: arm
+ -
+ id: "s2d"
+ binary: s2d
+ main: ./s2/cmd/s2d/main.go
+ flags:
+ - -trimpath
+ env:
+ - CGO_ENABLED=0
+ goos:
+ - aix
+ - linux
+ - freebsd
+ - netbsd
+ - windows
+ - darwin
+ goarch:
+ - 386
+ - amd64
+ - arm
+ - arm64
+ - ppc64
+ - ppc64le
+ - mips64
+ - mips64le
+ goarm:
+ - 7
+ ignore:
+ - goos: windows
+ goarch: arm
+ -
+ id: "s2sx"
+ binary: s2sx
+ main: ./s2/cmd/_s2sx/main.go
+ flags:
+ - -modfile=s2sx.mod
+ - -trimpath
+ env:
+ - CGO_ENABLED=0
+ goos:
+ - aix
+ - linux
+ - freebsd
+ - netbsd
+ - windows
+ - darwin
+ goarch:
+ - 386
+ - amd64
+ - arm
+ - arm64
+ - ppc64
+ - ppc64le
+ - mips64
+ - mips64le
+ goarm:
+ - 7
+ ignore:
+ - goos: windows
+ goarch: arm
+
+archives:
+ -
+ id: s2-binaries
+ name_template: "s2-{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
+ format_overrides:
+ - goos: windows
+ formats: ['zip']
+ files:
+ - unpack/*
+ - s2/LICENSE
+ - s2/README.md
+checksum:
+ name_template: 'checksums.txt'
+snapshot:
+ version_template: "{{ .Tag }}-next"
+changelog:
+ sort: asc
+ filters:
+ exclude:
+ - '^doc:'
+ - '^docs:'
+ - '^test:'
+ - '^tests:'
+ - '^Update\sREADME.md'
+
+nfpms:
+ -
+ file_name_template: "s2_package__{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
+ vendor: Klaus Post
+ homepage: https://github.com/klauspost/compress
+ maintainer: Klaus Post
+ description: S2 Compression Tool
+ license: BSD 3-Clause
+ formats:
+ - deb
+ - rpm
diff --git a/vendor/github.com/klauspost/compress/LICENSE b/vendor/github.com/klauspost/compress/LICENSE
new file mode 100644
index 00000000000..87d55747778
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/LICENSE
@@ -0,0 +1,304 @@
+Copyright (c) 2012 The Go Authors. All rights reserved.
+Copyright (c) 2019 Klaus Post. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+------------------
+
+Files: gzhttp/*
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2016-2017 The New York Times Company
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+------------------
+
+Files: s2/cmd/internal/readahead/*
+
+The MIT License (MIT)
+
+Copyright (c) 2015 Klaus Post
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+---------------------
+Files: snappy/*
+Files: internal/snapref/*
+
+Copyright (c) 2011 The Snappy-Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-----------------
+
+Files: s2/cmd/internal/filepathx/*
+
+Copyright 2016 The filepathx Authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md
new file mode 100644
index 00000000000..fb023f2cf21
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/README.md
@@ -0,0 +1,700 @@
+# compress
+
+This package provides various compression algorithms.
+
+* [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression in pure Go.
+* [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) is a high performance replacement for Snappy.
+* Optimized [deflate](https://godoc.org/github.com/klauspost/compress/flate) packages which can be used as a dropin replacement for [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip) and [zlib](https://godoc.org/github.com/klauspost/compress/zlib).
+* [snappy](https://github.com/klauspost/compress/tree/master/snappy) is a drop-in replacement for `github.com/golang/snappy` offering better compression and concurrent streams.
+* [huff0](https://github.com/klauspost/compress/tree/master/huff0) and [FSE](https://github.com/klauspost/compress/tree/master/fse) implementations for raw entropy encoding.
+* [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp) Provides client and server wrappers for handling gzipped/zstd HTTP requests efficiently.
+* [pgzip](https://github.com/klauspost/pgzip) is a separate package that provides a very fast parallel gzip implementation.
+
+[](https://pkg.go.dev/github.com/klauspost/compress?tab=subdirectories)
+[](https://github.com/klauspost/compress/actions/workflows/go.yml)
+[](https://sourcegraph.com/github.com/klauspost/compress?badge)
+
+# package usage
+
+Use `go get github.com/klauspost/compress@latest` to add it to your project.
+
+This package will support the current Go version and 2 versions back.
+
+* Use the `nounsafe` tag to disable all use of the "unsafe" package.
+* Use the `noasm` tag to disable all assembly across packages.
+
+Use the links above for more information on each.
+
+# changelog
+
+* Feb 9th, 2026 [1.18.4](https://github.com/klauspost/compress/releases/tag/v1.18.4)
+ * gzhttp: Add zstandard to server handler wrapper https://github.com/klauspost/compress/pull/1121
+ * zstd: Add ResetWithOptions to encoder/decoder https://github.com/klauspost/compress/pull/1122
+ * gzhttp: preserve qvalue when extra parameters follow in Accept-Encoding by @analytically in https://github.com/klauspost/compress/pull/1116
+
+* Jan 16th, 2026 [1.18.3](https://github.com/klauspost/compress/releases/tag/v1.18.3)
+ * Downstream CVE-2025-61728. See [golang/go#77102](https://github.com/golang/go/issues/77102).
+
+* Dec 1st, 2025 - [1.18.2](https://github.com/klauspost/compress/releases/tag/v1.18.2)
+ * flate: Fix invalid encoding on level 9 with single value input in https://github.com/klauspost/compress/pull/1115
+ * flate: reduce stateless allocations by @RXamzin in https://github.com/klauspost/compress/pull/1106
+
+* Oct 20, 2025 - [1.18.1](https://github.com/klauspost/compress/releases/tag/v1.18.1) - RETRACTED
+ * zstd: Add simple zstd EncodeTo/DecodeTo functions https://github.com/klauspost/compress/pull/1079
+ * zstd: Fix incorrect buffer size in dictionary encodes https://github.com/klauspost/compress/pull/1059
+ * s2: check for cap, not len of buffer in EncodeBetter/Best by @vdarulis in https://github.com/klauspost/compress/pull/1080
+ * zlib: Avoiding extra allocation in zlib.reader.Reset by @travelpolicy in https://github.com/klauspost/compress/pull/1086
+ * gzhttp: remove redundant err check in zstdReader by @ryanfowler in https://github.com/klauspost/compress/pull/1090
+ * flate: Faster load+store https://github.com/klauspost/compress/pull/1104
+ * flate: Simplify matchlen https://github.com/klauspost/compress/pull/1101
+ * flate: Use exact sizes for huffman tables https://github.com/klauspost/compress/pull/1103
+
+* Feb 19th, 2025 - [1.18.0](https://github.com/klauspost/compress/releases/tag/v1.18.0)
+ * Add unsafe little endian loaders https://github.com/klauspost/compress/pull/1036
+ * fix: check `r.err != nil` but return a nil value error `err` by @alingse in https://github.com/klauspost/compress/pull/1028
+ * flate: Simplify L4-6 loading https://github.com/klauspost/compress/pull/1043
+ * flate: Simplify matchlen (remove asm) https://github.com/klauspost/compress/pull/1045
+ * s2: Improve small block compression speed w/o asm https://github.com/klauspost/compress/pull/1048
+ * flate: Fix matchlen L5+L6 https://github.com/klauspost/compress/pull/1049
+ * flate: Cleanup & reduce casts https://github.com/klauspost/compress/pull/1050
+
+
+ See changes to v1.17.x
+
+* Oct 11th, 2024 - [1.17.11](https://github.com/klauspost/compress/releases/tag/v1.17.11)
+ * zstd: Fix extra CRC written with multiple Close calls https://github.com/klauspost/compress/pull/1017
+ * s2: Don't use stack for index tables https://github.com/klauspost/compress/pull/1014
+ * gzhttp: No content-type on no body response code by @juliens in https://github.com/klauspost/compress/pull/1011
+ * gzhttp: Do not set the content-type when response has no body by @kevinpollet in https://github.com/klauspost/compress/pull/1013
+
+* Sep 23rd, 2024 - [1.17.10](https://github.com/klauspost/compress/releases/tag/v1.17.10)
+ * gzhttp: Add TransportAlwaysDecompress option. https://github.com/klauspost/compress/pull/978
+ * gzhttp: Add supported decompress request body by @mirecl in https://github.com/klauspost/compress/pull/1002
+ * s2: Add EncodeBuffer buffer recycling callback https://github.com/klauspost/compress/pull/982
+ * zstd: Improve memory usage on small streaming encodes https://github.com/klauspost/compress/pull/1007
+ * flate: read data written with partial flush by @vajexal in https://github.com/klauspost/compress/pull/996
+
+* Jun 12th, 2024 - [1.17.9](https://github.com/klauspost/compress/releases/tag/v1.17.9)
+ * s2: Reduce ReadFrom temporary allocations https://github.com/klauspost/compress/pull/949
+ * flate, zstd: Shave some bytes off amd64 matchLen by @greatroar in https://github.com/klauspost/compress/pull/963
+ * Upgrade zip/zlib to 1.22.4 upstream https://github.com/klauspost/compress/pull/970 https://github.com/klauspost/compress/pull/971
+ * zstd: BuildDict fails with RLE table https://github.com/klauspost/compress/pull/951
+
+* Apr 9th, 2024 - [1.17.8](https://github.com/klauspost/compress/releases/tag/v1.17.8)
+ * zstd: Reject blocks where reserved values are not 0 https://github.com/klauspost/compress/pull/885
+ * zstd: Add RLE detection+encoding https://github.com/klauspost/compress/pull/938
+
+* Feb 21st, 2024 - [1.17.7](https://github.com/klauspost/compress/releases/tag/v1.17.7)
+ * s2: Add AsyncFlush method: Complete the block without flushing by @Jille in https://github.com/klauspost/compress/pull/927
+ * s2: Fix literal+repeat exceeds dst crash https://github.com/klauspost/compress/pull/930
+
+* Feb 5th, 2024 - [1.17.6](https://github.com/klauspost/compress/releases/tag/v1.17.6)
+ * zstd: Fix incorrect repeat coding in best mode https://github.com/klauspost/compress/pull/923
+ * s2: Fix DecodeConcurrent deadlock on errors https://github.com/klauspost/compress/pull/925
+
+* Jan 26th, 2024 - [v1.17.5](https://github.com/klauspost/compress/releases/tag/v1.17.5)
+ * flate: Fix reset with dictionary on custom window encodes https://github.com/klauspost/compress/pull/912
+ * zstd: Add Frame header encoding and stripping https://github.com/klauspost/compress/pull/908
+ * zstd: Limit better/best default window to 8MB https://github.com/klauspost/compress/pull/913
+ * zstd: Speed improvements by @greatroar in https://github.com/klauspost/compress/pull/896 https://github.com/klauspost/compress/pull/910
+ * s2: Fix callbacks for skippable blocks and disallow 0xfe (Padding) by @Jille in https://github.com/klauspost/compress/pull/916 https://github.com/klauspost/compress/pull/917
+https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/compress/pull/918
+
+* Dec 1st, 2023 - [v1.17.4](https://github.com/klauspost/compress/releases/tag/v1.17.4)
+ * huff0: Speed up symbol counting by @greatroar in https://github.com/klauspost/compress/pull/887
+ * huff0: Remove byteReader by @greatroar in https://github.com/klauspost/compress/pull/886
+ * gzhttp: Allow overriding decompression on transport https://github.com/klauspost/compress/pull/892
+ * gzhttp: Clamp compression level https://github.com/klauspost/compress/pull/890
+ * gzip: Error out if reserved bits are set https://github.com/klauspost/compress/pull/891
+
+* Nov 15th, 2023 - [v1.17.3](https://github.com/klauspost/compress/releases/tag/v1.17.3)
+ * fse: Fix max header size https://github.com/klauspost/compress/pull/881
+ * zstd: Improve better/best compression https://github.com/klauspost/compress/pull/877
+ * gzhttp: Fix missing content type on Close https://github.com/klauspost/compress/pull/883
+
+* Oct 22nd, 2023 - [v1.17.2](https://github.com/klauspost/compress/releases/tag/v1.17.2)
+ * zstd: Fix rare *CORRUPTION* output in "best" mode. See https://github.com/klauspost/compress/pull/876
+
+* Oct 14th, 2023 - [v1.17.1](https://github.com/klauspost/compress/releases/tag/v1.17.1)
+ * s2: Fix S2 "best" dictionary wrong encoding https://github.com/klauspost/compress/pull/871
+ * flate: Reduce allocations in decompressor and minor code improvements by @fakefloordiv in https://github.com/klauspost/compress/pull/869
+ * s2: Fix EstimateBlockSize on 6&7 length input https://github.com/klauspost/compress/pull/867
+
+* Sept 19th, 2023 - [v1.17.0](https://github.com/klauspost/compress/releases/tag/v1.17.0)
+ * Add experimental dictionary builder https://github.com/klauspost/compress/pull/853
+ * Add xerial snappy read/writer https://github.com/klauspost/compress/pull/838
+ * flate: Add limited window compression https://github.com/klauspost/compress/pull/843
+ * s2: Do 2 overlapping match checks https://github.com/klauspost/compress/pull/839
+ * flate: Add amd64 assembly matchlen https://github.com/klauspost/compress/pull/837
+ * gzip: Copy bufio.Reader on Reset by @thatguystone in https://github.com/klauspost/compress/pull/860
+
+
+
+ See changes to v1.16.x
+
+
+* July 1st, 2023 - [v1.16.7](https://github.com/klauspost/compress/releases/tag/v1.16.7)
+ * zstd: Fix default level first dictionary encode https://github.com/klauspost/compress/pull/829
+ * s2: add GetBufferCapacity() method by @GiedriusS in https://github.com/klauspost/compress/pull/832
+
+* June 13, 2023 - [v1.16.6](https://github.com/klauspost/compress/releases/tag/v1.16.6)
+ * zstd: correctly ignore WithEncoderPadding(1) by @ianlancetaylor in https://github.com/klauspost/compress/pull/806
+ * zstd: Add amd64 match length assembly https://github.com/klauspost/compress/pull/824
+ * gzhttp: Handle informational headers by @rtribotte in https://github.com/klauspost/compress/pull/815
+ * s2: Improve Better compression slightly https://github.com/klauspost/compress/pull/663
+
+* Apr 16, 2023 - [v1.16.5](https://github.com/klauspost/compress/releases/tag/v1.16.5)
+ * zstd: readByte needs to use io.ReadFull by @jnoxon in https://github.com/klauspost/compress/pull/802
+ * gzip: Fix WriterTo after initial read https://github.com/klauspost/compress/pull/804
+
+* Apr 5, 2023 - [v1.16.4](https://github.com/klauspost/compress/releases/tag/v1.16.4)
+ * zstd: Improve zstd best efficiency by @greatroar and @klauspost in https://github.com/klauspost/compress/pull/784
+ * zstd: Respect WithAllLitEntropyCompression https://github.com/klauspost/compress/pull/792
+ * zstd: Fix amd64 not always detecting corrupt data https://github.com/klauspost/compress/pull/785
+ * zstd: Various minor improvements by @greatroar in https://github.com/klauspost/compress/pull/788 https://github.com/klauspost/compress/pull/794 https://github.com/klauspost/compress/pull/795
+ * s2: Fix huge block overflow https://github.com/klauspost/compress/pull/779
+ * s2: Allow CustomEncoder fallback https://github.com/klauspost/compress/pull/780
+ * gzhttp: Support ResponseWriter Unwrap() in gzhttp handler by @jgimenez in https://github.com/klauspost/compress/pull/799
+
+* Mar 13, 2023 - [v1.16.1](https://github.com/klauspost/compress/releases/tag/v1.16.1)
+ * zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776
+ * gzhttp: Add optional [BREACH mitigation](https://github.com/klauspost/compress/tree/master/gzhttp#breach-mitigation). https://github.com/klauspost/compress/pull/762 https://github.com/klauspost/compress/pull/768 https://github.com/klauspost/compress/pull/769 https://github.com/klauspost/compress/pull/770 https://github.com/klauspost/compress/pull/767
+ * s2: Add Intel LZ4s converter https://github.com/klauspost/compress/pull/766
+ * zstd: Minor bug fixes https://github.com/klauspost/compress/pull/771 https://github.com/klauspost/compress/pull/772 https://github.com/klauspost/compress/pull/773
+ * huff0: Speed up compress1xDo by @greatroar in https://github.com/klauspost/compress/pull/774
+
+* Feb 26, 2023 - [v1.16.0](https://github.com/klauspost/compress/releases/tag/v1.16.0)
+ * s2: Add [Dictionary](https://github.com/klauspost/compress/tree/master/s2#dictionaries) support. https://github.com/klauspost/compress/pull/685
+ * s2: Add Compression Size Estimate. https://github.com/klauspost/compress/pull/752
+ * s2: Add support for custom stream encoder. https://github.com/klauspost/compress/pull/755
+ * s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748
+ * s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747
+ * s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746
+
+
+
+ See changes to v1.15.x
+
+* Jan 21st, 2023 (v1.15.15)
+ * deflate: Improve level 7-9 https://github.com/klauspost/compress/pull/739
+ * zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728
+ * zstd: Various speed improvements by @greatroar https://github.com/klauspost/compress/pull/741 https://github.com/klauspost/compress/pull/734 https://github.com/klauspost/compress/pull/736 https://github.com/klauspost/compress/pull/744 https://github.com/klauspost/compress/pull/743 https://github.com/klauspost/compress/pull/745
+ * gzhttp: Add SuffixETag() and DropETag() options to prevent ETag collisions on compressed responses by @willbicks in https://github.com/klauspost/compress/pull/740
+
+* Jan 3rd, 2023 (v1.15.14)
+
+ * flate: Improve speed in big stateless blocks https://github.com/klauspost/compress/pull/718
+ * zstd: Minor speed tweaks by @greatroar in https://github.com/klauspost/compress/pull/716 https://github.com/klauspost/compress/pull/720
+ * export NoGzipResponseWriter for custom ResponseWriter wrappers by @harshavardhana in https://github.com/klauspost/compress/pull/722
+ * s2: Add example for indexing and existing stream https://github.com/klauspost/compress/pull/723
+
+* Dec 11, 2022 (v1.15.13)
+ * zstd: Add [MaxEncodedSize](https://pkg.go.dev/github.com/klauspost/compress@v1.15.13/zstd#Encoder.MaxEncodedSize) to encoder https://github.com/klauspost/compress/pull/691
+ * zstd: Various tweaks and improvements https://github.com/klauspost/compress/pull/693 https://github.com/klauspost/compress/pull/695 https://github.com/klauspost/compress/pull/696 https://github.com/klauspost/compress/pull/701 https://github.com/klauspost/compress/pull/702 https://github.com/klauspost/compress/pull/703 https://github.com/klauspost/compress/pull/704 https://github.com/klauspost/compress/pull/705 https://github.com/klauspost/compress/pull/706 https://github.com/klauspost/compress/pull/707 https://github.com/klauspost/compress/pull/708
+
+* Oct 26, 2022 (v1.15.12)
+
+ * zstd: Tweak decoder allocs. https://github.com/klauspost/compress/pull/680
+ * gzhttp: Always delete `HeaderNoCompression` https://github.com/klauspost/compress/pull/683
+
+* Sept 26, 2022 (v1.15.11)
+
+ * flate: Improve level 1-3 compression https://github.com/klauspost/compress/pull/678
+ * zstd: Improve "best" compression by @nightwolfz in https://github.com/klauspost/compress/pull/677
+ * zstd: Fix+reduce decompression allocations https://github.com/klauspost/compress/pull/668
+ * zstd: Fix non-effective noescape tag https://github.com/klauspost/compress/pull/667
+
+* Sept 16, 2022 (v1.15.10)
+
+ * zstd: Add [WithDecodeAllCapLimit](https://pkg.go.dev/github.com/klauspost/compress@v1.15.10/zstd#WithDecodeAllCapLimit) https://github.com/klauspost/compress/pull/649
+ * Add Go 1.19 - deprecate Go 1.16 https://github.com/klauspost/compress/pull/651
+ * flate: Improve level 5+6 compression https://github.com/klauspost/compress/pull/656
+ * zstd: Improve "better" compression https://github.com/klauspost/compress/pull/657
+ * s2: Improve "best" compression https://github.com/klauspost/compress/pull/658
+ * s2: Improve "better" compression. https://github.com/klauspost/compress/pull/635
+ * s2: Slightly faster non-assembly decompression https://github.com/klauspost/compress/pull/646
+ * Use arrays for constant size copies https://github.com/klauspost/compress/pull/659
+
+* July 21, 2022 (v1.15.9)
+
+ * zstd: Fix decoder crash on amd64 (no BMI) on invalid input https://github.com/klauspost/compress/pull/645
+ * zstd: Disable decoder extended memory copies (amd64) due to possible crashes https://github.com/klauspost/compress/pull/644
+ * zstd: Allow single segments up to "max decoded size" https://github.com/klauspost/compress/pull/643
+
+* July 13, 2022 (v1.15.8)
+
+ * gzip: fix stack exhaustion bug in Reader.Read https://github.com/klauspost/compress/pull/641
+ * s2: Add Index header trim/restore https://github.com/klauspost/compress/pull/638
+ * zstd: Optimize seqdeq amd64 asm by @greatroar in https://github.com/klauspost/compress/pull/636
+ * zstd: Improve decoder memcopy https://github.com/klauspost/compress/pull/637
+ * huff0: Pass a single bitReader pointer to asm by @greatroar in https://github.com/klauspost/compress/pull/634
+ * zstd: Branchless getBits for amd64 w/o BMI2 by @greatroar in https://github.com/klauspost/compress/pull/640
+ * gzhttp: Remove header before writing https://github.com/klauspost/compress/pull/639
+
+* June 29, 2022 (v1.15.7)
+
+ * s2: Fix absolute forward seeks https://github.com/klauspost/compress/pull/633
+ * zip: Merge upstream https://github.com/klauspost/compress/pull/631
+ * zip: Re-add zip64 fix https://github.com/klauspost/compress/pull/624
+ * zstd: translate fseDecoder.buildDtable into asm by @WojciechMula in https://github.com/klauspost/compress/pull/598
+ * flate: Faster histograms https://github.com/klauspost/compress/pull/620
+ * deflate: Use compound hcode https://github.com/klauspost/compress/pull/622
+
+* June 3, 2022 (v1.15.6)
+ * s2: Improve coding for long, close matches https://github.com/klauspost/compress/pull/613
+ * s2c: Add Snappy/S2 stream recompression https://github.com/klauspost/compress/pull/611
+ * zstd: Always use configured block size https://github.com/klauspost/compress/pull/605
+ * zstd: Fix incorrect hash table placement for dict encoding in default https://github.com/klauspost/compress/pull/606
+ * zstd: Apply default config to ZipDecompressor without options https://github.com/klauspost/compress/pull/608
+ * gzhttp: Exclude more common archive formats https://github.com/klauspost/compress/pull/612
+ * s2: Add ReaderIgnoreCRC https://github.com/klauspost/compress/pull/609
+ * s2: Remove sanity load on index creation https://github.com/klauspost/compress/pull/607
+ * snappy: Use dedicated function for scoring https://github.com/klauspost/compress/pull/614
+ * s2c+s2d: Use official snappy framed extension https://github.com/klauspost/compress/pull/610
+
+* May 25, 2022 (v1.15.5)
+ * s2: Add concurrent stream decompression https://github.com/klauspost/compress/pull/602
+ * s2: Fix final emit oob read crash on amd64 https://github.com/klauspost/compress/pull/601
+ * huff0: asm implementation of Decompress1X by @WojciechMula https://github.com/klauspost/compress/pull/596
+ * zstd: Use 1 less goroutine for stream decoding https://github.com/klauspost/compress/pull/588
+ * zstd: Copy literal in 16 byte blocks when possible https://github.com/klauspost/compress/pull/592
+ * zstd: Speed up when WithDecoderLowmem(false) https://github.com/klauspost/compress/pull/599
+ * zstd: faster next state update in BMI2 version of decode by @WojciechMula in https://github.com/klauspost/compress/pull/593
+ * huff0: Do not check max size when reading table. https://github.com/klauspost/compress/pull/586
+ * flate: Inplace hashing for level 7-9 https://github.com/klauspost/compress/pull/590
+
+
+* May 11, 2022 (v1.15.4)
+ * huff0: decompress directly into output by @WojciechMula in [#577](https://github.com/klauspost/compress/pull/577)
+ * inflate: Keep dict on stack [#581](https://github.com/klauspost/compress/pull/581)
+ * zstd: Faster decoding memcopy in asm [#583](https://github.com/klauspost/compress/pull/583)
+ * zstd: Fix ignored crc [#580](https://github.com/klauspost/compress/pull/580)
+
+* May 5, 2022 (v1.15.3)
+ * zstd: Allow to ignore checksum checking by @WojciechMula [#572](https://github.com/klauspost/compress/pull/572)
+ * s2: Fix incorrect seek for io.SeekEnd in [#575](https://github.com/klauspost/compress/pull/575)
+
+* Apr 26, 2022 (v1.15.2)
+ * zstd: Add x86-64 assembly for decompression on streams and blocks. Contributed by [@WojciechMula](https://github.com/WojciechMula). Typically 2x faster. [#528](https://github.com/klauspost/compress/pull/528) [#531](https://github.com/klauspost/compress/pull/531) [#545](https://github.com/klauspost/compress/pull/545) [#537](https://github.com/klauspost/compress/pull/537)
+ * zstd: Add options to ZipDecompressor and fixes [#539](https://github.com/klauspost/compress/pull/539)
+ * s2: Use sorted search for index [#555](https://github.com/klauspost/compress/pull/555)
+ * Minimum version is Go 1.16, added CI test on 1.18.
+
+* Mar 11, 2022 (v1.15.1)
+ * huff0: Add x86 assembly of Decode4X by @WojciechMula in [#512](https://github.com/klauspost/compress/pull/512)
+ * zstd: Reuse zip decoders in [#514](https://github.com/klauspost/compress/pull/514)
+ * zstd: Detect extra block data and report as corrupted in [#520](https://github.com/klauspost/compress/pull/520)
+ * zstd: Handle zero sized frame content size stricter in [#521](https://github.com/klauspost/compress/pull/521)
+ * zstd: Add stricter block size checks in [#523](https://github.com/klauspost/compress/pull/523)
+
+* Mar 3, 2022 (v1.15.0)
+ * zstd: Refactor decoder [#498](https://github.com/klauspost/compress/pull/498)
+ * zstd: Add stream encoding without goroutines [#505](https://github.com/klauspost/compress/pull/505)
+ * huff0: Prevent single blocks exceeding 16 bits by @klauspost in[#507](https://github.com/klauspost/compress/pull/507)
+ * flate: Inline literal emission [#509](https://github.com/klauspost/compress/pull/509)
+ * gzhttp: Add zstd to transport [#400](https://github.com/klauspost/compress/pull/400)
+ * gzhttp: Make content-type optional [#510](https://github.com/klauspost/compress/pull/510)
+
+Both compression and decompression now supports "synchronous" stream operations. This means that whenever "concurrency" is set to 1, they will operate without spawning goroutines.
+
+Stream decompression is now faster on asynchronous, since the goroutine allocation much more effectively splits the workload. On typical streams this will typically use 2 cores fully for decompression. When a stream has finished decoding no goroutines will be left over, so decoders can now safely be pooled and still be garbage collected.
+
+While the release has been extensively tested, it is recommended to testing when upgrading.
+
+
+
+
+ See changes to v1.14.x
+
+* Feb 22, 2022 (v1.14.4)
+ * flate: Fix rare huffman only (-2) corruption. [#503](https://github.com/klauspost/compress/pull/503)
+ * zip: Update deprecated CreateHeaderRaw to correctly call CreateRaw by @saracen in [#502](https://github.com/klauspost/compress/pull/502)
+ * zip: don't read data descriptor early by @saracen in [#501](https://github.com/klauspost/compress/pull/501) #501
+ * huff0: Use static decompression buffer up to 30% faster [#499](https://github.com/klauspost/compress/pull/499) [#500](https://github.com/klauspost/compress/pull/500)
+
+* Feb 17, 2022 (v1.14.3)
+ * flate: Improve fastest levels compression speed ~10% more throughput. [#482](https://github.com/klauspost/compress/pull/482) [#489](https://github.com/klauspost/compress/pull/489) [#490](https://github.com/klauspost/compress/pull/490) [#491](https://github.com/klauspost/compress/pull/491) [#494](https://github.com/klauspost/compress/pull/494) [#478](https://github.com/klauspost/compress/pull/478)
+ * flate: Faster decompression speed, ~5-10%. [#483](https://github.com/klauspost/compress/pull/483)
+ * s2: Faster compression with Go v1.18 and amd64 microarch level 3+. [#484](https://github.com/klauspost/compress/pull/484) [#486](https://github.com/klauspost/compress/pull/486)
+
+* Jan 25, 2022 (v1.14.2)
+ * zstd: improve header decoder by @dsnet [#476](https://github.com/klauspost/compress/pull/476)
+ * zstd: Add bigger default blocks [#469](https://github.com/klauspost/compress/pull/469)
+ * zstd: Remove unused decompression buffer [#470](https://github.com/klauspost/compress/pull/470)
+ * zstd: Fix logically dead code by @ningmingxiao [#472](https://github.com/klauspost/compress/pull/472)
+ * flate: Improve level 7-9 [#471](https://github.com/klauspost/compress/pull/471) [#473](https://github.com/klauspost/compress/pull/473)
+ * zstd: Add noasm tag for xxhash [#475](https://github.com/klauspost/compress/pull/475)
+
+* Jan 11, 2022 (v1.14.1)
+ * s2: Add stream index in [#462](https://github.com/klauspost/compress/pull/462)
+ * flate: Speed and efficiency improvements in [#439](https://github.com/klauspost/compress/pull/439) [#461](https://github.com/klauspost/compress/pull/461) [#455](https://github.com/klauspost/compress/pull/455) [#452](https://github.com/klauspost/compress/pull/452) [#458](https://github.com/klauspost/compress/pull/458)
+ * zstd: Performance improvement in [#420]( https://github.com/klauspost/compress/pull/420) [#456](https://github.com/klauspost/compress/pull/456) [#437](https://github.com/klauspost/compress/pull/437) [#467](https://github.com/klauspost/compress/pull/467) [#468](https://github.com/klauspost/compress/pull/468)
+ * zstd: add arm64 xxhash assembly in [#464](https://github.com/klauspost/compress/pull/464)
+ * Add garbled for binaries for s2 in [#445](https://github.com/klauspost/compress/pull/445)
+
+
+
+ See changes to v1.13.x
+
+* Aug 30, 2021 (v1.13.5)
+ * gz/zlib/flate: Alias stdlib errors [#425](https://github.com/klauspost/compress/pull/425)
+ * s2: Add block support to commandline tools [#413](https://github.com/klauspost/compress/pull/413)
+ * zstd: pooledZipWriter should return Writers to the same pool [#426](https://github.com/klauspost/compress/pull/426)
+ * Removed golang/snappy as external dependency for tests [#421](https://github.com/klauspost/compress/pull/421)
+
+* Aug 12, 2021 (v1.13.4)
+ * Add [snappy replacement package](https://github.com/klauspost/compress/tree/master/snappy).
+ * zstd: Fix incorrect encoding in "best" mode [#415](https://github.com/klauspost/compress/pull/415)
+
+* Aug 3, 2021 (v1.13.3)
+ * zstd: Improve Best compression [#404](https://github.com/klauspost/compress/pull/404)
+ * zstd: Fix WriteTo error forwarding [#411](https://github.com/klauspost/compress/pull/411)
+ * gzhttp: Return http.HandlerFunc instead of http.Handler. Unlikely breaking change. [#406](https://github.com/klauspost/compress/pull/406)
+ * s2sx: Fix max size error [#399](https://github.com/klauspost/compress/pull/399)
+ * zstd: Add optional stream content size on reset [#401](https://github.com/klauspost/compress/pull/401)
+ * zstd: use SpeedBestCompression for level >= 10 [#410](https://github.com/klauspost/compress/pull/410)
+
+* Jun 14, 2021 (v1.13.1)
+ * s2: Add full Snappy output support [#396](https://github.com/klauspost/compress/pull/396)
+ * zstd: Add configurable [Decoder window](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithDecoderMaxWindow) size [#394](https://github.com/klauspost/compress/pull/394)
+ * gzhttp: Add header to skip compression [#389](https://github.com/klauspost/compress/pull/389)
+ * s2: Improve speed with bigger output margin [#395](https://github.com/klauspost/compress/pull/395)
+
+* Jun 3, 2021 (v1.13.0)
+ * Added [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp#gzip-handler) which allows wrapping HTTP servers and clients with GZIP compressors.
+ * zstd: Detect short invalid signatures [#382](https://github.com/klauspost/compress/pull/382)
+ * zstd: Spawn decoder goroutine only if needed. [#380](https://github.com/klauspost/compress/pull/380)
+
+
+
+
+ See changes to v1.12.x
+
+* May 25, 2021 (v1.12.3)
+ * deflate: Better/faster Huffman encoding [#374](https://github.com/klauspost/compress/pull/374)
+ * deflate: Allocate less for history. [#375](https://github.com/klauspost/compress/pull/375)
+ * zstd: Forward read errors [#373](https://github.com/klauspost/compress/pull/373)
+
+* Apr 27, 2021 (v1.12.2)
+ * zstd: Improve better/best compression [#360](https://github.com/klauspost/compress/pull/360) [#364](https://github.com/klauspost/compress/pull/364) [#365](https://github.com/klauspost/compress/pull/365)
+ * zstd: Add helpers to compress/decompress zstd inside zip files [#363](https://github.com/klauspost/compress/pull/363)
+ * deflate: Improve level 5+6 compression [#367](https://github.com/klauspost/compress/pull/367)
+ * s2: Improve better/best compression [#358](https://github.com/klauspost/compress/pull/358) [#359](https://github.com/klauspost/compress/pull/358)
+ * s2: Load after checking src limit on amd64. [#362](https://github.com/klauspost/compress/pull/362)
+ * s2sx: Limit max executable size [#368](https://github.com/klauspost/compress/pull/368)
+
+* Apr 14, 2021 (v1.12.1)
+ * snappy package removed. Upstream added as dependency.
+ * s2: Better compression in "best" mode [#353](https://github.com/klauspost/compress/pull/353)
+ * s2sx: Add stdin input and detect pre-compressed from signature [#352](https://github.com/klauspost/compress/pull/352)
+ * s2c/s2d: Add http as possible input [#348](https://github.com/klauspost/compress/pull/348)
+ * s2c/s2d/s2sx: Always truncate when writing files [#352](https://github.com/klauspost/compress/pull/352)
+ * zstd: Reduce memory usage further when using [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) [#346](https://github.com/klauspost/compress/pull/346)
+ * s2: Fix potential problem with amd64 assembly and profilers [#349](https://github.com/klauspost/compress/pull/349)
+
+
+
+ See changes to v1.11.x
+
+* Mar 26, 2021 (v1.11.13)
+ * zstd: Big speedup on small dictionary encodes [#344](https://github.com/klauspost/compress/pull/344) [#345](https://github.com/klauspost/compress/pull/345)
+ * zstd: Add [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) encoder option [#336](https://github.com/klauspost/compress/pull/336)
+ * deflate: Improve entropy compression [#338](https://github.com/klauspost/compress/pull/338)
+ * s2: Clean up and minor performance improvement in best [#341](https://github.com/klauspost/compress/pull/341)
+
+* Mar 5, 2021 (v1.11.12)
+ * s2: Add `s2sx` binary that creates [self extracting archives](https://github.com/klauspost/compress/tree/master/s2#s2sx-self-extracting-archives).
+ * s2: Speed up decompression on non-assembly platforms [#328](https://github.com/klauspost/compress/pull/328)
+
+* Mar 1, 2021 (v1.11.9)
+ * s2: Add ARM64 decompression assembly. Around 2x output speed. [#324](https://github.com/klauspost/compress/pull/324)
+ * s2: Improve "better" speed and efficiency. [#325](https://github.com/klauspost/compress/pull/325)
+ * s2: Fix binaries.
+
+* Feb 25, 2021 (v1.11.8)
+ * s2: Fixed occasional out-of-bounds write on amd64. Upgrade recommended.
+ * s2: Add AMD64 assembly for better mode. 25-50% faster. [#315](https://github.com/klauspost/compress/pull/315)
+ * s2: Less upfront decoder allocation. [#322](https://github.com/klauspost/compress/pull/322)
+ * zstd: Faster "compression" of incompressible data. [#314](https://github.com/klauspost/compress/pull/314)
+ * zip: Fix zip64 headers. [#313](https://github.com/klauspost/compress/pull/313)
+
+* Jan 14, 2021 (v1.11.7)
+ * Use Bytes() interface to get bytes across packages. [#309](https://github.com/klauspost/compress/pull/309)
+ * s2: Add 'best' compression option. [#310](https://github.com/klauspost/compress/pull/310)
+ * s2: Add ReaderMaxBlockSize, changes `s2.NewReader` signature to include varargs. [#311](https://github.com/klauspost/compress/pull/311)
+ * s2: Fix crash on small better buffers. [#308](https://github.com/klauspost/compress/pull/308)
+ * s2: Clean up decoder. [#312](https://github.com/klauspost/compress/pull/312)
+
+* Jan 7, 2021 (v1.11.6)
+ * zstd: Make decoder allocations smaller [#306](https://github.com/klauspost/compress/pull/306)
+ * zstd: Free Decoder resources when Reset is called with a nil io.Reader [#305](https://github.com/klauspost/compress/pull/305)
+
+* Dec 20, 2020 (v1.11.4)
+ * zstd: Add Best compression mode [#304](https://github.com/klauspost/compress/pull/304)
+ * Add header decoder [#299](https://github.com/klauspost/compress/pull/299)
+ * s2: Add uncompressed stream option [#297](https://github.com/klauspost/compress/pull/297)
+ * Simplify/speed up small blocks with known max size. [#300](https://github.com/klauspost/compress/pull/300)
+ * zstd: Always reset literal dict encoder [#303](https://github.com/klauspost/compress/pull/303)
+
+* Nov 15, 2020 (v1.11.3)
+ * inflate: 10-15% faster decompression [#293](https://github.com/klauspost/compress/pull/293)
+ * zstd: Tweak DecodeAll default allocation [#295](https://github.com/klauspost/compress/pull/295)
+
+* Oct 11, 2020 (v1.11.2)
+ * s2: Fix out of bounds read in "better" block compression [#291](https://github.com/klauspost/compress/pull/291)
+
+* Oct 1, 2020 (v1.11.1)
+ * zstd: Set allLitEntropy true in default configuration [#286](https://github.com/klauspost/compress/pull/286)
+
+* Sept 8, 2020 (v1.11.0)
+ * zstd: Add experimental compression [dictionaries](https://github.com/klauspost/compress/tree/master/zstd#dictionaries) [#281](https://github.com/klauspost/compress/pull/281)
+ * zstd: Fix mixed Write and ReadFrom calls [#282](https://github.com/klauspost/compress/pull/282)
+ * inflate/gz: Limit variable shifts, ~5% faster decompression [#274](https://github.com/klauspost/compress/pull/274)
+
+
+
+ See changes to v1.10.x
+
+* July 8, 2020 (v1.10.11)
+ * zstd: Fix extra block when compressing with ReadFrom. [#278](https://github.com/klauspost/compress/pull/278)
+ * huff0: Also populate compression table when reading decoding table. [#275](https://github.com/klauspost/compress/pull/275)
+
+* June 23, 2020 (v1.10.10)
+ * zstd: Skip entropy compression in fastest mode when no matches. [#270](https://github.com/klauspost/compress/pull/270)
+
+* June 16, 2020 (v1.10.9):
+ * zstd: API change for specifying dictionaries. See [#268](https://github.com/klauspost/compress/pull/268)
+ * zip: update CreateHeaderRaw to handle zip64 fields. [#266](https://github.com/klauspost/compress/pull/266)
+ * Fuzzit tests removed. The service has been purchased and is no longer available.
+
+* June 5, 2020 (v1.10.8):
+ * 1.15x faster zstd block decompression. [#265](https://github.com/klauspost/compress/pull/265)
+
+* June 1, 2020 (v1.10.7):
+ * Added zstd decompression [dictionary support](https://github.com/klauspost/compress/tree/master/zstd#dictionaries)
+ * Increase zstd decompression speed up to 1.19x. [#259](https://github.com/klauspost/compress/pull/259)
+ * Remove internal reset call in zstd compression and reduce allocations. [#263](https://github.com/klauspost/compress/pull/263)
+
+* May 21, 2020: (v1.10.6)
+ * zstd: Reduce allocations while decoding. [#258](https://github.com/klauspost/compress/pull/258), [#252](https://github.com/klauspost/compress/pull/252)
+ * zstd: Stricter decompression checks.
+
+* April 12, 2020: (v1.10.5)
+ * s2-commands: Flush output when receiving SIGINT. [#239](https://github.com/klauspost/compress/pull/239)
+
+* Apr 8, 2020: (v1.10.4)
+ * zstd: Minor/special case optimizations. [#251](https://github.com/klauspost/compress/pull/251), [#250](https://github.com/klauspost/compress/pull/250), [#249](https://github.com/klauspost/compress/pull/249), [#247](https://github.com/klauspost/compress/pull/247)
+* Mar 11, 2020: (v1.10.3)
+ * s2: Use S2 encoder in pure Go mode for Snappy output as well. [#245](https://github.com/klauspost/compress/pull/245)
+ * s2: Fix pure Go block encoder. [#244](https://github.com/klauspost/compress/pull/244)
+ * zstd: Added "better compression" mode. [#240](https://github.com/klauspost/compress/pull/240)
+ * zstd: Improve speed of fastest compression mode by 5-10% [#241](https://github.com/klauspost/compress/pull/241)
+ * zstd: Skip creating encoders when not needed. [#238](https://github.com/klauspost/compress/pull/238)
+
+* Feb 27, 2020: (v1.10.2)
+ * Close to 50% speedup in inflate (gzip/zip decompression). [#236](https://github.com/klauspost/compress/pull/236) [#234](https://github.com/klauspost/compress/pull/234) [#232](https://github.com/klauspost/compress/pull/232)
+ * Reduce deflate level 1-6 memory usage up to 59%. [#227](https://github.com/klauspost/compress/pull/227)
+
+* Feb 18, 2020: (v1.10.1)
+ * Fix zstd crash when resetting multiple times without sending data. [#226](https://github.com/klauspost/compress/pull/226)
+ * deflate: Fix dictionary use on level 1-6. [#224](https://github.com/klauspost/compress/pull/224)
+ * Remove deflate writer reference when closing. [#224](https://github.com/klauspost/compress/pull/224)
+
+* Feb 4, 2020: (v1.10.0)
+ * Add optional dictionary to [stateless deflate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc#StatelessDeflate). Breaking change, send `nil` for previous behaviour. [#216](https://github.com/klauspost/compress/pull/216)
+ * Fix buffer overflow on repeated small block deflate. [#218](https://github.com/klauspost/compress/pull/218)
+ * Allow copying content from an existing ZIP file without decompressing+compressing. [#214](https://github.com/klauspost/compress/pull/214)
+ * Added [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) AMD64 assembler and various optimizations. Stream speed >10GB/s. [#186](https://github.com/klauspost/compress/pull/186)
+
+
+
+
+ See changes prior to v1.10.0
+
+* Jan 20,2020 (v1.9.8) Optimize gzip/deflate with better size estimates and faster table generation. [#207](https://github.com/klauspost/compress/pull/207) by [luyu6056](https://github.com/luyu6056), [#206](https://github.com/klauspost/compress/pull/206).
+* Jan 11, 2020: S2 Encode/Decode will use provided buffer if capacity is big enough. [#204](https://github.com/klauspost/compress/pull/204)
+* Jan 5, 2020: (v1.9.7) Fix another zstd regression in v1.9.5 - v1.9.6 removed.
+* Jan 4, 2020: (v1.9.6) Regression in v1.9.5 fixed causing corrupt zstd encodes in rare cases.
+* Jan 4, 2020: Faster IO in [s2c + s2d commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) compression/decompression. [#192](https://github.com/klauspost/compress/pull/192)
+* Dec 29, 2019: Removed v1.9.5 since fuzz tests showed a compatibility problem with the reference zstandard decoder.
+* Dec 29, 2019: (v1.9.5) zstd: 10-20% faster block compression. [#199](https://github.com/klauspost/compress/pull/199)
+* Dec 29, 2019: [zip](https://godoc.org/github.com/klauspost/compress/zip) package updated with latest Go features
+* Dec 29, 2019: zstd: Single segment flag condintions tweaked. [#197](https://github.com/klauspost/compress/pull/197)
+* Dec 18, 2019: s2: Faster compression when ReadFrom is used. [#198](https://github.com/klauspost/compress/pull/198)
+* Dec 10, 2019: s2: Fix repeat length output when just above at 16MB limit.
+* Dec 10, 2019: zstd: Add function to get decoder as io.ReadCloser. [#191](https://github.com/klauspost/compress/pull/191)
+* Dec 3, 2019: (v1.9.4) S2: limit max repeat length. [#188](https://github.com/klauspost/compress/pull/188)
+* Dec 3, 2019: Add [WithNoEntropyCompression](https://godoc.org/github.com/klauspost/compress/zstd#WithNoEntropyCompression) to zstd [#187](https://github.com/klauspost/compress/pull/187)
+* Dec 3, 2019: Reduce memory use for tests. Check for leaked goroutines.
+* Nov 28, 2019 (v1.9.3) Less allocations in stateless deflate.
+* Nov 28, 2019: 5-20% Faster huff0 decode. Impacts zstd as well. [#184](https://github.com/klauspost/compress/pull/184)
+* Nov 12, 2019 (v1.9.2) Added [Stateless Compression](#stateless-compression) for gzip/deflate.
+* Nov 12, 2019: Fixed zstd decompression of large single blocks. [#180](https://github.com/klauspost/compress/pull/180)
+* Nov 11, 2019: Set default [s2c](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) block size to 4MB.
+* Nov 11, 2019: Reduce inflate memory use by 1KB.
+* Nov 10, 2019: Less allocations in deflate bit writer.
+* Nov 10, 2019: Fix inconsistent error returned by zstd decoder.
+* Oct 28, 2019 (v1.9.1) ztsd: Fix crash when compressing blocks. [#174](https://github.com/klauspost/compress/pull/174)
+* Oct 24, 2019 (v1.9.0) zstd: Fix rare data corruption [#173](https://github.com/klauspost/compress/pull/173)
+* Oct 24, 2019 zstd: Fix huff0 out of buffer write [#171](https://github.com/klauspost/compress/pull/171) and always return errors [#172](https://github.com/klauspost/compress/pull/172)
+* Oct 10, 2019: Big deflate rewrite, 30-40% faster with better compression [#105](https://github.com/klauspost/compress/pull/105)
+
+
+
+
+ See changes prior to v1.9.0
+
+* Oct 10, 2019: (v1.8.6) zstd: Allow partial reads to get flushed data. [#169](https://github.com/klauspost/compress/pull/169)
+* Oct 3, 2019: Fix inconsistent results on broken zstd streams.
+* Sep 25, 2019: Added `-rm` (remove source files) and `-q` (no output except errors) to `s2c` and `s2d` [commands](https://github.com/klauspost/compress/tree/master/s2#commandline-tools)
+* Sep 16, 2019: (v1.8.4) Add `s2c` and `s2d` [commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools).
+* Sep 10, 2019: (v1.8.3) Fix s2 decoder [Skip](https://godoc.org/github.com/klauspost/compress/s2#Reader.Skip).
+* Sep 7, 2019: zstd: Added [WithWindowSize](https://godoc.org/github.com/klauspost/compress/zstd#WithWindowSize), contributed by [ianwilkes](https://github.com/ianwilkes).
+* Sep 5, 2019: (v1.8.2) Add [WithZeroFrames](https://godoc.org/github.com/klauspost/compress/zstd#WithZeroFrames) which adds full zero payload block encoding option.
+* Sep 5, 2019: Lazy initialization of zstandard predefined en/decoder tables.
+* Aug 26, 2019: (v1.8.1) S2: 1-2% compression increase in "better" compression mode.
+* Aug 26, 2019: zstd: Check maximum size of Huffman 1X compressed literals while decoding.
+* Aug 24, 2019: (v1.8.0) Added [S2 compression](https://github.com/klauspost/compress/tree/master/s2#s2-compression), a high performance replacement for Snappy.
+* Aug 21, 2019: (v1.7.6) Fixed minor issues found by fuzzer. One could lead to zstd not decompressing.
+* Aug 18, 2019: Add [fuzzit](https://fuzzit.dev/) continuous fuzzing.
+* Aug 14, 2019: zstd: Skip incompressible data 2x faster. [#147](https://github.com/klauspost/compress/pull/147)
+* Aug 4, 2019 (v1.7.5): Better literal compression. [#146](https://github.com/klauspost/compress/pull/146)
+* Aug 4, 2019: Faster zstd compression. [#143](https://github.com/klauspost/compress/pull/143) [#144](https://github.com/klauspost/compress/pull/144)
+* Aug 4, 2019: Faster zstd decompression. [#145](https://github.com/klauspost/compress/pull/145) [#143](https://github.com/klauspost/compress/pull/143) [#142](https://github.com/klauspost/compress/pull/142)
+* July 15, 2019 (v1.7.4): Fix double EOF block in rare cases on zstd encoder.
+* July 15, 2019 (v1.7.3): Minor speedup/compression increase in default zstd encoder.
+* July 14, 2019: zstd decoder: Fix decompression error on multiple uses with mixed content.
+* July 7, 2019 (v1.7.2): Snappy update, zstd decoder potential race fix.
+* June 17, 2019: zstd decompression bugfix.
+* June 17, 2019: fix 32 bit builds.
+* June 17, 2019: Easier use in modules (less dependencies).
+* June 9, 2019: New stronger "default" [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression mode. Matches zstd default compression ratio.
+* June 5, 2019: 20-40% throughput in [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and better compression.
+* June 5, 2019: deflate/gzip compression: Reduce memory usage of lower compression levels.
+* June 2, 2019: Added [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression!
+* May 25, 2019: deflate/gzip: 10% faster bit writer, mostly visible in lower levels.
+* Apr 22, 2019: [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) decompression added.
+* Aug 1, 2018: Added [huff0 README](https://github.com/klauspost/compress/tree/master/huff0#huff0-entropy-compression).
+* Jul 8, 2018: Added [Performance Update 2018](#performance-update-2018) below.
+* Jun 23, 2018: Merged [Go 1.11 inflate optimizations](https://go-review.googlesource.com/c/go/+/102235). Go 1.9 is now required. Backwards compatible version tagged with [v1.3.0](https://github.com/klauspost/compress/releases/tag/v1.3.0).
+* Apr 2, 2018: Added [huff0](https://godoc.org/github.com/klauspost/compress/huff0) en/decoder. Experimental for now, API may change.
+* Mar 4, 2018: Added [FSE Entropy](https://godoc.org/github.com/klauspost/compress/fse) en/decoder. Experimental for now, API may change.
+* Nov 3, 2017: Add compression [Estimate](https://godoc.org/github.com/klauspost/compress#Estimate) function.
+* May 28, 2017: Reduce allocations when resetting decoder.
+* Apr 02, 2017: Change back to official crc32, since changes were merged in Go 1.7.
+* Jan 14, 2017: Reduce stack pressure due to array copies. See [Issue #18625](https://github.com/golang/go/issues/18625).
+* Oct 25, 2016: Level 2-4 have been rewritten and now offers significantly better performance than before.
+* Oct 20, 2016: Port zlib changes from Go 1.7 to fix zlib writer issue. Please update.
+* Oct 16, 2016: Go 1.7 changes merged. Apples to apples this package is a few percent faster, but has a significantly better balance between speed and compression per level.
+* Mar 24, 2016: Always attempt Huffman encoding on level 4-7. This improves base 64 encoded data compression.
+* Mar 24, 2016: Small speedup for level 1-3.
+* Feb 19, 2016: Faster bit writer, level -2 is 15% faster, level 1 is 4% faster.
+* Feb 19, 2016: Handle small payloads faster in level 1-3.
+* Feb 19, 2016: Added faster level 2 + 3 compression modes.
+* Feb 19, 2016: [Rebalanced compression levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/), so there is a more even progression in terms of compression. New default level is 5.
+* Feb 14, 2016: Snappy: Merge upstream changes.
+* Feb 14, 2016: Snappy: Fix aggressive skipping.
+* Feb 14, 2016: Snappy: Update benchmark.
+* Feb 13, 2016: Deflate: Fixed assembler problem that could lead to sub-optimal compression.
+* Feb 12, 2016: Snappy: Added AMD64 SSE 4.2 optimizations to matching, which makes easy to compress material run faster. Typical speedup is around 25%.
+* Feb 9, 2016: Added Snappy package fork. This version is 5-7% faster, much more on hard to compress content.
+* Jan 30, 2016: Optimize level 1 to 3 by not considering static dictionary or storing uncompressed. ~4-5% speedup.
+* Jan 16, 2016: Optimization on deflate level 1,2,3 compression.
+* Jan 8 2016: Merge [CL 18317](https://go-review.googlesource.com/#/c/18317): fix reading, writing of zip64 archives.
+* Dec 8 2015: Make level 1 and -2 deterministic even if write size differs.
+* Dec 8 2015: Split encoding functions, so hashing and matching can potentially be inlined. 1-3% faster on AMD64. 5% faster on other platforms.
+* Dec 8 2015: Fixed rare [one byte out-of bounds read](https://github.com/klauspost/compress/issues/20). Please update!
+* Nov 23 2015: Optimization on token writer. ~2-4% faster. Contributed by [@dsnet](https://github.com/dsnet).
+* Nov 20 2015: Small optimization to bit writer on 64 bit systems.
+* Nov 17 2015: Fixed out-of-bound errors if the underlying Writer returned an error. See [#15](https://github.com/klauspost/compress/issues/15).
+* Nov 12 2015: Added [io.WriterTo](https://golang.org/pkg/io/#WriterTo) support to gzip/inflate.
+* Nov 11 2015: Merged [CL 16669](https://go-review.googlesource.com/#/c/16669/4): archive/zip: enable overriding (de)compressors per file
+* Oct 15 2015: Added skipping on uncompressible data. Random data speed up >5x.
+
+
+
+# deflate usage
+
+The packages are drop-in replacements for standard library [deflate](https://godoc.org/github.com/klauspost/compress/flate), [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip), and [zlib](https://godoc.org/github.com/klauspost/compress/zlib). Simply replace the import path to use them:
+
+Typical speed is about 2x of the standard library packages.
+
+| old import | new import | Documentation |
+|------------------|---------------------------------------|-------------------------------------------------------------------------|
+| `compress/gzip` | `github.com/klauspost/compress/gzip` | [gzip](https://pkg.go.dev/github.com/klauspost/compress/gzip?tab=doc) |
+| `compress/zlib` | `github.com/klauspost/compress/zlib` | [zlib](https://pkg.go.dev/github.com/klauspost/compress/zlib?tab=doc) |
+| `archive/zip` | `github.com/klauspost/compress/zip` | [zip](https://pkg.go.dev/github.com/klauspost/compress/zip?tab=doc) |
+| `compress/flate` | `github.com/klauspost/compress/flate` | [flate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc) |
+
+You may also be interested in [pgzip](https://github.com/klauspost/pgzip), which is a drop-in replacement for gzip, which support multithreaded compression on big files and the optimized [crc32](https://github.com/klauspost/crc32) package used by these packages.
+
+The packages implement the same API as the standard library, so you can use the original godoc documentation: [gzip](http://golang.org/pkg/compress/gzip/), [zip](http://golang.org/pkg/archive/zip/), [zlib](http://golang.org/pkg/compress/zlib/), [flate](http://golang.org/pkg/compress/flate/).
+
+Currently there is only minor speedup on decompression (mostly CRC32 calculation).
+
+Memory usage is typically 1MB for a Writer. stdlib is in the same range.
+If you expect to have a lot of concurrently allocated Writers consider using
+the stateless compression described below.
+
+For compression performance, see: [this spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing).
+
+To disable all assembly add `-tags=noasm`. This works across all packages.
+
+# Stateless compression
+
+This package offers stateless compression as a special option for gzip/deflate.
+It will do compression but without maintaining any state between Write calls.
+
+This means there will be no memory kept between Write calls, but compression and speed will be suboptimal.
+
+This is only relevant in cases where you expect to run many thousands of compressors concurrently,
+but with very little activity. This is *not* intended for regular web servers serving individual requests.
+
+Because of this, the size of actual Write calls will affect output size.
+
+In gzip, specify level `-3` / `gzip.StatelessCompression` to enable.
+
+For direct deflate use, NewStatelessWriter and StatelessDeflate are available. See [documentation](https://godoc.org/github.com/klauspost/compress/flate#NewStatelessWriter)
+
+A `bufio.Writer` can of course be used to control write sizes. For example, to use a 4KB buffer:
+
+```go
+ // replace 'ioutil.Discard' with your output.
+ gzw, err := gzip.NewWriterLevel(ioutil.Discard, gzip.StatelessCompression)
+ if err != nil {
+ return err
+ }
+ defer gzw.Close()
+
+ w := bufio.NewWriterSize(gzw, 4096)
+ defer w.Flush()
+
+ // Write to 'w'
+```
+
+This will only use up to 4KB in memory when the writer is idle.
+
+Compression is almost always worse than the fastest compression level
+and each write will allocate (a little) memory.
+
+
+# Other packages
+
+Here are other packages of good quality and pure Go (no cgo wrappers or autoconverted code):
+
+* [github.com/pierrec/lz4](https://github.com/pierrec/lz4) - strong multithreaded LZ4 compression.
+* [github.com/cosnicolaou/pbzip2](https://github.com/cosnicolaou/pbzip2) - multithreaded bzip2 decompression.
+* [github.com/dsnet/compress](https://github.com/dsnet/compress) - brotli decompression, bzip2 writer.
+* [github.com/ronanh/intcomp](https://github.com/ronanh/intcomp) - Integer compression.
+* [github.com/spenczar/fpc](https://github.com/spenczar/fpc) - Float compression.
+* [github.com/minio/zipindex](https://github.com/minio/zipindex) - External ZIP directory index.
+* [github.com/ybirader/pzip](https://github.com/ybirader/pzip) - Fast concurrent zip archiver and extractor.
+
+# license
+
+This code is licensed under the same conditions as the original Go code. See LICENSE file.
+
+
+
+
+
diff --git a/vendor/github.com/klauspost/compress/SECURITY.md b/vendor/github.com/klauspost/compress/SECURITY.md
new file mode 100644
index 00000000000..ca6685e2b72
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/SECURITY.md
@@ -0,0 +1,25 @@
+# Security Policy
+
+## Supported Versions
+
+Security updates are applied only to the latest release.
+
+## Vulnerability Definition
+
+A security vulnerability is a bug that with certain input triggers a crash or an infinite loop. Most calls will have varying execution time and only in rare cases will slow operation be considered a security vulnerability.
+
+Corrupted output generally is not considered a security vulnerability, unless independent operations are able to affect each other. Note that not all functionality is re-entrant and safe to use concurrently.
+
+Out-of-memory crashes only applies if the en/decoder uses an abnormal amount of memory, with appropriate options applied, to limit maximum window size, concurrency, etc. However, if you are in doubt you are welcome to file a security issue.
+
+It is assumed that all callers are trusted, meaning internal data exposed through reflection or inspection of returned data structures is not considered a vulnerability.
+
+Vulnerabilities resulting from compiler/assembler errors should be reported upstream. Depending on the severity this package may or may not implement a workaround.
+
+## Reporting a Vulnerability
+
+If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
+
+Please disclose it at [security advisory](https://github.com/klauspost/compress/security/advisories/new). If possible please provide a minimal reproducer. If the issue only applies to a single platform, it would be helpful to provide access to that.
+
+This project is maintained by a team of volunteers on a reasonable-effort basis. As such, vulnerabilities will be disclosed in a best effort base.
diff --git a/vendor/github.com/klauspost/compress/compressible.go b/vendor/github.com/klauspost/compress/compressible.go
new file mode 100644
index 00000000000..ea5a692d513
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/compressible.go
@@ -0,0 +1,85 @@
+package compress
+
+import "math"
+
+// Estimate returns a normalized compressibility estimate of block b.
+// Values close to zero are likely uncompressible.
+// Values above 0.1 are likely to be compressible.
+// Values above 0.5 are very compressible.
+// Very small lengths will return 0.
+func Estimate(b []byte) float64 {
+ if len(b) < 16 {
+ return 0
+ }
+
+ // Correctly predicted order 1
+ hits := 0
+ lastMatch := false
+ var o1 [256]byte
+ var hist [256]int
+ c1 := byte(0)
+ for _, c := range b {
+ if c == o1[c1] {
+ // We only count a hit if there was two correct predictions in a row.
+ if lastMatch {
+ hits++
+ }
+ lastMatch = true
+ } else {
+ lastMatch = false
+ }
+ o1[c1] = c
+ c1 = c
+ hist[c]++
+ }
+
+ // Use x^0.6 to give better spread
+ prediction := math.Pow(float64(hits)/float64(len(b)), 0.6)
+
+ // Calculate histogram distribution
+ variance := float64(0)
+ avg := float64(len(b)) / 256
+
+ for _, v := range hist {
+ Δ := float64(v) - avg
+ variance += Δ * Δ
+ }
+
+ stddev := math.Sqrt(float64(variance)) / float64(len(b))
+ exp := math.Sqrt(1 / float64(len(b)))
+
+ // Subtract expected stddev
+ stddev -= exp
+ if stddev < 0 {
+ stddev = 0
+ }
+ stddev *= 1 + exp
+
+ // Use x^0.4 to give better spread
+ entropy := math.Pow(stddev, 0.4)
+
+ // 50/50 weight between prediction and histogram distribution
+ return math.Pow((prediction+entropy)/2, 0.9)
+}
+
+// ShannonEntropyBits returns the number of bits minimum required to represent
+// an entropy encoding of the input bytes.
+// https://en.wiktionary.org/wiki/Shannon_entropy
+func ShannonEntropyBits(b []byte) int {
+ if len(b) == 0 {
+ return 0
+ }
+ var hist [256]int
+ for _, c := range b {
+ hist[c]++
+ }
+ shannon := float64(0)
+ invTotal := 1.0 / float64(len(b))
+ for _, v := range hist[:] {
+ if v > 0 {
+ n := float64(v)
+ shannon += math.Ceil(-math.Log2(n*invTotal) * n)
+ }
+ }
+ return int(math.Ceil(shannon))
+}
diff --git a/vendor/github.com/klauspost/compress/fse/README.md b/vendor/github.com/klauspost/compress/fse/README.md
new file mode 100644
index 00000000000..27d8ed56fcc
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/fse/README.md
@@ -0,0 +1,79 @@
+# Finite State Entropy
+
+This package provides Finite State Entropy encoding and decoding.
+
+Finite State Entropy (also referenced as [tANS](https://en.wikipedia.org/wiki/Asymmetric_numeral_systems#tANS))
+encoding provides a fast near-optimal symbol encoding/decoding
+for byte blocks as implemented in [zstandard](https://github.com/facebook/zstd).
+
+This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
+This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
+but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
+
+* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/fse)
+
+## News
+
+ * Feb 2018: First implementation released. Consider this beta software for now.
+
+# Usage
+
+This package provides a low level interface that allows to compress single independent blocks.
+
+Each block is separate, and there is no built in integrity checks.
+This means that the caller should keep track of block sizes and also do checksums if needed.
+
+Compressing a block is done via the [`Compress`](https://godoc.org/github.com/klauspost/compress/fse#Compress) function.
+You must provide input and will receive the output and maybe an error.
+
+These error values can be returned:
+
+| Error | Description |
+|---------------------|-----------------------------------------------------------------------------|
+| `` | Everything ok, output is returned |
+| `ErrIncompressible` | Returned when input is judged to be too hard to compress |
+| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated |
+| `(error)` | An internal error occurred. |
+
+As can be seen above there are errors that will be returned even under normal operation so it is important to handle these.
+
+To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/fse#Scratch) object
+that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same
+object can be used for both.
+
+Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
+you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.
+
+Decompressing is done by calling the [`Decompress`](https://godoc.org/github.com/klauspost/compress/fse#Decompress) function.
+You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
+your input was likely corrupted.
+
+It is important to note that a successful decoding does *not* mean your output matches your original input.
+There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
+
+For more detailed usage, see examples in the [godoc documentation](https://godoc.org/github.com/klauspost/compress/fse#pkg-examples).
+
+# Performance
+
+A lot of factors are affecting speed. Block sizes and compressibility of the material are primary factors.
+All compression functions are currently only running on the calling goroutine so only one core will be used per block.
+
+The compressor is significantly faster if symbols are kept as small as possible. The highest byte value of the input
+is used to reduce some of the processing, so if all your input is above byte value 64 for instance, it may be
+beneficial to transpose all your input values down by 64.
+
+With moderate block sizes around 64k speed are typically 200MB/s per core for compression and
+around 300MB/s decompression speed.
+
+The same hardware typically does Huffman (deflate) encoding at 125MB/s and decompression at 100MB/s.
+
+# Plans
+
+At one point, more internals will be exposed to facilitate more "expert" usage of the components.
+
+A streaming interface is also likely to be implemented. Likely compatible with [FSE stream format](https://github.com/Cyan4973/FiniteStateEntropy/blob/dev/programs/fileio.c#L261).
+
+# Contributing
+
+Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
+changes will likely not be accepted. If in doubt open an issue before writing the PR.
\ No newline at end of file
diff --git a/vendor/github.com/klauspost/compress/fse/bitreader.go b/vendor/github.com/klauspost/compress/fse/bitreader.go
new file mode 100644
index 00000000000..f65eb3909cf
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/fse/bitreader.go
@@ -0,0 +1,122 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package fse
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+)
+
+// bitReader reads a bitstream in reverse.
+// The last set bit indicates the start of the stream and is used
+// for aligning the input.
+type bitReader struct {
+ in []byte
+ off uint // next byte to read is at in[off - 1]
+ value uint64
+ bitsRead uint8
+}
+
+// init initializes and resets the bit reader.
+func (b *bitReader) init(in []byte) error {
+ if len(in) < 1 {
+ return errors.New("corrupt stream: too short")
+ }
+ b.in = in
+ b.off = uint(len(in))
+ // The highest bit of the last byte indicates where to start
+ v := in[len(in)-1]
+ if v == 0 {
+ return errors.New("corrupt stream, did not find end of stream")
+ }
+ b.bitsRead = 64
+ b.value = 0
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
+ b.bitsRead += 8 - uint8(highBits(uint32(v)))
+ return nil
+}
+
+// getBits will return n bits. n can be 0.
+func (b *bitReader) getBits(n uint8) uint16 {
+ if n == 0 || b.bitsRead >= 64 {
+ return 0
+ }
+ return b.getBitsFast(n)
+}
+
+// getBitsFast requires that at least one bit is requested every time.
+// There are no checks if the buffer is filled.
+func (b *bitReader) getBitsFast(n uint8) uint16 {
+ const regMask = 64 - 1
+ v := uint16((b.value << (b.bitsRead & regMask)) >> ((regMask + 1 - n) & regMask))
+ b.bitsRead += n
+ return v
+}
+
+// fillFast() will make sure at least 32 bits are available.
+// There must be at least 4 bytes available.
+func (b *bitReader) fillFast() {
+ if b.bitsRead < 32 {
+ return
+ }
+ // 2 bounds checks.
+ v := b.in[b.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ b.value = (b.value << 32) | uint64(low)
+ b.bitsRead -= 32
+ b.off -= 4
+}
+
+// fill() will make sure at least 32 bits are available.
+func (b *bitReader) fill() {
+ if b.bitsRead < 32 {
+ return
+ }
+ if b.off > 4 {
+ v := b.in[b.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ b.value = (b.value << 32) | uint64(low)
+ b.bitsRead -= 32
+ b.off -= 4
+ return
+ }
+ for b.off > 0 {
+ b.value = (b.value << 8) | uint64(b.in[b.off-1])
+ b.bitsRead -= 8
+ b.off--
+ }
+}
+
+// fillFastStart() assumes the bitreader is empty and there is at least 8 bytes to read.
+func (b *bitReader) fillFastStart() {
+ // Do single re-slice to avoid bounds checks.
+ b.value = binary.LittleEndian.Uint64(b.in[b.off-8:])
+ b.bitsRead = 0
+ b.off -= 8
+}
+
+// finished returns true if all bits have been read from the bit stream.
+func (b *bitReader) finished() bool {
+ return b.bitsRead >= 64 && b.off == 0
+}
+
+// close the bitstream and returns an error if out-of-buffer reads occurred.
+func (b *bitReader) close() error {
+ // Release reference.
+ b.in = nil
+ if b.bitsRead > 64 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/fse/bitwriter.go b/vendor/github.com/klauspost/compress/fse/bitwriter.go
new file mode 100644
index 00000000000..d58b3fe4237
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/fse/bitwriter.go
@@ -0,0 +1,167 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package fse
+
+import "fmt"
+
+// bitWriter will write bits.
+// First bit will be LSB of the first byte of output.
+type bitWriter struct {
+ bitContainer uint64
+ nBits uint8
+ out []byte
+}
+
+// bitMask16 is bitmasks. Has extra to avoid bounds check.
+var bitMask16 = [32]uint16{
+ 0, 1, 3, 7, 0xF, 0x1F,
+ 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,
+ 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0xFFFF} /* up to 16 bits */
+
+// addBits16NC will add up to 16 bits.
+// It will not check if there is space for them,
+// so the caller must ensure that it has flushed recently.
+func (b *bitWriter) addBits16NC(value uint16, bits uint8) {
+ b.bitContainer |= uint64(value&bitMask16[bits&31]) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated.
+// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
+func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
+ b.bitContainer |= uint64(value) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// addBits16ZeroNC will add up to 16 bits.
+// It will not check if there is space for them,
+// so the caller must ensure that it has flushed recently.
+// This is fastest if bits can be zero.
+func (b *bitWriter) addBits16ZeroNC(value uint16, bits uint8) {
+ if bits == 0 {
+ return
+ }
+ value <<= (16 - bits) & 15
+ value >>= (16 - bits) & 15
+ b.bitContainer |= uint64(value) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// flush will flush all pending full bytes.
+// There will be at least 56 bits available for writing when this has been called.
+// Using flush32 is faster, but leaves less space for writing.
+func (b *bitWriter) flush() {
+ v := b.nBits >> 3
+ switch v {
+ case 0:
+ case 1:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ )
+ case 2:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ )
+ case 3:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ )
+ case 4:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24),
+ )
+ case 5:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24),
+ byte(b.bitContainer>>32),
+ )
+ case 6:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24),
+ byte(b.bitContainer>>32),
+ byte(b.bitContainer>>40),
+ )
+ case 7:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24),
+ byte(b.bitContainer>>32),
+ byte(b.bitContainer>>40),
+ byte(b.bitContainer>>48),
+ )
+ case 8:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24),
+ byte(b.bitContainer>>32),
+ byte(b.bitContainer>>40),
+ byte(b.bitContainer>>48),
+ byte(b.bitContainer>>56),
+ )
+ default:
+ panic(fmt.Errorf("bits (%d) > 64", b.nBits))
+ }
+ b.bitContainer >>= v << 3
+ b.nBits &= 7
+}
+
+// flush32 will flush out, so there are at least 32 bits available for writing.
+func (b *bitWriter) flush32() {
+ if b.nBits < 32 {
+ return
+ }
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24))
+ b.nBits -= 32
+ b.bitContainer >>= 32
+}
+
+// flushAlign will flush remaining full bytes and align to next byte boundary.
+func (b *bitWriter) flushAlign() {
+ nbBytes := (b.nBits + 7) >> 3
+ for i := range nbBytes {
+ b.out = append(b.out, byte(b.bitContainer>>(i*8)))
+ }
+ b.nBits = 0
+ b.bitContainer = 0
+}
+
+// close will write the alignment bit and write the final byte(s)
+// to the output.
+func (b *bitWriter) close() {
+ // End mark
+ b.addBits16Clean(1, 1)
+ // flush until next byte.
+ b.flushAlign()
+}
+
+// reset and continue writing by appending to out.
+func (b *bitWriter) reset(out []byte) {
+ b.bitContainer = 0
+ b.nBits = 0
+ b.out = out
+}
diff --git a/vendor/github.com/klauspost/compress/fse/bytereader.go b/vendor/github.com/klauspost/compress/fse/bytereader.go
new file mode 100644
index 00000000000..abade2d6052
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/fse/bytereader.go
@@ -0,0 +1,47 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package fse
+
+// byteReader provides a byte reader that reads
+// little endian values from a byte stream.
+// The input stream is manually advanced.
+// The reader performs no bounds checks.
+type byteReader struct {
+ b []byte
+ off int
+}
+
+// init will initialize the reader and set the input.
+func (b *byteReader) init(in []byte) {
+ b.b = in
+ b.off = 0
+}
+
+// advance the stream b n bytes.
+func (b *byteReader) advance(n uint) {
+ b.off += int(n)
+}
+
+// Uint32 returns a little endian uint32 starting at current offset.
+func (b byteReader) Uint32() uint32 {
+ b2 := b.b[b.off:]
+ b2 = b2[:4]
+ v3 := uint32(b2[3])
+ v2 := uint32(b2[2])
+ v1 := uint32(b2[1])
+ v0 := uint32(b2[0])
+ return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24)
+}
+
+// unread returns the unread portion of the input.
+func (b byteReader) unread() []byte {
+ return b.b[b.off:]
+}
+
+// remain will return the number of bytes remaining.
+func (b byteReader) remain() int {
+ return len(b.b) - b.off
+}
diff --git a/vendor/github.com/klauspost/compress/fse/compress.go b/vendor/github.com/klauspost/compress/fse/compress.go
new file mode 100644
index 00000000000..8c8baa4fc2c
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/fse/compress.go
@@ -0,0 +1,683 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package fse
+
+import (
+ "errors"
+ "fmt"
+)
+
+// Compress the input bytes. Input must be < 2GB.
+// Provide a Scratch buffer to avoid memory allocations.
+// Note that the output is also kept in the scratch buffer.
+// If input is too hard to compress, ErrIncompressible is returned.
+// If input is a single byte value repeated ErrUseRLE is returned.
+func Compress(in []byte, s *Scratch) ([]byte, error) {
+ if len(in) <= 1 {
+ return nil, ErrIncompressible
+ }
+ if len(in) > (2<<30)-1 {
+ return nil, errors.New("input too big, must be < 2GB")
+ }
+ s, err := s.prepare(in)
+ if err != nil {
+ return nil, err
+ }
+
+ // Create histogram, if none was provided.
+ maxCount := s.maxCount
+ if maxCount == 0 {
+ maxCount = s.countSimple(in)
+ }
+ // Reset for next run.
+ s.clearCount = true
+ s.maxCount = 0
+ if maxCount == len(in) {
+ // One symbol, use RLE
+ return nil, ErrUseRLE
+ }
+ if maxCount == 1 || maxCount < (len(in)>>7) {
+ // Each symbol present maximum once or too well distributed.
+ return nil, ErrIncompressible
+ }
+ s.optimalTableLog()
+ err = s.normalizeCount()
+ if err != nil {
+ return nil, err
+ }
+ err = s.writeCount()
+ if err != nil {
+ return nil, err
+ }
+
+ if false {
+ err = s.validateNorm()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ err = s.buildCTable()
+ if err != nil {
+ return nil, err
+ }
+ err = s.compress(in)
+ if err != nil {
+ return nil, err
+ }
+ s.Out = s.bw.out
+ // Check if we compressed.
+ if len(s.Out) >= len(in) {
+ return nil, ErrIncompressible
+ }
+ return s.Out, nil
+}
+
+// cState contains the compression state of a stream.
+type cState struct {
+ bw *bitWriter
+ stateTable []uint16
+ state uint16
+}
+
+// init will initialize the compression state to the first symbol of the stream.
+func (c *cState) init(bw *bitWriter, ct *cTable, tableLog uint8, first symbolTransform) {
+ c.bw = bw
+ c.stateTable = ct.stateTable
+
+ nbBitsOut := (first.deltaNbBits + (1 << 15)) >> 16
+ im := int32((nbBitsOut << 16) - first.deltaNbBits)
+ lu := (im >> nbBitsOut) + first.deltaFindState
+ c.state = c.stateTable[lu]
+}
+
+// encode the output symbol provided and write it to the bitstream.
+func (c *cState) encode(symbolTT symbolTransform) {
+ nbBitsOut := (uint32(c.state) + symbolTT.deltaNbBits) >> 16
+ dstState := int32(c.state>>(nbBitsOut&15)) + symbolTT.deltaFindState
+ c.bw.addBits16NC(c.state, uint8(nbBitsOut))
+ c.state = c.stateTable[dstState]
+}
+
+// encode the output symbol provided and write it to the bitstream.
+func (c *cState) encodeZero(symbolTT symbolTransform) {
+ nbBitsOut := (uint32(c.state) + symbolTT.deltaNbBits) >> 16
+ dstState := int32(c.state>>(nbBitsOut&15)) + symbolTT.deltaFindState
+ c.bw.addBits16ZeroNC(c.state, uint8(nbBitsOut))
+ c.state = c.stateTable[dstState]
+}
+
+// flush will write the tablelog to the output and flush the remaining full bytes.
+func (c *cState) flush(tableLog uint8) {
+ c.bw.flush32()
+ c.bw.addBits16NC(c.state, tableLog)
+ c.bw.flush()
+}
+
+// compress is the main compression loop that will encode the input from the last byte to the first.
+func (s *Scratch) compress(src []byte) error {
+ if len(src) <= 2 {
+ return errors.New("compress: src too small")
+ }
+ tt := s.ct.symbolTT[:256]
+ s.bw.reset(s.Out)
+
+ // Our two states each encodes every second byte.
+ // Last byte encoded (first byte decoded) will always be encoded by c1.
+ var c1, c2 cState
+
+ // Encode so remaining size is divisible by 4.
+ ip := len(src)
+ if ip&1 == 1 {
+ c1.init(&s.bw, &s.ct, s.actualTableLog, tt[src[ip-1]])
+ c2.init(&s.bw, &s.ct, s.actualTableLog, tt[src[ip-2]])
+ c1.encodeZero(tt[src[ip-3]])
+ ip -= 3
+ } else {
+ c2.init(&s.bw, &s.ct, s.actualTableLog, tt[src[ip-1]])
+ c1.init(&s.bw, &s.ct, s.actualTableLog, tt[src[ip-2]])
+ ip -= 2
+ }
+ if ip&2 != 0 {
+ c2.encodeZero(tt[src[ip-1]])
+ c1.encodeZero(tt[src[ip-2]])
+ ip -= 2
+ }
+ src = src[:ip]
+
+ // Main compression loop.
+ switch {
+ case !s.zeroBits && s.actualTableLog <= 8:
+ // We can encode 4 symbols without requiring a flush.
+ // We do not need to check if any output is 0 bits.
+ for ; len(src) >= 4; src = src[:len(src)-4] {
+ s.bw.flush32()
+ v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1]
+ c2.encode(tt[v0])
+ c1.encode(tt[v1])
+ c2.encode(tt[v2])
+ c1.encode(tt[v3])
+ }
+ case !s.zeroBits:
+ // We do not need to check if any output is 0 bits.
+ for ; len(src) >= 4; src = src[:len(src)-4] {
+ s.bw.flush32()
+ v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1]
+ c2.encode(tt[v0])
+ c1.encode(tt[v1])
+ s.bw.flush32()
+ c2.encode(tt[v2])
+ c1.encode(tt[v3])
+ }
+ case s.actualTableLog <= 8:
+ // We can encode 4 symbols without requiring a flush
+ for ; len(src) >= 4; src = src[:len(src)-4] {
+ s.bw.flush32()
+ v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1]
+ c2.encodeZero(tt[v0])
+ c1.encodeZero(tt[v1])
+ c2.encodeZero(tt[v2])
+ c1.encodeZero(tt[v3])
+ }
+ default:
+ for ; len(src) >= 4; src = src[:len(src)-4] {
+ s.bw.flush32()
+ v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1]
+ c2.encodeZero(tt[v0])
+ c1.encodeZero(tt[v1])
+ s.bw.flush32()
+ c2.encodeZero(tt[v2])
+ c1.encodeZero(tt[v3])
+ }
+ }
+
+ // Flush final state.
+ // Used to initialize state when decoding.
+ c2.flush(s.actualTableLog)
+ c1.flush(s.actualTableLog)
+
+ s.bw.close()
+ return nil
+}
+
+// writeCount will write the normalized histogram count to header.
+// This is read back by readNCount.
+func (s *Scratch) writeCount() error {
+ var (
+ tableLog = s.actualTableLog
+ tableSize = 1 << tableLog
+ previous0 bool
+ charnum uint16
+
+ maxHeaderSize = ((int(s.symbolLen)*int(tableLog) + 4 + 2) >> 3) + 3
+
+ // Write Table Size
+ bitStream = uint32(tableLog - minTablelog)
+ bitCount = uint(4)
+ remaining = int16(tableSize + 1) /* +1 for extra accuracy */
+ threshold = int16(tableSize)
+ nbBits = uint(tableLog + 1)
+ )
+ if cap(s.Out) < maxHeaderSize {
+ s.Out = make([]byte, 0, s.br.remain()+maxHeaderSize)
+ }
+ outP := uint(0)
+ out := s.Out[:maxHeaderSize]
+
+ // stops at 1
+ for remaining > 1 {
+ if previous0 {
+ start := charnum
+ for s.norm[charnum] == 0 {
+ charnum++
+ }
+ for charnum >= start+24 {
+ start += 24
+ bitStream += uint32(0xFFFF) << bitCount
+ out[outP] = byte(bitStream)
+ out[outP+1] = byte(bitStream >> 8)
+ outP += 2
+ bitStream >>= 16
+ }
+ for charnum >= start+3 {
+ start += 3
+ bitStream += 3 << bitCount
+ bitCount += 2
+ }
+ bitStream += uint32(charnum-start) << bitCount
+ bitCount += 2
+ if bitCount > 16 {
+ out[outP] = byte(bitStream)
+ out[outP+1] = byte(bitStream >> 8)
+ outP += 2
+ bitStream >>= 16
+ bitCount -= 16
+ }
+ }
+
+ count := s.norm[charnum]
+ charnum++
+ max := (2*threshold - 1) - remaining
+ if count < 0 {
+ remaining += count
+ } else {
+ remaining -= count
+ }
+ count++ // +1 for extra accuracy
+ if count >= threshold {
+ count += max // [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[
+ }
+ bitStream += uint32(count) << bitCount
+ bitCount += nbBits
+ if count < max {
+ bitCount--
+ }
+
+ previous0 = count == 1
+ if remaining < 1 {
+ return errors.New("internal error: remaining<1")
+ }
+ for remaining < threshold {
+ nbBits--
+ threshold >>= 1
+ }
+
+ if bitCount > 16 {
+ out[outP] = byte(bitStream)
+ out[outP+1] = byte(bitStream >> 8)
+ outP += 2
+ bitStream >>= 16
+ bitCount -= 16
+ }
+ }
+
+ out[outP] = byte(bitStream)
+ out[outP+1] = byte(bitStream >> 8)
+ outP += (bitCount + 7) / 8
+
+ if charnum > s.symbolLen {
+ return errors.New("internal error: charnum > s.symbolLen")
+ }
+ s.Out = out[:outP]
+ return nil
+}
+
+// symbolTransform contains the state transform for a symbol.
+type symbolTransform struct {
+ deltaFindState int32
+ deltaNbBits uint32
+}
+
+// String prints values as a human readable string.
+func (s symbolTransform) String() string {
+ return fmt.Sprintf("dnbits: %08x, fs:%d", s.deltaNbBits, s.deltaFindState)
+}
+
+// cTable contains tables used for compression.
+type cTable struct {
+ tableSymbol []byte
+ stateTable []uint16
+ symbolTT []symbolTransform
+}
+
+// allocCtable will allocate tables needed for compression.
+// If existing tables a re big enough, they are simply re-used.
+func (s *Scratch) allocCtable() {
+ tableSize := 1 << s.actualTableLog
+ // get tableSymbol that is big enough.
+ if cap(s.ct.tableSymbol) < tableSize {
+ s.ct.tableSymbol = make([]byte, tableSize)
+ }
+ s.ct.tableSymbol = s.ct.tableSymbol[:tableSize]
+
+ ctSize := tableSize
+ if cap(s.ct.stateTable) < ctSize {
+ s.ct.stateTable = make([]uint16, ctSize)
+ }
+ s.ct.stateTable = s.ct.stateTable[:ctSize]
+
+ if cap(s.ct.symbolTT) < 256 {
+ s.ct.symbolTT = make([]symbolTransform, 256)
+ }
+ s.ct.symbolTT = s.ct.symbolTT[:256]
+}
+
+// buildCTable will populate the compression table so it is ready to be used.
+func (s *Scratch) buildCTable() error {
+ tableSize := uint32(1 << s.actualTableLog)
+ highThreshold := tableSize - 1
+ var cumul [maxSymbolValue + 2]int16
+
+ s.allocCtable()
+ tableSymbol := s.ct.tableSymbol[:tableSize]
+ // symbol start positions
+ {
+ cumul[0] = 0
+ for ui, v := range s.norm[:s.symbolLen-1] {
+ u := byte(ui) // one less than reference
+ if v == -1 {
+ // Low proba symbol
+ cumul[u+1] = cumul[u] + 1
+ tableSymbol[highThreshold] = u
+ highThreshold--
+ } else {
+ cumul[u+1] = cumul[u] + v
+ }
+ }
+ // Encode last symbol separately to avoid overflowing u
+ u := int(s.symbolLen - 1)
+ v := s.norm[s.symbolLen-1]
+ if v == -1 {
+ // Low proba symbol
+ cumul[u+1] = cumul[u] + 1
+ tableSymbol[highThreshold] = byte(u)
+ highThreshold--
+ } else {
+ cumul[u+1] = cumul[u] + v
+ }
+ if uint32(cumul[s.symbolLen]) != tableSize {
+ return fmt.Errorf("internal error: expected cumul[s.symbolLen] (%d) == tableSize (%d)", cumul[s.symbolLen], tableSize)
+ }
+ cumul[s.symbolLen] = int16(tableSize) + 1
+ }
+ // Spread symbols
+ s.zeroBits = false
+ {
+ step := tableStep(tableSize)
+ tableMask := tableSize - 1
+ var position uint32
+ // if any symbol > largeLimit, we may have 0 bits output.
+ largeLimit := int16(1 << (s.actualTableLog - 1))
+ for ui, v := range s.norm[:s.symbolLen] {
+ symbol := byte(ui)
+ if v > largeLimit {
+ s.zeroBits = true
+ }
+ for range v {
+ tableSymbol[position] = symbol
+ position = (position + step) & tableMask
+ for position > highThreshold {
+ position = (position + step) & tableMask
+ } /* Low proba area */
+ }
+ }
+
+ // Check if we have gone through all positions
+ if position != 0 {
+ return errors.New("position!=0")
+ }
+ }
+
+ // Build table
+ table := s.ct.stateTable
+ {
+ tsi := int(tableSize)
+ for u, v := range tableSymbol {
+ // TableU16 : sorted by symbol order; gives next state value
+ table[cumul[v]] = uint16(tsi + u)
+ cumul[v]++
+ }
+ }
+
+ // Build Symbol Transformation Table
+ {
+ total := int16(0)
+ symbolTT := s.ct.symbolTT[:s.symbolLen]
+ tableLog := s.actualTableLog
+ tl := (uint32(tableLog) << 16) - (1 << tableLog)
+ for i, v := range s.norm[:s.symbolLen] {
+ switch v {
+ case 0:
+ case -1, 1:
+ symbolTT[i].deltaNbBits = tl
+ symbolTT[i].deltaFindState = int32(total - 1)
+ total++
+ default:
+ maxBitsOut := uint32(tableLog) - highBits(uint32(v-1))
+ minStatePlus := uint32(v) << maxBitsOut
+ symbolTT[i].deltaNbBits = (maxBitsOut << 16) - minStatePlus
+ symbolTT[i].deltaFindState = int32(total - v)
+ total += v
+ }
+ }
+ if total != int16(tableSize) {
+ return fmt.Errorf("total mismatch %d (got) != %d (want)", total, tableSize)
+ }
+ }
+ return nil
+}
+
+// countSimple will create a simple histogram in s.count.
+// Returns the biggest count.
+// Does not update s.clearCount.
+func (s *Scratch) countSimple(in []byte) (max int) {
+ for _, v := range in {
+ s.count[v]++
+ }
+ m, symlen := uint32(0), s.symbolLen
+ for i, v := range s.count[:] {
+ if v == 0 {
+ continue
+ }
+ if v > m {
+ m = v
+ }
+ symlen = uint16(i) + 1
+ }
+ s.symbolLen = symlen
+ return int(m)
+}
+
+// minTableLog provides the minimum logSize to safely represent a distribution.
+func (s *Scratch) minTableLog() uint8 {
+ minBitsSrc := highBits(uint32(s.br.remain()-1)) + 1
+ minBitsSymbols := highBits(uint32(s.symbolLen-1)) + 2
+ if minBitsSrc < minBitsSymbols {
+ return uint8(minBitsSrc)
+ }
+ return uint8(minBitsSymbols)
+}
+
+// optimalTableLog calculates and sets the optimal tableLog in s.actualTableLog
+func (s *Scratch) optimalTableLog() {
+ tableLog := s.TableLog
+ minBits := s.minTableLog()
+ maxBitsSrc := uint8(highBits(uint32(s.br.remain()-1))) - 2
+ if maxBitsSrc < tableLog {
+ // Accuracy can be reduced
+ tableLog = maxBitsSrc
+ }
+ if minBits > tableLog {
+ tableLog = minBits
+ }
+ // Need a minimum to safely represent all symbol values
+ if tableLog < minTablelog {
+ tableLog = minTablelog
+ }
+ if tableLog > maxTableLog {
+ tableLog = maxTableLog
+ }
+ s.actualTableLog = tableLog
+}
+
+var rtbTable = [...]uint32{0, 473195, 504333, 520860, 550000, 700000, 750000, 830000}
+
+// normalizeCount will normalize the count of the symbols so
+// the total is equal to the table size.
+func (s *Scratch) normalizeCount() error {
+ var (
+ tableLog = s.actualTableLog
+ scale = 62 - uint64(tableLog)
+ step = (1 << 62) / uint64(s.br.remain())
+ vStep = uint64(1) << (scale - 20)
+ stillToDistribute = int16(1 << tableLog)
+ largest int
+ largestP int16
+ lowThreshold = (uint32)(s.br.remain() >> tableLog)
+ )
+
+ for i, cnt := range s.count[:s.symbolLen] {
+ // already handled
+ // if (count[s] == s.length) return 0; /* rle special case */
+
+ if cnt == 0 {
+ s.norm[i] = 0
+ continue
+ }
+ if cnt <= lowThreshold {
+ s.norm[i] = -1
+ stillToDistribute--
+ } else {
+ proba := (int16)((uint64(cnt) * step) >> scale)
+ if proba < 8 {
+ restToBeat := vStep * uint64(rtbTable[proba])
+ v := uint64(cnt)*step - (uint64(proba) << scale)
+ if v > restToBeat {
+ proba++
+ }
+ }
+ if proba > largestP {
+ largestP = proba
+ largest = i
+ }
+ s.norm[i] = proba
+ stillToDistribute -= proba
+ }
+ }
+
+ if -stillToDistribute >= (s.norm[largest] >> 1) {
+ // corner case, need another normalization method
+ return s.normalizeCount2()
+ }
+ s.norm[largest] += stillToDistribute
+ return nil
+}
+
+// Secondary normalization method.
+// To be used when primary method fails.
+func (s *Scratch) normalizeCount2() error {
+ const notYetAssigned = -2
+ var (
+ distributed uint32
+ total = uint32(s.br.remain())
+ tableLog = s.actualTableLog
+ lowThreshold = total >> tableLog
+ lowOne = (total * 3) >> (tableLog + 1)
+ )
+ for i, cnt := range s.count[:s.symbolLen] {
+ if cnt == 0 {
+ s.norm[i] = 0
+ continue
+ }
+ if cnt <= lowThreshold {
+ s.norm[i] = -1
+ distributed++
+ total -= cnt
+ continue
+ }
+ if cnt <= lowOne {
+ s.norm[i] = 1
+ distributed++
+ total -= cnt
+ continue
+ }
+ s.norm[i] = notYetAssigned
+ }
+ toDistribute := (1 << tableLog) - distributed
+
+ if (total / toDistribute) > lowOne {
+ // risk of rounding to zero
+ lowOne = (total * 3) / (toDistribute * 2)
+ for i, cnt := range s.count[:s.symbolLen] {
+ if (s.norm[i] == notYetAssigned) && (cnt <= lowOne) {
+ s.norm[i] = 1
+ distributed++
+ total -= cnt
+ continue
+ }
+ }
+ toDistribute = (1 << tableLog) - distributed
+ }
+ if distributed == uint32(s.symbolLen)+1 {
+ // all values are pretty poor;
+ // probably incompressible data (should have already been detected);
+ // find max, then give all remaining points to max
+ var maxV int
+ var maxC uint32
+ for i, cnt := range s.count[:s.symbolLen] {
+ if cnt > maxC {
+ maxV = i
+ maxC = cnt
+ }
+ }
+ s.norm[maxV] += int16(toDistribute)
+ return nil
+ }
+
+ if total == 0 {
+ // all of the symbols were low enough for the lowOne or lowThreshold
+ for i := uint32(0); toDistribute > 0; i = (i + 1) % (uint32(s.symbolLen)) {
+ if s.norm[i] > 0 {
+ toDistribute--
+ s.norm[i]++
+ }
+ }
+ return nil
+ }
+
+ var (
+ vStepLog = 62 - uint64(tableLog)
+ mid = uint64((1 << (vStepLog - 1)) - 1)
+ rStep = (((1 << vStepLog) * uint64(toDistribute)) + mid) / uint64(total) // scale on remaining
+ tmpTotal = mid
+ )
+ for i, cnt := range s.count[:s.symbolLen] {
+ if s.norm[i] == notYetAssigned {
+ var (
+ end = tmpTotal + uint64(cnt)*rStep
+ sStart = uint32(tmpTotal >> vStepLog)
+ sEnd = uint32(end >> vStepLog)
+ weight = sEnd - sStart
+ )
+ if weight < 1 {
+ return errors.New("weight < 1")
+ }
+ s.norm[i] = int16(weight)
+ tmpTotal = end
+ }
+ }
+ return nil
+}
+
+// validateNorm validates the normalized histogram table.
+func (s *Scratch) validateNorm() (err error) {
+ var total int
+ for _, v := range s.norm[:s.symbolLen] {
+ if v >= 0 {
+ total += int(v)
+ } else {
+ total -= int(v)
+ }
+ }
+ defer func() {
+ if err == nil {
+ return
+ }
+ fmt.Printf("selected TableLog: %d, Symbol length: %d\n", s.actualTableLog, s.symbolLen)
+ for i, v := range s.norm[:s.symbolLen] {
+ fmt.Printf("%3d: %5d -> %4d \n", i, s.count[i], v)
+ }
+ }()
+ if total != (1 << s.actualTableLog) {
+ return fmt.Errorf("warning: Total == %d != %d", total, 1< tablelogAbsoluteMax {
+ return errors.New("tableLog too large")
+ }
+ bitStream >>= 4
+ bitCount := uint(4)
+
+ s.actualTableLog = uint8(nbBits)
+ remaining := int32((1 << nbBits) + 1)
+ threshold := int32(1 << nbBits)
+ gotTotal := int32(0)
+ nbBits++
+
+ for remaining > 1 {
+ if previous0 {
+ n0 := charnum
+ for (bitStream & 0xFFFF) == 0xFFFF {
+ n0 += 24
+ if b.off < iend-5 {
+ b.advance(2)
+ bitStream = b.Uint32() >> bitCount
+ } else {
+ bitStream >>= 16
+ bitCount += 16
+ }
+ }
+ for (bitStream & 3) == 3 {
+ n0 += 3
+ bitStream >>= 2
+ bitCount += 2
+ }
+ n0 += uint16(bitStream & 3)
+ bitCount += 2
+ if n0 > maxSymbolValue {
+ return errors.New("maxSymbolValue too small")
+ }
+ for charnum < n0 {
+ s.norm[charnum&0xff] = 0
+ charnum++
+ }
+
+ if b.off <= iend-7 || b.off+int(bitCount>>3) <= iend-4 {
+ b.advance(bitCount >> 3)
+ bitCount &= 7
+ bitStream = b.Uint32() >> bitCount
+ } else {
+ bitStream >>= 2
+ }
+ }
+
+ max := (2*(threshold) - 1) - (remaining)
+ var count int32
+
+ if (int32(bitStream) & (threshold - 1)) < max {
+ count = int32(bitStream) & (threshold - 1)
+ bitCount += nbBits - 1
+ } else {
+ count = int32(bitStream) & (2*threshold - 1)
+ if count >= threshold {
+ count -= max
+ }
+ bitCount += nbBits
+ }
+
+ count-- // extra accuracy
+ if count < 0 {
+ // -1 means +1
+ remaining += count
+ gotTotal -= count
+ } else {
+ remaining -= count
+ gotTotal += count
+ }
+ s.norm[charnum&0xff] = int16(count)
+ charnum++
+ previous0 = count == 0
+ for remaining < threshold {
+ nbBits--
+ threshold >>= 1
+ }
+ if b.off <= iend-7 || b.off+int(bitCount>>3) <= iend-4 {
+ b.advance(bitCount >> 3)
+ bitCount &= 7
+ } else {
+ bitCount -= (uint)(8 * (len(b.b) - 4 - b.off))
+ b.off = len(b.b) - 4
+ }
+ bitStream = b.Uint32() >> (bitCount & 31)
+ }
+ s.symbolLen = charnum
+
+ if s.symbolLen <= 1 {
+ return fmt.Errorf("symbolLen (%d) too small", s.symbolLen)
+ }
+ if s.symbolLen > maxSymbolValue+1 {
+ return fmt.Errorf("symbolLen (%d) too big", s.symbolLen)
+ }
+ if remaining != 1 {
+ return fmt.Errorf("corruption detected (remaining %d != 1)", remaining)
+ }
+ if bitCount > 32 {
+ return fmt.Errorf("corruption detected (bitCount %d > 32)", bitCount)
+ }
+ if gotTotal != 1<> 3)
+ return nil
+}
+
+// decSymbol contains information about a state entry,
+// Including the state offset base, the output symbol and
+// the number of bits to read for the low part of the destination state.
+type decSymbol struct {
+ newState uint16
+ symbol uint8
+ nbBits uint8
+}
+
+// allocDtable will allocate decoding tables if they are not big enough.
+func (s *Scratch) allocDtable() {
+ tableSize := 1 << s.actualTableLog
+ if cap(s.decTable) < tableSize {
+ s.decTable = make([]decSymbol, tableSize)
+ }
+ s.decTable = s.decTable[:tableSize]
+
+ if cap(s.ct.tableSymbol) < 256 {
+ s.ct.tableSymbol = make([]byte, 256)
+ }
+ s.ct.tableSymbol = s.ct.tableSymbol[:256]
+
+ if cap(s.ct.stateTable) < 256 {
+ s.ct.stateTable = make([]uint16, 256)
+ }
+ s.ct.stateTable = s.ct.stateTable[:256]
+}
+
+// buildDtable will build the decoding table.
+func (s *Scratch) buildDtable() error {
+ tableSize := uint32(1 << s.actualTableLog)
+ highThreshold := tableSize - 1
+ s.allocDtable()
+ symbolNext := s.ct.stateTable[:256]
+
+ // Init, lay down lowprob symbols
+ s.zeroBits = false
+ {
+ largeLimit := int16(1 << (s.actualTableLog - 1))
+ for i, v := range s.norm[:s.symbolLen] {
+ if v == -1 {
+ s.decTable[highThreshold].symbol = uint8(i)
+ highThreshold--
+ symbolNext[i] = 1
+ } else {
+ if v >= largeLimit {
+ s.zeroBits = true
+ }
+ symbolNext[i] = uint16(v)
+ }
+ }
+ }
+ // Spread symbols
+ {
+ tableMask := tableSize - 1
+ step := tableStep(tableSize)
+ position := uint32(0)
+ for ss, v := range s.norm[:s.symbolLen] {
+ for i := 0; i < int(v); i++ {
+ s.decTable[position].symbol = uint8(ss)
+ position = (position + step) & tableMask
+ for position > highThreshold {
+ // lowprob area
+ position = (position + step) & tableMask
+ }
+ }
+ }
+ if position != 0 {
+ // position must reach all cells once, otherwise normalizedCounter is incorrect
+ return errors.New("corrupted input (position != 0)")
+ }
+ }
+
+ // Build Decoding table
+ {
+ tableSize := uint16(1 << s.actualTableLog)
+ for u, v := range s.decTable {
+ symbol := v.symbol
+ nextState := symbolNext[symbol]
+ symbolNext[symbol] = nextState + 1
+ nBits := s.actualTableLog - byte(highBits(uint32(nextState)))
+ s.decTable[u].nbBits = nBits
+ newState := (nextState << nBits) - tableSize
+ if newState >= tableSize {
+ return fmt.Errorf("newState (%d) outside table size (%d)", newState, tableSize)
+ }
+ if newState == uint16(u) && nBits == 0 {
+ // Seems weird that this is possible with nbits > 0.
+ return fmt.Errorf("newState (%d) == oldState (%d) and no bits", newState, u)
+ }
+ s.decTable[u].newState = newState
+ }
+ }
+ return nil
+}
+
+// decompress will decompress the bitstream.
+// If the buffer is over-read an error is returned.
+func (s *Scratch) decompress() error {
+ br := &s.bits
+ if err := br.init(s.br.unread()); err != nil {
+ return err
+ }
+
+ var s1, s2 decoder
+ // Initialize and decode first state and symbol.
+ s1.init(br, s.decTable, s.actualTableLog)
+ s2.init(br, s.decTable, s.actualTableLog)
+
+ // Use temp table to avoid bound checks/append penalty.
+ var tmp = s.ct.tableSymbol[:256]
+ var off uint8
+
+ // Main part
+ if !s.zeroBits {
+ for br.off >= 8 {
+ br.fillFast()
+ tmp[off+0] = s1.nextFast()
+ tmp[off+1] = s2.nextFast()
+ br.fillFast()
+ tmp[off+2] = s1.nextFast()
+ tmp[off+3] = s2.nextFast()
+ off += 4
+ // When off is 0, we have overflowed and should write.
+ if off == 0 {
+ s.Out = append(s.Out, tmp...)
+ if len(s.Out) >= s.DecompressLimit {
+ return fmt.Errorf("output size (%d) > DecompressLimit (%d)", len(s.Out), s.DecompressLimit)
+ }
+ }
+ }
+ } else {
+ for br.off >= 8 {
+ br.fillFast()
+ tmp[off+0] = s1.next()
+ tmp[off+1] = s2.next()
+ br.fillFast()
+ tmp[off+2] = s1.next()
+ tmp[off+3] = s2.next()
+ off += 4
+ if off == 0 {
+ s.Out = append(s.Out, tmp...)
+ // When off is 0, we have overflowed and should write.
+ if len(s.Out) >= s.DecompressLimit {
+ return fmt.Errorf("output size (%d) > DecompressLimit (%d)", len(s.Out), s.DecompressLimit)
+ }
+ }
+ }
+ }
+ s.Out = append(s.Out, tmp[:off]...)
+
+ // Final bits, a bit more expensive check
+ for {
+ if s1.finished() {
+ s.Out = append(s.Out, s1.final(), s2.final())
+ break
+ }
+ br.fill()
+ s.Out = append(s.Out, s1.next())
+ if s2.finished() {
+ s.Out = append(s.Out, s2.final(), s1.final())
+ break
+ }
+ s.Out = append(s.Out, s2.next())
+ if len(s.Out) >= s.DecompressLimit {
+ return fmt.Errorf("output size (%d) > DecompressLimit (%d)", len(s.Out), s.DecompressLimit)
+ }
+ }
+ return br.close()
+}
+
+// decoder keeps track of the current state and updates it from the bitstream.
+type decoder struct {
+ state uint16
+ br *bitReader
+ dt []decSymbol
+}
+
+// init will initialize the decoder and read the first state from the stream.
+func (d *decoder) init(in *bitReader, dt []decSymbol, tableLog uint8) {
+ d.dt = dt
+ d.br = in
+ d.state = in.getBits(tableLog)
+}
+
+// next returns the next symbol and sets the next state.
+// At least tablelog bits must be available in the bit reader.
+func (d *decoder) next() uint8 {
+ n := &d.dt[d.state]
+ lowBits := d.br.getBits(n.nbBits)
+ d.state = n.newState + lowBits
+ return n.symbol
+}
+
+// finished returns true if all bits have been read from the bitstream
+// and the next state would require reading bits from the input.
+func (d *decoder) finished() bool {
+ return d.br.finished() && d.dt[d.state].nbBits > 0
+}
+
+// final returns the current state symbol without decoding the next.
+func (d *decoder) final() uint8 {
+ return d.dt[d.state].symbol
+}
+
+// nextFast returns the next symbol and sets the next state.
+// This can only be used if no symbols are 0 bits.
+// At least tablelog bits must be available in the bit reader.
+func (d *decoder) nextFast() uint8 {
+ n := d.dt[d.state]
+ lowBits := d.br.getBitsFast(n.nbBits)
+ d.state = n.newState + lowBits
+ return n.symbol
+}
diff --git a/vendor/github.com/klauspost/compress/fse/fse.go b/vendor/github.com/klauspost/compress/fse/fse.go
new file mode 100644
index 00000000000..535cbadfdea
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/fse/fse.go
@@ -0,0 +1,144 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+// Package fse provides Finite State Entropy encoding and decoding.
+//
+// Finite State Entropy encoding provides a fast near-optimal symbol encoding/decoding
+// for byte blocks as implemented in zstd.
+//
+// See https://github.com/klauspost/compress/tree/master/fse for more information.
+package fse
+
+import (
+ "errors"
+ "fmt"
+ "math/bits"
+)
+
+const (
+ /*!MEMORY_USAGE :
+ * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+ * Increasing memory usage improves compression ratio
+ * Reduced memory usage can improve speed, due to cache effect
+ * Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
+ maxMemoryUsage = 14
+ defaultMemoryUsage = 13
+
+ maxTableLog = maxMemoryUsage - 2
+ maxTablesize = 1 << maxTableLog
+ defaultTablelog = defaultMemoryUsage - 2
+ minTablelog = 5
+ maxSymbolValue = 255
+)
+
+var (
+ // ErrIncompressible is returned when input is judged to be too hard to compress.
+ ErrIncompressible = errors.New("input is not compressible")
+
+ // ErrUseRLE is returned from the compressor when the input is a single byte value repeated.
+ ErrUseRLE = errors.New("input is single value repeated")
+)
+
+// Scratch provides temporary storage for compression and decompression.
+type Scratch struct {
+ // Private
+ count [maxSymbolValue + 1]uint32
+ norm [maxSymbolValue + 1]int16
+ br byteReader
+ bits bitReader
+ bw bitWriter
+ ct cTable // Compression tables.
+ decTable []decSymbol // Decompression table.
+ maxCount int // count of the most probable symbol
+
+ // Per block parameters.
+ // These can be used to override compression parameters of the block.
+ // Do not touch, unless you know what you are doing.
+
+ // Out is output buffer.
+ // If the scratch is re-used before the caller is done processing the output,
+ // set this field to nil.
+ // Otherwise the output buffer will be re-used for next Compression/Decompression step
+ // and allocation will be avoided.
+ Out []byte
+
+ // DecompressLimit limits the maximum decoded size acceptable.
+ // If > 0 decompression will stop when approximately this many bytes
+ // has been decoded.
+ // If 0, maximum size will be 2GB.
+ DecompressLimit int
+
+ symbolLen uint16 // Length of active part of the symbol table.
+ actualTableLog uint8 // Selected tablelog.
+ zeroBits bool // no bits has prob > 50%.
+ clearCount bool // clear count
+
+ // MaxSymbolValue will override the maximum symbol value of the next block.
+ MaxSymbolValue uint8
+
+ // TableLog will attempt to override the tablelog for the next block.
+ TableLog uint8
+}
+
+// Histogram allows to populate the histogram and skip that step in the compression,
+// It otherwise allows to inspect the histogram when compression is done.
+// To indicate that you have populated the histogram call HistogramFinished
+// with the value of the highest populated symbol, as well as the number of entries
+// in the most populated entry. These are accepted at face value.
+// The returned slice will always be length 256.
+func (s *Scratch) Histogram() []uint32 {
+ return s.count[:]
+}
+
+// HistogramFinished can be called to indicate that the histogram has been populated.
+// maxSymbol is the index of the highest set symbol of the next data segment.
+// maxCount is the number of entries in the most populated entry.
+// These are accepted at face value.
+func (s *Scratch) HistogramFinished(maxSymbol uint8, maxCount int) {
+ s.maxCount = maxCount
+ s.symbolLen = uint16(maxSymbol) + 1
+ s.clearCount = maxCount != 0
+}
+
+// prepare will prepare and allocate scratch tables used for both compression and decompression.
+func (s *Scratch) prepare(in []byte) (*Scratch, error) {
+ if s == nil {
+ s = &Scratch{}
+ }
+ if s.MaxSymbolValue == 0 {
+ s.MaxSymbolValue = 255
+ }
+ if s.TableLog == 0 {
+ s.TableLog = defaultTablelog
+ }
+ if s.TableLog > maxTableLog {
+ return nil, fmt.Errorf("tableLog (%d) > maxTableLog (%d)", s.TableLog, maxTableLog)
+ }
+ if cap(s.Out) == 0 {
+ s.Out = make([]byte, 0, len(in))
+ }
+ if s.clearCount && s.maxCount == 0 {
+ for i := range s.count {
+ s.count[i] = 0
+ }
+ s.clearCount = false
+ }
+ s.br.init(in)
+ if s.DecompressLimit == 0 {
+ // Max size 2GB.
+ s.DecompressLimit = (2 << 30) - 1
+ }
+
+ return s, nil
+}
+
+// tableStep returns the next table index.
+func tableStep(tableSize uint32) uint32 {
+ return (tableSize >> 1) + (tableSize >> 3) + 3
+}
+
+func highBits(val uint32) (n uint32) {
+ return uint32(bits.Len32(val) - 1)
+}
diff --git a/vendor/github.com/klauspost/compress/gen.sh b/vendor/github.com/klauspost/compress/gen.sh
new file mode 100644
index 00000000000..aff942205f1
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/gen.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+cd s2/cmd/_s2sx/ || exit 1
+go generate .
diff --git a/vendor/github.com/klauspost/compress/huff0/.gitignore b/vendor/github.com/klauspost/compress/huff0/.gitignore
new file mode 100644
index 00000000000..b3d262958f8
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/.gitignore
@@ -0,0 +1 @@
+/huff0-fuzz.zip
diff --git a/vendor/github.com/klauspost/compress/huff0/README.md b/vendor/github.com/klauspost/compress/huff0/README.md
new file mode 100644
index 00000000000..26d5101b363
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/README.md
@@ -0,0 +1,89 @@
+# Huff0 entropy compression
+
+This package provides Huff0 encoding and decoding as used in zstd.
+
+[Huff0](https://github.com/Cyan4973/FiniteStateEntropy#new-generation-entropy-coders),
+a Huffman codec designed for modern CPU, featuring OoO (Out of Order) operations on multiple ALU
+(Arithmetic Logic Unit), achieving extremely fast compression and decompression speeds.
+
+This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
+This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
+but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
+
+* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/huff0)
+
+## News
+
+This is used as part of the [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression package.
+
+This ensures that most functionality is well tested.
+
+# Usage
+
+This package provides a low level interface that allows to compress single independent blocks.
+
+Each block is separate, and there is no built in integrity checks.
+This means that the caller should keep track of block sizes and also do checksums if needed.
+
+Compressing a block is done via the [`Compress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress1X) and
+[`Compress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress4X) functions.
+You must provide input and will receive the output and maybe an error.
+
+These error values can be returned:
+
+| Error | Description |
+|---------------------|-----------------------------------------------------------------------------|
+| `` | Everything ok, output is returned |
+| `ErrIncompressible` | Returned when input is judged to be too hard to compress |
+| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated |
+| `ErrTooBig` | Returned if the input block exceeds the maximum allowed size (128 Kib) |
+| `(error)` | An internal error occurred. |
+
+
+As can be seen above some of there are errors that will be returned even under normal operation so it is important to handle these.
+
+To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object
+that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same
+object can be used for both.
+
+Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
+you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.
+
+The `Scratch` object will retain state that allows to re-use previous tables for encoding and decoding.
+
+## Tables and re-use
+
+Huff0 allows for reusing tables from the previous block to save space if that is expected to give better/faster results.
+
+The Scratch object allows you to set a [`ReusePolicy`](https://godoc.org/github.com/klauspost/compress/huff0#ReusePolicy)
+that controls this behaviour. See the documentation for details. This can be altered between each block.
+
+Do however note that this information is *not* stored in the output block and it is up to the users of the package to
+record whether [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable) should be called,
+based on the boolean reported back from the CompressXX call.
+
+If you want to store the table separate from the data, you can access them as `OutData` and `OutTable` on the
+[`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object.
+
+## Decompressing
+
+The first part of decoding is to initialize the decoding table through [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable).
+This will initialize the decoding tables.
+You can supply the complete block to `ReadTable` and it will return the data part of the block
+which can be given to the decompressor.
+
+Decompressing is done by calling the [`Decompress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress1X)
+or [`Decompress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress4X) function.
+
+For concurrently decompressing content with a fixed table a stateless [`Decoder`](https://godoc.org/github.com/klauspost/compress/huff0#Decoder) can be requested which will remain correct as long as the scratch is unchanged. The capacity of the provided slice indicates the expected output size.
+
+You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
+your input was likely corrupted.
+
+It is important to note that a successful decoding does *not* mean your output matches your original input.
+There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
+
+# Contributing
+
+Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
+changes will likely not be accepted. If in doubt open an issue before writing the PR.
diff --git a/vendor/github.com/klauspost/compress/huff0/bitreader.go b/vendor/github.com/klauspost/compress/huff0/bitreader.go
new file mode 100644
index 00000000000..bfc7a523dee
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/bitreader.go
@@ -0,0 +1,224 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package huff0
+
+import (
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/klauspost/compress/internal/le"
+)
+
+// bitReader reads a bitstream in reverse.
+// The last set bit indicates the start of the stream and is used
+// for aligning the input.
+type bitReaderBytes struct {
+ in []byte
+ off uint // next byte to read is at in[off - 1]
+ value uint64
+ bitsRead uint8
+}
+
+// init initializes and resets the bit reader.
+func (b *bitReaderBytes) init(in []byte) error {
+ if len(in) < 1 {
+ return errors.New("corrupt stream: too short")
+ }
+ b.in = in
+ b.off = uint(len(in))
+ // The highest bit of the last byte indicates where to start
+ v := in[len(in)-1]
+ if v == 0 {
+ return errors.New("corrupt stream, did not find end of stream")
+ }
+ b.bitsRead = 64
+ b.value = 0
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
+ b.advance(8 - uint8(highBit32(uint32(v))))
+ return nil
+}
+
+// peekByteFast requires that at least one byte is requested every time.
+// There are no checks if the buffer is filled.
+func (b *bitReaderBytes) peekByteFast() uint8 {
+ got := uint8(b.value >> 56)
+ return got
+}
+
+func (b *bitReaderBytes) advance(n uint8) {
+ b.bitsRead += n
+ b.value <<= n & 63
+}
+
+// fillFast() will make sure at least 32 bits are available.
+// There must be at least 4 bytes available.
+func (b *bitReaderBytes) fillFast() {
+ if b.bitsRead < 32 {
+ return
+ }
+
+ // 2 bounds checks.
+ low := le.Load32(b.in, b.off-4)
+ b.value |= uint64(low) << (b.bitsRead - 32)
+ b.bitsRead -= 32
+ b.off -= 4
+}
+
+// fillFastStart() assumes the bitReaderBytes is empty and there is at least 8 bytes to read.
+func (b *bitReaderBytes) fillFastStart() {
+ // Do single re-slice to avoid bounds checks.
+ b.value = le.Load64(b.in, b.off-8)
+ b.bitsRead = 0
+ b.off -= 8
+}
+
+// fill() will make sure at least 32 bits are available.
+func (b *bitReaderBytes) fill() {
+ if b.bitsRead < 32 {
+ return
+ }
+ if b.off >= 4 {
+ low := le.Load32(b.in, b.off-4)
+ b.value |= uint64(low) << (b.bitsRead - 32)
+ b.bitsRead -= 32
+ b.off -= 4
+ return
+ }
+ for b.off > 0 {
+ b.value |= uint64(b.in[b.off-1]) << (b.bitsRead - 8)
+ b.bitsRead -= 8
+ b.off--
+ }
+}
+
+// finished returns true if all bits have been read from the bit stream.
+func (b *bitReaderBytes) finished() bool {
+ return b.off == 0 && b.bitsRead >= 64
+}
+
+func (b *bitReaderBytes) remaining() uint {
+ return b.off*8 + uint(64-b.bitsRead)
+}
+
+// close the bitstream and returns an error if out-of-buffer reads occurred.
+func (b *bitReaderBytes) close() error {
+ // Release reference.
+ b.in = nil
+ if b.remaining() > 0 {
+ return fmt.Errorf("corrupt input: %d bits remain on stream", b.remaining())
+ }
+ if b.bitsRead > 64 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+
+// bitReaderShifted reads a bitstream in reverse.
+// The last set bit indicates the start of the stream and is used
+// for aligning the input.
+type bitReaderShifted struct {
+ in []byte
+ off uint // next byte to read is at in[off - 1]
+ value uint64
+ bitsRead uint8
+}
+
+// init initializes and resets the bit reader.
+func (b *bitReaderShifted) init(in []byte) error {
+ if len(in) < 1 {
+ return errors.New("corrupt stream: too short")
+ }
+ b.in = in
+ b.off = uint(len(in))
+ // The highest bit of the last byte indicates where to start
+ v := in[len(in)-1]
+ if v == 0 {
+ return errors.New("corrupt stream, did not find end of stream")
+ }
+ b.bitsRead = 64
+ b.value = 0
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
+ b.advance(8 - uint8(highBit32(uint32(v))))
+ return nil
+}
+
+// peekBitsFast requires that at least one bit is requested every time.
+// There are no checks if the buffer is filled.
+func (b *bitReaderShifted) peekBitsFast(n uint8) uint16 {
+ return uint16(b.value >> ((64 - n) & 63))
+}
+
+func (b *bitReaderShifted) advance(n uint8) {
+ b.bitsRead += n
+ b.value <<= n & 63
+}
+
+// fillFast() will make sure at least 32 bits are available.
+// There must be at least 4 bytes available.
+func (b *bitReaderShifted) fillFast() {
+ if b.bitsRead < 32 {
+ return
+ }
+
+ low := le.Load32(b.in, b.off-4)
+ b.value |= uint64(low) << ((b.bitsRead - 32) & 63)
+ b.bitsRead -= 32
+ b.off -= 4
+}
+
+// fillFastStart() assumes the bitReaderShifted is empty and there is at least 8 bytes to read.
+func (b *bitReaderShifted) fillFastStart() {
+ b.value = le.Load64(b.in, b.off-8)
+ b.bitsRead = 0
+ b.off -= 8
+}
+
+// fill() will make sure at least 32 bits are available.
+func (b *bitReaderShifted) fill() {
+ if b.bitsRead < 32 {
+ return
+ }
+ if b.off > 4 {
+ low := le.Load32(b.in, b.off-4)
+ b.value |= uint64(low) << ((b.bitsRead - 32) & 63)
+ b.bitsRead -= 32
+ b.off -= 4
+ return
+ }
+ for b.off > 0 {
+ b.value |= uint64(b.in[b.off-1]) << ((b.bitsRead - 8) & 63)
+ b.bitsRead -= 8
+ b.off--
+ }
+}
+
+func (b *bitReaderShifted) remaining() uint {
+ return b.off*8 + uint(64-b.bitsRead)
+}
+
+// close the bitstream and returns an error if out-of-buffer reads occurred.
+func (b *bitReaderShifted) close() error {
+ // Release reference.
+ b.in = nil
+ if b.remaining() > 0 {
+ return fmt.Errorf("corrupt input: %d bits remain on stream", b.remaining())
+ }
+ if b.bitsRead > 64 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/bitwriter.go b/vendor/github.com/klauspost/compress/huff0/bitwriter.go
new file mode 100644
index 00000000000..41db94cded0
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/bitwriter.go
@@ -0,0 +1,102 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package huff0
+
+// bitWriter will write bits.
+// First bit will be LSB of the first byte of output.
+type bitWriter struct {
+ bitContainer uint64
+ nBits uint8
+ out []byte
+}
+
+// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated.
+// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
+func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
+ b.bitContainer |= uint64(value) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// encSymbol will add up to 16 bits. value may not contain more set bits than indicated.
+// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
+func (b *bitWriter) encSymbol(ct cTable, symbol byte) {
+ enc := ct[symbol]
+ b.bitContainer |= uint64(enc.val) << (b.nBits & 63)
+ if false {
+ if enc.nBits == 0 {
+ panic("nbits 0")
+ }
+ }
+ b.nBits += enc.nBits
+}
+
+// encTwoSymbols will add up to 32 bits. value may not contain more set bits than indicated.
+// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
+func (b *bitWriter) encTwoSymbols(ct cTable, av, bv byte) {
+ encA := ct[av]
+ encB := ct[bv]
+ sh := b.nBits & 63
+ combined := uint64(encA.val) | (uint64(encB.val) << (encA.nBits & 63))
+ b.bitContainer |= combined << sh
+ if false {
+ if encA.nBits == 0 {
+ panic("nbitsA 0")
+ }
+ if encB.nBits == 0 {
+ panic("nbitsB 0")
+ }
+ }
+ b.nBits += encA.nBits + encB.nBits
+}
+
+// encFourSymbols adds up to 32 bits from four symbols.
+// It will not check if there is space for them,
+// so the caller must ensure that b has been flushed recently.
+func (b *bitWriter) encFourSymbols(encA, encB, encC, encD cTableEntry) {
+ bitsA := encA.nBits
+ bitsB := bitsA + encB.nBits
+ bitsC := bitsB + encC.nBits
+ bitsD := bitsC + encD.nBits
+ combined := uint64(encA.val) |
+ (uint64(encB.val) << (bitsA & 63)) |
+ (uint64(encC.val) << (bitsB & 63)) |
+ (uint64(encD.val) << (bitsC & 63))
+ b.bitContainer |= combined << (b.nBits & 63)
+ b.nBits += bitsD
+}
+
+// flush32 will flush out, so there are at least 32 bits available for writing.
+func (b *bitWriter) flush32() {
+ if b.nBits < 32 {
+ return
+ }
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24))
+ b.nBits -= 32
+ b.bitContainer >>= 32
+}
+
+// flushAlign will flush remaining full bytes and align to next byte boundary.
+func (b *bitWriter) flushAlign() {
+ nbBytes := (b.nBits + 7) >> 3
+ for i := range nbBytes {
+ b.out = append(b.out, byte(b.bitContainer>>(i*8)))
+ }
+ b.nBits = 0
+ b.bitContainer = 0
+}
+
+// close will write the alignment bit and write the final byte(s)
+// to the output.
+func (b *bitWriter) close() {
+ // End mark
+ b.addBits16Clean(1, 1)
+ // flush until next byte.
+ b.flushAlign()
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/compress.go b/vendor/github.com/klauspost/compress/huff0/compress.go
new file mode 100644
index 00000000000..a97cf1b5d35
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/compress.go
@@ -0,0 +1,742 @@
+package huff0
+
+import (
+ "fmt"
+ "math"
+ "runtime"
+ "sync"
+)
+
+// Compress1X will compress the input.
+// The output can be decoded using Decompress1X.
+// Supply a Scratch object. The scratch object contains state about re-use,
+// So when sharing across independent encodes, be sure to set the re-use policy.
+func Compress1X(in []byte, s *Scratch) (out []byte, reUsed bool, err error) {
+ s, err = s.prepare(in)
+ if err != nil {
+ return nil, false, err
+ }
+ return compress(in, s, s.compress1X)
+}
+
+// Compress4X will compress the input. The input is split into 4 independent blocks
+// and compressed similar to Compress1X.
+// The output can be decoded using Decompress4X.
+// Supply a Scratch object. The scratch object contains state about re-use,
+// So when sharing across independent encodes, be sure to set the re-use policy.
+func Compress4X(in []byte, s *Scratch) (out []byte, reUsed bool, err error) {
+ s, err = s.prepare(in)
+ if err != nil {
+ return nil, false, err
+ }
+ if false {
+ // TODO: compress4Xp only slightly faster.
+ const parallelThreshold = 8 << 10
+ if len(in) < parallelThreshold || runtime.GOMAXPROCS(0) == 1 {
+ return compress(in, s, s.compress4X)
+ }
+ return compress(in, s, s.compress4Xp)
+ }
+ return compress(in, s, s.compress4X)
+}
+
+func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)) (out []byte, reUsed bool, err error) {
+ // Nuke previous table if we cannot reuse anyway.
+ if s.Reuse == ReusePolicyNone {
+ s.prevTable = s.prevTable[:0]
+ }
+
+ // Create histogram, if none was provided.
+ maxCount := s.maxCount
+ var canReuse = false
+ if maxCount == 0 {
+ maxCount, canReuse = s.countSimple(in)
+ } else {
+ canReuse = s.canUseTable(s.prevTable)
+ }
+
+ // We want the output size to be less than this:
+ wantSize := len(in)
+ if s.WantLogLess > 0 {
+ wantSize -= wantSize >> s.WantLogLess
+ }
+
+ // Reset for next run.
+ s.clearCount = true
+ s.maxCount = 0
+ if maxCount >= len(in) {
+ if maxCount > len(in) {
+ return nil, false, fmt.Errorf("maxCount (%d) > length (%d)", maxCount, len(in))
+ }
+ if len(in) == 1 {
+ return nil, false, ErrIncompressible
+ }
+ // One symbol, use RLE
+ return nil, false, ErrUseRLE
+ }
+ if maxCount == 1 || maxCount < (len(in)>>7) {
+ // Each symbol present maximum once or too well distributed.
+ return nil, false, ErrIncompressible
+ }
+ if s.Reuse == ReusePolicyMust && !canReuse {
+ // We must reuse, but we can't.
+ return nil, false, ErrIncompressible
+ }
+ if (s.Reuse == ReusePolicyPrefer || s.Reuse == ReusePolicyMust) && canReuse {
+ keepTable := s.cTable
+ keepTL := s.actualTableLog
+ s.cTable = s.prevTable
+ s.actualTableLog = s.prevTableLog
+ s.Out, err = compressor(in)
+ s.cTable = keepTable
+ s.actualTableLog = keepTL
+ if err == nil && len(s.Out) < wantSize {
+ s.OutData = s.Out
+ return s.Out, true, nil
+ }
+ if s.Reuse == ReusePolicyMust {
+ return nil, false, ErrIncompressible
+ }
+ // Do not attempt to re-use later.
+ s.prevTable = s.prevTable[:0]
+ }
+
+ // Calculate new table.
+ err = s.buildCTable()
+ if err != nil {
+ return nil, false, err
+ }
+
+ if false && !s.canUseTable(s.cTable) {
+ panic("invalid table generated")
+ }
+
+ if s.Reuse == ReusePolicyAllow && canReuse {
+ hSize := len(s.Out)
+ oldSize := s.prevTable.estimateSize(s.count[:s.symbolLen])
+ newSize := s.cTable.estimateSize(s.count[:s.symbolLen])
+ if oldSize <= hSize+newSize || hSize+12 >= wantSize {
+ // Retain cTable even if we re-use.
+ keepTable := s.cTable
+ keepTL := s.actualTableLog
+
+ s.cTable = s.prevTable
+ s.actualTableLog = s.prevTableLog
+ s.Out, err = compressor(in)
+
+ // Restore ctable.
+ s.cTable = keepTable
+ s.actualTableLog = keepTL
+ if err != nil {
+ return nil, false, err
+ }
+ if len(s.Out) >= wantSize {
+ return nil, false, ErrIncompressible
+ }
+ s.OutData = s.Out
+ return s.Out, true, nil
+ }
+ }
+
+ // Use new table
+ err = s.cTable.write(s)
+ if err != nil {
+ s.OutTable = nil
+ return nil, false, err
+ }
+ s.OutTable = s.Out
+
+ // Compress using new table
+ s.Out, err = compressor(in)
+ if err != nil {
+ s.OutTable = nil
+ return nil, false, err
+ }
+ if len(s.Out) >= wantSize {
+ s.OutTable = nil
+ return nil, false, ErrIncompressible
+ }
+ // Move current table into previous.
+ s.prevTable, s.prevTableLog, s.cTable = s.cTable, s.actualTableLog, s.prevTable[:0]
+ s.OutData = s.Out[len(s.OutTable):]
+ return s.Out, false, nil
+}
+
+// EstimateSizes will estimate the data sizes
+func EstimateSizes(in []byte, s *Scratch) (tableSz, dataSz, reuseSz int, err error) {
+ s, err = s.prepare(in)
+ if err != nil {
+ return 0, 0, 0, err
+ }
+
+ // Create histogram, if none was provided.
+ tableSz, dataSz, reuseSz = -1, -1, -1
+ maxCount := s.maxCount
+ var canReuse = false
+ if maxCount == 0 {
+ maxCount, canReuse = s.countSimple(in)
+ } else {
+ canReuse = s.canUseTable(s.prevTable)
+ }
+
+ // We want the output size to be less than this:
+ wantSize := len(in)
+ if s.WantLogLess > 0 {
+ wantSize -= wantSize >> s.WantLogLess
+ }
+
+ // Reset for next run.
+ s.clearCount = true
+ s.maxCount = 0
+ if maxCount >= len(in) {
+ if maxCount > len(in) {
+ return 0, 0, 0, fmt.Errorf("maxCount (%d) > length (%d)", maxCount, len(in))
+ }
+ if len(in) == 1 {
+ return 0, 0, 0, ErrIncompressible
+ }
+ // One symbol, use RLE
+ return 0, 0, 0, ErrUseRLE
+ }
+ if maxCount == 1 || maxCount < (len(in)>>7) {
+ // Each symbol present maximum once or too well distributed.
+ return 0, 0, 0, ErrIncompressible
+ }
+
+ // Calculate new table.
+ err = s.buildCTable()
+ if err != nil {
+ return 0, 0, 0, err
+ }
+
+ if false && !s.canUseTable(s.cTable) {
+ panic("invalid table generated")
+ }
+
+ tableSz, err = s.cTable.estTableSize(s)
+ if err != nil {
+ return 0, 0, 0, err
+ }
+ if canReuse {
+ reuseSz = s.prevTable.estimateSize(s.count[:s.symbolLen])
+ }
+ dataSz = s.cTable.estimateSize(s.count[:s.symbolLen])
+
+ // Restore
+ return tableSz, dataSz, reuseSz, nil
+}
+
+func (s *Scratch) compress1X(src []byte) ([]byte, error) {
+ return s.compress1xDo(s.Out, src), nil
+}
+
+func (s *Scratch) compress1xDo(dst, src []byte) []byte {
+ var bw = bitWriter{out: dst}
+
+ // N is length divisible by 4.
+ n := len(src)
+ n -= n & 3
+ cTable := s.cTable[:256]
+
+ // Encode last bytes.
+ for i := len(src) & 3; i > 0; i-- {
+ bw.encSymbol(cTable, src[n+i-1])
+ }
+ n -= 4
+ if s.actualTableLog <= 8 {
+ for ; n >= 0; n -= 4 {
+ tmp := src[n : n+4]
+ // tmp should be len 4
+ bw.flush32()
+ bw.encFourSymbols(cTable[tmp[3]], cTable[tmp[2]], cTable[tmp[1]], cTable[tmp[0]])
+ }
+ } else {
+ for ; n >= 0; n -= 4 {
+ tmp := src[n : n+4]
+ // tmp should be len 4
+ bw.flush32()
+ bw.encTwoSymbols(cTable, tmp[3], tmp[2])
+ bw.flush32()
+ bw.encTwoSymbols(cTable, tmp[1], tmp[0])
+ }
+ }
+ bw.close()
+ return bw.out
+}
+
+var sixZeros [6]byte
+
+func (s *Scratch) compress4X(src []byte) ([]byte, error) {
+ if len(src) < 12 {
+ return nil, ErrIncompressible
+ }
+ segmentSize := (len(src) + 3) / 4
+
+ // Add placeholder for output length
+ offsetIdx := len(s.Out)
+ s.Out = append(s.Out, sixZeros[:]...)
+
+ for i := range 4 {
+ toDo := src
+ if len(toDo) > segmentSize {
+ toDo = toDo[:segmentSize]
+ }
+ src = src[len(toDo):]
+
+ idx := len(s.Out)
+ s.Out = s.compress1xDo(s.Out, toDo)
+ if len(s.Out)-idx > math.MaxUint16 {
+ // We cannot store the size in the jump table
+ return nil, ErrIncompressible
+ }
+ // Write compressed length as little endian before block.
+ if i < 3 {
+ // Last length is not written.
+ length := len(s.Out) - idx
+ s.Out[i*2+offsetIdx] = byte(length)
+ s.Out[i*2+offsetIdx+1] = byte(length >> 8)
+ }
+ }
+
+ return s.Out, nil
+}
+
+// compress4Xp will compress 4 streams using separate goroutines.
+func (s *Scratch) compress4Xp(src []byte) ([]byte, error) {
+ if len(src) < 12 {
+ return nil, ErrIncompressible
+ }
+ // Add placeholder for output length
+ s.Out = s.Out[:6]
+
+ segmentSize := (len(src) + 3) / 4
+ var wg sync.WaitGroup
+ wg.Add(4)
+ for i := range 4 {
+ toDo := src
+ if len(toDo) > segmentSize {
+ toDo = toDo[:segmentSize]
+ }
+ src = src[len(toDo):]
+
+ // Separate goroutine for each block.
+ go func(i int) {
+ s.tmpOut[i] = s.compress1xDo(s.tmpOut[i][:0], toDo)
+ wg.Done()
+ }(i)
+ }
+ wg.Wait()
+ for i := range 4 {
+ o := s.tmpOut[i]
+ if len(o) > math.MaxUint16 {
+ // We cannot store the size in the jump table
+ return nil, ErrIncompressible
+ }
+ // Write compressed length as little endian before block.
+ if i < 3 {
+ // Last length is not written.
+ s.Out[i*2] = byte(len(o))
+ s.Out[i*2+1] = byte(len(o) >> 8)
+ }
+
+ // Write output.
+ s.Out = append(s.Out, o...)
+ }
+ return s.Out, nil
+}
+
+// countSimple will create a simple histogram in s.count.
+// Returns the biggest count.
+// Does not update s.clearCount.
+func (s *Scratch) countSimple(in []byte) (max int, reuse bool) {
+ reuse = true
+ _ = s.count // Assert that s != nil to speed up the following loop.
+ for _, v := range in {
+ s.count[v]++
+ }
+ m := uint32(0)
+ if len(s.prevTable) > 0 {
+ for i, v := range s.count[:] {
+ if v == 0 {
+ continue
+ }
+ if v > m {
+ m = v
+ }
+ s.symbolLen = uint16(i) + 1
+ if i >= len(s.prevTable) {
+ reuse = false
+ } else if s.prevTable[i].nBits == 0 {
+ reuse = false
+ }
+ }
+ return int(m), reuse
+ }
+ for i, v := range s.count[:] {
+ if v == 0 {
+ continue
+ }
+ if v > m {
+ m = v
+ }
+ s.symbolLen = uint16(i) + 1
+ }
+ return int(m), false
+}
+
+func (s *Scratch) canUseTable(c cTable) bool {
+ if len(c) < int(s.symbolLen) {
+ return false
+ }
+ for i, v := range s.count[:s.symbolLen] {
+ if v != 0 && c[i].nBits == 0 {
+ return false
+ }
+ }
+ return true
+}
+
+//lint:ignore U1000 used for debugging
+func (s *Scratch) validateTable(c cTable) bool {
+ if len(c) < int(s.symbolLen) {
+ return false
+ }
+ for i, v := range s.count[:s.symbolLen] {
+ if v != 0 {
+ if c[i].nBits == 0 {
+ return false
+ }
+ if c[i].nBits > s.actualTableLog {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// minTableLog provides the minimum logSize to safely represent a distribution.
+func (s *Scratch) minTableLog() uint8 {
+ minBitsSrc := highBit32(uint32(s.srcLen)) + 1
+ minBitsSymbols := highBit32(uint32(s.symbolLen-1)) + 2
+ if minBitsSrc < minBitsSymbols {
+ return uint8(minBitsSrc)
+ }
+ return uint8(minBitsSymbols)
+}
+
+// optimalTableLog calculates and sets the optimal tableLog in s.actualTableLog
+func (s *Scratch) optimalTableLog() {
+ tableLog := s.TableLog
+ minBits := s.minTableLog()
+ maxBitsSrc := uint8(highBit32(uint32(s.srcLen-1))) - 1
+ if maxBitsSrc < tableLog {
+ // Accuracy can be reduced
+ tableLog = maxBitsSrc
+ }
+ if minBits > tableLog {
+ tableLog = minBits
+ }
+ // Need a minimum to safely represent all symbol values
+ if tableLog < minTablelog {
+ tableLog = minTablelog
+ }
+ if tableLog > tableLogMax {
+ tableLog = tableLogMax
+ }
+ s.actualTableLog = tableLog
+}
+
+type cTableEntry struct {
+ val uint16
+ nBits uint8
+ // We have 8 bits extra
+}
+
+const huffNodesMask = huffNodesLen - 1
+
+func (s *Scratch) buildCTable() error {
+ s.optimalTableLog()
+ s.huffSort()
+ if cap(s.cTable) < maxSymbolValue+1 {
+ s.cTable = make([]cTableEntry, s.symbolLen, maxSymbolValue+1)
+ } else {
+ s.cTable = s.cTable[:s.symbolLen]
+ for i := range s.cTable {
+ s.cTable[i] = cTableEntry{}
+ }
+ }
+
+ var startNode = int16(s.symbolLen)
+ nonNullRank := s.symbolLen - 1
+
+ nodeNb := startNode
+ huffNode := s.nodes[1 : huffNodesLen+1]
+
+ // This overlays the slice above, but allows "-1" index lookups.
+ // Different from reference implementation.
+ huffNode0 := s.nodes[0 : huffNodesLen+1]
+
+ for huffNode[nonNullRank].count() == 0 {
+ nonNullRank--
+ }
+
+ lowS := int16(nonNullRank)
+ nodeRoot := nodeNb + lowS - 1
+ lowN := nodeNb
+ huffNode[nodeNb].setCount(huffNode[lowS].count() + huffNode[lowS-1].count())
+ huffNode[lowS].setParent(nodeNb)
+ huffNode[lowS-1].setParent(nodeNb)
+ nodeNb++
+ lowS -= 2
+ for n := nodeNb; n <= nodeRoot; n++ {
+ huffNode[n].setCount(1 << 30)
+ }
+ // fake entry, strong barrier
+ huffNode0[0].setCount(1 << 31)
+
+ // create parents
+ for nodeNb <= nodeRoot {
+ var n1, n2 int16
+ if huffNode0[lowS+1].count() < huffNode0[lowN+1].count() {
+ n1 = lowS
+ lowS--
+ } else {
+ n1 = lowN
+ lowN++
+ }
+ if huffNode0[lowS+1].count() < huffNode0[lowN+1].count() {
+ n2 = lowS
+ lowS--
+ } else {
+ n2 = lowN
+ lowN++
+ }
+
+ huffNode[nodeNb].setCount(huffNode0[n1+1].count() + huffNode0[n2+1].count())
+ huffNode0[n1+1].setParent(nodeNb)
+ huffNode0[n2+1].setParent(nodeNb)
+ nodeNb++
+ }
+
+ // distribute weights (unlimited tree height)
+ huffNode[nodeRoot].setNbBits(0)
+ for n := nodeRoot - 1; n >= startNode; n-- {
+ huffNode[n].setNbBits(huffNode[huffNode[n].parent()].nbBits() + 1)
+ }
+ for n := uint16(0); n <= nonNullRank; n++ {
+ huffNode[n].setNbBits(huffNode[huffNode[n].parent()].nbBits() + 1)
+ }
+ s.actualTableLog = s.setMaxHeight(int(nonNullRank))
+ maxNbBits := s.actualTableLog
+
+ // fill result into tree (val, nbBits)
+ if maxNbBits > tableLogMax {
+ return fmt.Errorf("internal error: maxNbBits (%d) > tableLogMax (%d)", maxNbBits, tableLogMax)
+ }
+ var nbPerRank [tableLogMax + 1]uint16
+ var valPerRank [16]uint16
+ for _, v := range huffNode[:nonNullRank+1] {
+ nbPerRank[v.nbBits()]++
+ }
+ // determine stating value per rank
+ {
+ min := uint16(0)
+ for n := maxNbBits; n > 0; n-- {
+ // get starting value within each rank
+ valPerRank[n] = min
+ min += nbPerRank[n]
+ min >>= 1
+ }
+ }
+
+ // push nbBits per symbol, symbol order
+ for _, v := range huffNode[:nonNullRank+1] {
+ s.cTable[v.symbol()].nBits = v.nbBits()
+ }
+
+ // assign value within rank, symbol order
+ t := s.cTable[:s.symbolLen]
+ for n, val := range t {
+ nbits := val.nBits & 15
+ v := valPerRank[nbits]
+ t[n].val = v
+ valPerRank[nbits] = v + 1
+ }
+
+ return nil
+}
+
+// huffSort will sort symbols, decreasing order.
+func (s *Scratch) huffSort() {
+ type rankPos struct {
+ base uint32
+ current uint32
+ }
+
+ // Clear nodes
+ nodes := s.nodes[:huffNodesLen+1]
+ s.nodes = nodes
+ nodes = nodes[1 : huffNodesLen+1]
+
+ // Sort into buckets based on length of symbol count.
+ var rank [32]rankPos
+ for _, v := range s.count[:s.symbolLen] {
+ r := highBit32(v+1) & 31
+ rank[r].base++
+ }
+ // maxBitLength is log2(BlockSizeMax) + 1
+ const maxBitLength = 18 + 1
+ for n := maxBitLength; n > 0; n-- {
+ rank[n-1].base += rank[n].base
+ }
+ for n := range rank[:maxBitLength] {
+ rank[n].current = rank[n].base
+ }
+ for n, c := range s.count[:s.symbolLen] {
+ r := (highBit32(c+1) + 1) & 31
+ pos := rank[r].current
+ rank[r].current++
+ prev := nodes[(pos-1)&huffNodesMask]
+ for pos > rank[r].base && c > prev.count() {
+ nodes[pos&huffNodesMask] = prev
+ pos--
+ prev = nodes[(pos-1)&huffNodesMask]
+ }
+ nodes[pos&huffNodesMask] = makeNodeElt(c, byte(n))
+ }
+}
+
+func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
+ maxNbBits := s.actualTableLog
+ huffNode := s.nodes[1 : huffNodesLen+1]
+ //huffNode = huffNode[: huffNodesLen]
+
+ largestBits := huffNode[lastNonNull].nbBits()
+
+ // early exit : no elt > maxNbBits
+ if largestBits <= maxNbBits {
+ return largestBits
+ }
+ totalCost := int(0)
+ baseCost := int(1) << (largestBits - maxNbBits)
+ n := uint32(lastNonNull)
+
+ for huffNode[n].nbBits() > maxNbBits {
+ totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits()))
+ huffNode[n].setNbBits(maxNbBits)
+ n--
+ }
+ // n stops at huffNode[n].nbBits <= maxNbBits
+
+ for huffNode[n].nbBits() == maxNbBits {
+ n--
+ }
+ // n end at index of smallest symbol using < maxNbBits
+
+ // renorm totalCost
+ totalCost >>= largestBits - maxNbBits /* note : totalCost is necessarily a multiple of baseCost */
+
+ // repay normalized cost
+ {
+ const noSymbol = 0xF0F0F0F0
+ var rankLast [tableLogMax + 2]uint32
+
+ for i := range rankLast[:] {
+ rankLast[i] = noSymbol
+ }
+
+ // Get pos of last (smallest) symbol per rank
+ {
+ currentNbBits := maxNbBits
+ for pos := int(n); pos >= 0; pos-- {
+ if huffNode[pos].nbBits() >= currentNbBits {
+ continue
+ }
+ currentNbBits = huffNode[pos].nbBits() // < maxNbBits
+ rankLast[maxNbBits-currentNbBits] = uint32(pos)
+ }
+ }
+
+ for totalCost > 0 {
+ nBitsToDecrease := uint8(highBit32(uint32(totalCost))) + 1
+
+ for ; nBitsToDecrease > 1; nBitsToDecrease-- {
+ highPos := rankLast[nBitsToDecrease]
+ lowPos := rankLast[nBitsToDecrease-1]
+ if highPos == noSymbol {
+ continue
+ }
+ if lowPos == noSymbol {
+ break
+ }
+ highTotal := huffNode[highPos].count()
+ lowTotal := 2 * huffNode[lowPos].count()
+ if highTotal <= lowTotal {
+ break
+ }
+ }
+ // only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !)
+ // HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary
+ // FIXME: try to remove
+ for (nBitsToDecrease <= tableLogMax) && (rankLast[nBitsToDecrease] == noSymbol) {
+ nBitsToDecrease++
+ }
+ totalCost -= 1 << (nBitsToDecrease - 1)
+ if rankLast[nBitsToDecrease-1] == noSymbol {
+ // this rank is no longer empty
+ rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]
+ }
+ huffNode[rankLast[nBitsToDecrease]].setNbBits(1 +
+ huffNode[rankLast[nBitsToDecrease]].nbBits())
+ if rankLast[nBitsToDecrease] == 0 {
+ /* special case, reached largest symbol */
+ rankLast[nBitsToDecrease] = noSymbol
+ } else {
+ rankLast[nBitsToDecrease]--
+ if huffNode[rankLast[nBitsToDecrease]].nbBits() != maxNbBits-nBitsToDecrease {
+ rankLast[nBitsToDecrease] = noSymbol /* this rank is now empty */
+ }
+ }
+ }
+
+ for totalCost < 0 { /* Sometimes, cost correction overshoot */
+ if rankLast[1] == noSymbol { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
+ for huffNode[n].nbBits() == maxNbBits {
+ n--
+ }
+ huffNode[n+1].setNbBits(huffNode[n+1].nbBits() - 1)
+ rankLast[1] = n + 1
+ totalCost++
+ continue
+ }
+ huffNode[rankLast[1]+1].setNbBits(huffNode[rankLast[1]+1].nbBits() - 1)
+ rankLast[1]++
+ totalCost++
+ }
+ }
+ return maxNbBits
+}
+
+// A nodeElt is the fields
+//
+// count uint32
+// parent uint16
+// symbol byte
+// nbBits uint8
+//
+// in some order, all squashed into an integer so that the compiler
+// always loads and stores entire nodeElts instead of separate fields.
+type nodeElt uint64
+
+func makeNodeElt(count uint32, symbol byte) nodeElt {
+ return nodeElt(count) | nodeElt(symbol)<<48
+}
+
+func (e *nodeElt) count() uint32 { return uint32(*e) }
+func (e *nodeElt) parent() uint16 { return uint16(*e >> 32) }
+func (e *nodeElt) symbol() byte { return byte(*e >> 48) }
+func (e *nodeElt) nbBits() uint8 { return uint8(*e >> 56) }
+
+func (e *nodeElt) setCount(c uint32) { *e = (*e)&0xffffffff00000000 | nodeElt(c) }
+func (e *nodeElt) setParent(p int16) { *e = (*e)&0xffff0000ffffffff | nodeElt(uint16(p))<<32 }
+func (e *nodeElt) setNbBits(n uint8) { *e = (*e)&0x00ffffffffffffff | nodeElt(n)<<56 }
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress.go b/vendor/github.com/klauspost/compress/huff0/decompress.go
new file mode 100644
index 00000000000..7d0efa8818a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/decompress.go
@@ -0,0 +1,1161 @@
+package huff0
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "sync"
+
+ "github.com/klauspost/compress/fse"
+)
+
+type dTable struct {
+ single []dEntrySingle
+}
+
+// single-symbols decoding
+type dEntrySingle struct {
+ entry uint16
+}
+
+// Uses special code for all tables that are < 8 bits.
+const use8BitTables = true
+
+// ReadTable will read a table from the input.
+// The size of the input may be larger than the table definition.
+// Any content remaining after the table definition will be returned.
+// If no Scratch is provided a new one is allocated.
+// The returned Scratch can be used for encoding or decoding input using this table.
+func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
+ s, err = s.prepare(nil)
+ if err != nil {
+ return s, nil, err
+ }
+ if len(in) <= 1 {
+ return s, nil, errors.New("input too small for table")
+ }
+ iSize := in[0]
+ in = in[1:]
+ if iSize >= 128 {
+ // Uncompressed
+ oSize := iSize - 127
+ iSize = (oSize + 1) / 2
+ if int(iSize) > len(in) {
+ return s, nil, errors.New("input too small for table")
+ }
+ for n := uint8(0); n < oSize; n += 2 {
+ v := in[n/2]
+ s.huffWeight[n] = v >> 4
+ s.huffWeight[n+1] = v & 15
+ }
+ s.symbolLen = uint16(oSize)
+ in = in[iSize:]
+ } else {
+ if len(in) < int(iSize) {
+ return s, nil, fmt.Errorf("input too small for table, want %d bytes, have %d", iSize, len(in))
+ }
+ // FSE compressed weights
+ s.fse.DecompressLimit = 255
+ hw := s.huffWeight[:]
+ s.fse.Out = hw
+ b, err := fse.Decompress(in[:iSize], s.fse)
+ s.fse.Out = nil
+ if err != nil {
+ return s, nil, fmt.Errorf("fse decompress returned: %w", err)
+ }
+ if len(b) > 255 {
+ return s, nil, errors.New("corrupt input: output table too large")
+ }
+ s.symbolLen = uint16(len(b))
+ in = in[iSize:]
+ }
+
+ // collect weight stats
+ var rankStats [16]uint32
+ weightTotal := uint32(0)
+ for _, v := range s.huffWeight[:s.symbolLen] {
+ if v > tableLogMax {
+ return s, nil, errors.New("corrupt input: weight too large")
+ }
+ v2 := v & 15
+ rankStats[v2]++
+ // (1 << (v2-1)) is slower since the compiler cannot prove that v2 isn't 0.
+ weightTotal += (1 << v2) >> 1
+ }
+ if weightTotal == 0 {
+ return s, nil, errors.New("corrupt input: weights zero")
+ }
+
+ // get last non-null symbol weight (implied, total must be 2^n)
+ {
+ tableLog := highBit32(weightTotal) + 1
+ if tableLog > tableLogMax {
+ return s, nil, errors.New("corrupt input: tableLog too big")
+ }
+ s.actualTableLog = uint8(tableLog)
+ // determine last weight
+ {
+ total := uint32(1) << tableLog
+ rest := total - weightTotal
+ verif := uint32(1) << highBit32(rest)
+ lastWeight := highBit32(rest) + 1
+ if verif != rest {
+ // last value must be a clean power of 2
+ return s, nil, errors.New("corrupt input: last value not power of two")
+ }
+ s.huffWeight[s.symbolLen] = uint8(lastWeight)
+ s.symbolLen++
+ rankStats[lastWeight]++
+ }
+ }
+
+ if (rankStats[1] < 2) || (rankStats[1]&1 != 0) {
+ // by construction : at least 2 elts of rank 1, must be even
+ return s, nil, errors.New("corrupt input: min elt size, even check failed ")
+ }
+
+ // TODO: Choose between single/double symbol decoding
+
+ // Calculate starting value for each rank
+ {
+ var nextRankStart uint32
+ for n := uint8(1); n < s.actualTableLog+1; n++ {
+ current := nextRankStart
+ nextRankStart += rankStats[n] << (n - 1)
+ rankStats[n] = current
+ }
+ }
+
+ // fill DTable (always full size)
+ tSize := 1 << tableLogMax
+ if len(s.dt.single) != tSize {
+ s.dt.single = make([]dEntrySingle, tSize)
+ }
+ cTable := s.prevTable
+ if cap(cTable) < maxSymbolValue+1 {
+ cTable = make([]cTableEntry, 0, maxSymbolValue+1)
+ }
+ cTable = cTable[:maxSymbolValue+1]
+ s.prevTable = cTable[:s.symbolLen]
+ s.prevTableLog = s.actualTableLog
+
+ for n, w := range s.huffWeight[:s.symbolLen] {
+ if w == 0 {
+ cTable[n] = cTableEntry{
+ val: 0,
+ nBits: 0,
+ }
+ continue
+ }
+ length := (uint32(1) << w) >> 1
+ d := dEntrySingle{
+ entry: uint16(s.actualTableLog+1-w) | (uint16(n) << 8),
+ }
+
+ rank := &rankStats[w]
+ cTable[n] = cTableEntry{
+ val: uint16(*rank >> (w - 1)),
+ nBits: uint8(d.entry),
+ }
+
+ single := s.dt.single[*rank : *rank+length]
+ for i := range single {
+ single[i] = d
+ }
+ *rank += length
+ }
+
+ return s, in, nil
+}
+
+// Decompress1X will decompress a 1X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// Before this is called, the table must be initialized with ReadTable unless
+// the encoder re-used the table.
+// deprecated: Use the stateless Decoder() to get a concurrent version.
+func (s *Scratch) Decompress1X(in []byte) (out []byte, err error) {
+ if cap(s.Out) < s.MaxDecodedSize {
+ s.Out = make([]byte, s.MaxDecodedSize)
+ }
+ s.Out = s.Out[:0:s.MaxDecodedSize]
+ s.Out, err = s.Decoder().Decompress1X(s.Out, in)
+ return s.Out, err
+}
+
+// Decompress4X will decompress a 4X encoded stream.
+// Before this is called, the table must be initialized with ReadTable unless
+// the encoder re-used the table.
+// The length of the supplied input must match the end of a block exactly.
+// The destination size of the uncompressed data must be known and provided.
+// deprecated: Use the stateless Decoder() to get a concurrent version.
+func (s *Scratch) Decompress4X(in []byte, dstSize int) (out []byte, err error) {
+ if dstSize > s.MaxDecodedSize {
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ if cap(s.Out) < dstSize {
+ s.Out = make([]byte, s.MaxDecodedSize)
+ }
+ s.Out = s.Out[:0:dstSize]
+ s.Out, err = s.Decoder().Decompress4X(s.Out, in)
+ return s.Out, err
+}
+
+// Decoder will return a stateless decoder that can be used by multiple
+// decompressors concurrently.
+// Before this is called, the table must be initialized with ReadTable.
+// The Decoder is still linked to the scratch buffer so that cannot be reused.
+// However, it is safe to discard the scratch.
+func (s *Scratch) Decoder() *Decoder {
+ return &Decoder{
+ dt: s.dt,
+ actualTableLog: s.actualTableLog,
+ bufs: &s.decPool,
+ }
+}
+
+// Decoder provides stateless decoding.
+type Decoder struct {
+ dt dTable
+ actualTableLog uint8
+ bufs *sync.Pool
+}
+
+func (d *Decoder) buffer() *[4][256]byte {
+ buf, ok := d.bufs.Get().(*[4][256]byte)
+ if ok {
+ return buf
+ }
+ return &[4][256]byte{}
+}
+
+// decompress1X8Bit will decompress a 1X encoded stream with tablelog <= 8.
+// The cap of the output buffer will be the maximum decompressed size.
+// The length of the supplied input must match the end of a block exactly.
+func (d *Decoder) decompress1X8Bit(dst, src []byte) ([]byte, error) {
+ if d.actualTableLog == 8 {
+ return d.decompress1X8BitExactly(dst, src)
+ }
+ var br bitReaderBytes
+ err := br.init(src)
+ if err != nil {
+ return dst, err
+ }
+ maxDecodedSize := cap(dst)
+ dst = dst[:0]
+
+ // Avoid bounds check by always having full sized table.
+ dt := d.dt.single[:256]
+
+ // Use temp table to avoid bound checks/append penalty.
+ bufs := d.buffer()
+ buf := &bufs[0]
+ var off uint8
+
+ switch d.actualTableLog {
+ case 8:
+ const shift = 0
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ d.bufs.Put(bufs)
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 7:
+ const shift = 8 - 7
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ d.bufs.Put(bufs)
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 6:
+ const shift = 8 - 6
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 5:
+ const shift = 8 - 5
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 4:
+ const shift = 8 - 4
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 3:
+ const shift = 8 - 3
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 2:
+ const shift = 8 - 2
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 1:
+ const shift = 8 - 1
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ default:
+ d.bufs.Put(bufs)
+ return nil, fmt.Errorf("invalid tablelog: %d", d.actualTableLog)
+ }
+
+ if len(dst)+int(off) > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:off]...)
+
+ // br < 4, so uint8 is fine
+ bitsLeft := int8(uint8(br.off)*8 + (64 - br.bitsRead))
+ shift := (8 - d.actualTableLog) & 7
+
+ for bitsLeft > 0 {
+ if br.bitsRead >= 64-8 {
+ for br.off > 0 {
+ br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8)
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ if len(dst) >= maxDecodedSize {
+ br.close()
+ d.bufs.Put(bufs)
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ v := dt[br.peekByteFast()>>shift]
+ nBits := uint8(v.entry)
+ br.advance(nBits)
+ bitsLeft -= int8(nBits)
+ dst = append(dst, uint8(v.entry>>8))
+ }
+ d.bufs.Put(bufs)
+ return dst, br.close()
+}
+
+// decompress1X8Bit will decompress a 1X encoded stream with tablelog <= 8.
+// The cap of the output buffer will be the maximum decompressed size.
+// The length of the supplied input must match the end of a block exactly.
+func (d *Decoder) decompress1X8BitExactly(dst, src []byte) ([]byte, error) {
+ var br bitReaderBytes
+ err := br.init(src)
+ if err != nil {
+ return dst, err
+ }
+ maxDecodedSize := cap(dst)
+ dst = dst[:0]
+
+ // Avoid bounds check by always having full sized table.
+ dt := d.dt.single[:256]
+
+ // Use temp table to avoid bound checks/append penalty.
+ bufs := d.buffer()
+ buf := &bufs[0]
+ var off uint8
+
+ const shift = 56
+
+ //fmt.Printf("mask: %b, tl:%d\n", mask, d.actualTableLog)
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>shift)]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>shift)]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>shift)]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>shift)]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+
+ if len(dst)+int(off) > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:off]...)
+
+ // br < 4, so uint8 is fine
+ bitsLeft := int8(uint8(br.off)*8 + (64 - br.bitsRead))
+ for bitsLeft > 0 {
+ if br.bitsRead >= 64-8 {
+ for br.off > 0 {
+ br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8)
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ if len(dst) >= maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ v := dt[br.peekByteFast()]
+ nBits := uint8(v.entry)
+ br.advance(nBits)
+ bitsLeft -= int8(nBits)
+ dst = append(dst, uint8(v.entry>>8))
+ }
+ d.bufs.Put(bufs)
+ return dst, br.close()
+}
+
+// Decompress4X will decompress a 4X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// The *capacity* of the dst slice must match the destination size of
+// the uncompressed data exactly.
+func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) {
+ if d.actualTableLog == 8 {
+ return d.decompress4X8bitExactly(dst, src)
+ }
+
+ var br [4]bitReaderBytes
+ start := 6
+ for i := range 3 {
+ length := int(src[i*2]) | (int(src[i*2+1]) << 8)
+ if start+length >= len(src) {
+ return nil, errors.New("truncated input (or invalid offset)")
+ }
+ err := br[i].init(src[start : start+length])
+ if err != nil {
+ return nil, err
+ }
+ start += length
+ }
+ err := br[3].init(src[start:])
+ if err != nil {
+ return nil, err
+ }
+
+ // destination, offset to match first output
+ dstSize := cap(dst)
+ dst = dst[:dstSize]
+ out := dst
+ dstEvery := (dstSize + 3) / 4
+
+ shift := (56 + (8 - d.actualTableLog)) & 63
+
+ const tlSize = 1 << 8
+ single := d.dt.single[:tlSize]
+
+ // Use temp table to avoid bound checks/append penalty.
+ buf := d.buffer()
+ var off uint8
+ var decoded int
+
+ // Decode 4 values from each decoder/loop.
+ const bufoff = 256
+ for {
+ if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 {
+ break
+ }
+
+ {
+ // Interleave 2 decodes.
+ const stream = 0
+ const stream2 = 1
+ br1 := &br[stream]
+ br2 := &br[stream2]
+ br1.fillFast()
+ br2.fillFast()
+
+ v := single[uint8(br1.value>>shift)].entry
+ v2 := single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off] = uint8(v >> 8)
+ buf[stream2][off] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+1] = uint8(v >> 8)
+ buf[stream2][off+1] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+2] = uint8(v >> 8)
+ buf[stream2][off+2] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+3] = uint8(v >> 8)
+ buf[stream2][off+3] = uint8(v2 >> 8)
+ }
+
+ {
+ const stream = 2
+ const stream2 = 3
+ br1 := &br[stream]
+ br2 := &br[stream2]
+ br1.fillFast()
+ br2.fillFast()
+
+ v := single[uint8(br1.value>>shift)].entry
+ v2 := single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off] = uint8(v >> 8)
+ buf[stream2][off] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+1] = uint8(v >> 8)
+ buf[stream2][off+1] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+2] = uint8(v >> 8)
+ buf[stream2][off+2] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+3] = uint8(v >> 8)
+ buf[stream2][off+3] = uint8(v2 >> 8)
+ }
+
+ off += 4
+
+ if off == 0 {
+ if bufoff > dstEvery {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 1")
+ }
+ // There must at least be 3 buffers left.
+ if len(out)-bufoff < dstEvery*3 {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 2")
+ }
+ //copy(out, buf[0][:])
+ //copy(out[dstEvery:], buf[1][:])
+ //copy(out[dstEvery*2:], buf[2][:])
+ *(*[bufoff]byte)(out) = buf[0]
+ *(*[bufoff]byte)(out[dstEvery:]) = buf[1]
+ *(*[bufoff]byte)(out[dstEvery*2:]) = buf[2]
+ *(*[bufoff]byte)(out[dstEvery*3:]) = buf[3]
+ out = out[bufoff:]
+ decoded += bufoff * 4
+ }
+ }
+ if off > 0 {
+ ioff := int(off)
+ if len(out) < dstEvery*3+ioff {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 3")
+ }
+ copy(out, buf[0][:off])
+ copy(out[dstEvery:], buf[1][:off])
+ copy(out[dstEvery*2:], buf[2][:off])
+ copy(out[dstEvery*3:], buf[3][:off])
+ decoded += int(off) * 4
+ out = out[off:]
+ }
+
+ // Decode remaining.
+ // Decode remaining.
+ remainBytes := dstEvery - (decoded / 4)
+ for i := range br {
+ offset := dstEvery * i
+ endsAt := min(offset+remainBytes, len(out))
+ br := &br[i]
+ bitsLeft := br.remaining()
+ for bitsLeft > 0 {
+ if br.finished() {
+ d.bufs.Put(buf)
+ return nil, io.ErrUnexpectedEOF
+ }
+ if br.bitsRead >= 56 {
+ if br.off >= 4 {
+ v := br.in[br.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ br.value |= uint64(low) << (br.bitsRead - 32)
+ br.bitsRead -= 32
+ br.off -= 4
+ } else {
+ for br.off > 0 {
+ br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8)
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ }
+ // end inline...
+ if offset >= endsAt {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 4")
+ }
+
+ // Read value and increment offset.
+ v := single[uint8(br.value>>shift)].entry
+ nBits := uint8(v)
+ br.advance(nBits)
+ bitsLeft -= uint(nBits)
+ out[offset] = uint8(v >> 8)
+ offset++
+ }
+ if offset != endsAt {
+ d.bufs.Put(buf)
+ return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
+ }
+ decoded += offset - dstEvery*i
+ err = br.close()
+ if err != nil {
+ d.bufs.Put(buf)
+ return nil, err
+ }
+ }
+ d.bufs.Put(buf)
+ if dstSize != decoded {
+ return nil, errors.New("corruption detected: short output block")
+ }
+ return dst, nil
+}
+
+// Decompress4X will decompress a 4X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// The *capacity* of the dst slice must match the destination size of
+// the uncompressed data exactly.
+func (d *Decoder) decompress4X8bitExactly(dst, src []byte) ([]byte, error) {
+ var br [4]bitReaderBytes
+ start := 6
+ for i := range 3 {
+ length := int(src[i*2]) | (int(src[i*2+1]) << 8)
+ if start+length >= len(src) {
+ return nil, errors.New("truncated input (or invalid offset)")
+ }
+ err := br[i].init(src[start : start+length])
+ if err != nil {
+ return nil, err
+ }
+ start += length
+ }
+ err := br[3].init(src[start:])
+ if err != nil {
+ return nil, err
+ }
+
+ // destination, offset to match first output
+ dstSize := cap(dst)
+ dst = dst[:dstSize]
+ out := dst
+ dstEvery := (dstSize + 3) / 4
+
+ const shift = 56
+ const tlSize = 1 << 8
+ single := d.dt.single[:tlSize]
+
+ // Use temp table to avoid bound checks/append penalty.
+ buf := d.buffer()
+ var off uint8
+ var decoded int
+
+ // Decode 4 values from each decoder/loop.
+ const bufoff = 256
+ for {
+ if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 {
+ break
+ }
+
+ {
+ // Interleave 2 decodes.
+ const stream = 0
+ const stream2 = 1
+ br1 := &br[stream]
+ br2 := &br[stream2]
+ br1.fillFast()
+ br2.fillFast()
+
+ v := single[uint8(br1.value>>shift)].entry
+ v2 := single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off] = uint8(v >> 8)
+ buf[stream2][off] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+1] = uint8(v >> 8)
+ buf[stream2][off+1] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+2] = uint8(v >> 8)
+ buf[stream2][off+2] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+3] = uint8(v >> 8)
+ buf[stream2][off+3] = uint8(v2 >> 8)
+ }
+
+ {
+ const stream = 2
+ const stream2 = 3
+ br1 := &br[stream]
+ br2 := &br[stream2]
+ br1.fillFast()
+ br2.fillFast()
+
+ v := single[uint8(br1.value>>shift)].entry
+ v2 := single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off] = uint8(v >> 8)
+ buf[stream2][off] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+1] = uint8(v >> 8)
+ buf[stream2][off+1] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+2] = uint8(v >> 8)
+ buf[stream2][off+2] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+3] = uint8(v >> 8)
+ buf[stream2][off+3] = uint8(v2 >> 8)
+ }
+
+ off += 4
+
+ if off == 0 {
+ if bufoff > dstEvery {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 1")
+ }
+ // There must at least be 3 buffers left.
+ if len(out)-bufoff < dstEvery*3 {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 2")
+ }
+
+ //copy(out, buf[0][:])
+ //copy(out[dstEvery:], buf[1][:])
+ //copy(out[dstEvery*2:], buf[2][:])
+ // copy(out[dstEvery*3:], buf[3][:])
+ *(*[bufoff]byte)(out) = buf[0]
+ *(*[bufoff]byte)(out[dstEvery:]) = buf[1]
+ *(*[bufoff]byte)(out[dstEvery*2:]) = buf[2]
+ *(*[bufoff]byte)(out[dstEvery*3:]) = buf[3]
+ out = out[bufoff:]
+ decoded += bufoff * 4
+ }
+ }
+ if off > 0 {
+ ioff := int(off)
+ if len(out) < dstEvery*3+ioff {
+ return nil, errors.New("corruption detected: stream overrun 3")
+ }
+ copy(out, buf[0][:off])
+ copy(out[dstEvery:], buf[1][:off])
+ copy(out[dstEvery*2:], buf[2][:off])
+ copy(out[dstEvery*3:], buf[3][:off])
+ decoded += int(off) * 4
+ out = out[off:]
+ }
+
+ // Decode remaining.
+ remainBytes := dstEvery - (decoded / 4)
+ for i := range br {
+ offset := dstEvery * i
+ endsAt := min(offset+remainBytes, len(out))
+ br := &br[i]
+ bitsLeft := br.remaining()
+ for bitsLeft > 0 {
+ if br.finished() {
+ d.bufs.Put(buf)
+ return nil, io.ErrUnexpectedEOF
+ }
+ if br.bitsRead >= 56 {
+ if br.off >= 4 {
+ v := br.in[br.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ br.value |= uint64(low) << (br.bitsRead - 32)
+ br.bitsRead -= 32
+ br.off -= 4
+ } else {
+ for br.off > 0 {
+ br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8)
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ }
+ // end inline...
+ if offset >= endsAt {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 4")
+ }
+
+ // Read value and increment offset.
+ v := single[br.peekByteFast()].entry
+ nBits := uint8(v)
+ br.advance(nBits)
+ bitsLeft -= uint(nBits)
+ out[offset] = uint8(v >> 8)
+ offset++
+ }
+ if offset != endsAt {
+ d.bufs.Put(buf)
+ return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
+ }
+
+ decoded += offset - dstEvery*i
+ err = br.close()
+ if err != nil {
+ d.bufs.Put(buf)
+ return nil, err
+ }
+ }
+ d.bufs.Put(buf)
+ if dstSize != decoded {
+ return nil, errors.New("corruption detected: short output block")
+ }
+ return dst, nil
+}
+
+// matches will compare a decoding table to a coding table.
+// Errors are written to the writer.
+// Nothing will be written if table is ok.
+func (s *Scratch) matches(ct cTable, w io.Writer) {
+ if s == nil || len(s.dt.single) == 0 {
+ return
+ }
+ dt := s.dt.single[:1<>8) == byte(sym) {
+ fmt.Fprintf(w, "symbol %x has decoder, but no encoder\n", sym)
+ errs++
+ break
+ }
+ }
+ if errs == 0 {
+ broken--
+ }
+ continue
+ }
+ // Unused bits in input
+ ub := tablelog - enc.nBits
+ top := enc.val << ub
+ // decoder looks at top bits.
+ dec := dt[top]
+ if uint8(dec.entry) != enc.nBits {
+ fmt.Fprintf(w, "symbol 0x%x bit size mismatch (enc: %d, dec:%d).\n", sym, enc.nBits, uint8(dec.entry))
+ errs++
+ }
+ if uint8(dec.entry>>8) != uint8(sym) {
+ fmt.Fprintf(w, "symbol 0x%x decoder output mismatch (enc: %d, dec:%d).\n", sym, sym, uint8(dec.entry>>8))
+ errs++
+ }
+ if errs > 0 {
+ fmt.Fprintf(w, "%d errors in base, stopping\n", errs)
+ continue
+ }
+ // Ensure that all combinations are covered.
+ for i := uint16(0); i < (1 << ub); i++ {
+ vval := top | i
+ dec := dt[vval]
+ if uint8(dec.entry) != enc.nBits {
+ fmt.Fprintf(w, "symbol 0x%x bit size mismatch (enc: %d, dec:%d).\n", vval, enc.nBits, uint8(dec.entry))
+ errs++
+ }
+ if uint8(dec.entry>>8) != uint8(sym) {
+ fmt.Fprintf(w, "symbol 0x%x decoder output mismatch (enc: %d, dec:%d).\n", vval, sym, uint8(dec.entry>>8))
+ errs++
+ }
+ if errs > 20 {
+ fmt.Fprintf(w, "%d errors, stopping\n", errs)
+ break
+ }
+ }
+ if errs == 0 {
+ ok++
+ broken--
+ }
+ }
+ if broken > 0 {
+ fmt.Fprintf(w, "%d broken, %d ok\n", broken, ok)
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
new file mode 100644
index 00000000000..2d6ef64be15
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
@@ -0,0 +1,222 @@
+//go:build amd64 && !appengine && !noasm && gc
+
+// This file contains the specialisation of Decoder.Decompress4X
+// and Decoder.Decompress1X that use an asm implementation of thir main loops.
+package huff0
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/klauspost/compress/internal/cpuinfo"
+)
+
+// decompress4x_main_loop_x86 is an x86 assembler implementation
+// of Decompress4X when tablelog > 8.
+//
+//go:noescape
+func decompress4x_main_loop_amd64(ctx *decompress4xContext)
+
+// decompress4x_8b_loop_x86 is an x86 assembler implementation
+// of Decompress4X when tablelog <= 8 which decodes 4 entries
+// per loop.
+//
+//go:noescape
+func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext)
+
+// fallback8BitSize is the size where using Go version is faster.
+const fallback8BitSize = 800
+
+type decompress4xContext struct {
+ pbr *[4]bitReaderShifted
+ peekBits uint8
+ out *byte
+ dstEvery int
+ tbl *dEntrySingle
+ decoded int
+ limit *byte
+}
+
+// Decompress4X will decompress a 4X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// The *capacity* of the dst slice must match the destination size of
+// the uncompressed data exactly.
+func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
+ if len(d.dt.single) == 0 {
+ return nil, errors.New("no table loaded")
+ }
+ if len(src) < 6+(4*1) {
+ return nil, errors.New("input too small")
+ }
+
+ use8BitTables := d.actualTableLog <= 8
+ if cap(dst) < fallback8BitSize && use8BitTables {
+ return d.decompress4X8bit(dst, src)
+ }
+
+ var br [4]bitReaderShifted
+ // Decode "jump table"
+ start := 6
+ for i := range 3 {
+ length := int(src[i*2]) | (int(src[i*2+1]) << 8)
+ if start+length >= len(src) {
+ return nil, errors.New("truncated input (or invalid offset)")
+ }
+ err := br[i].init(src[start : start+length])
+ if err != nil {
+ return nil, err
+ }
+ start += length
+ }
+ err := br[3].init(src[start:])
+ if err != nil {
+ return nil, err
+ }
+
+ // destination, offset to match first output
+ dstSize := cap(dst)
+ dst = dst[:dstSize]
+ out := dst
+ dstEvery := (dstSize + 3) / 4
+
+ const tlSize = 1 << tableLogMax
+ const tlMask = tlSize - 1
+ single := d.dt.single[:tlSize]
+
+ var decoded int
+
+ if len(out) > 4*4 && !(br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4) {
+ ctx := decompress4xContext{
+ pbr: &br,
+ peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
+ out: &out[0],
+ dstEvery: dstEvery,
+ tbl: &single[0],
+ limit: &out[dstEvery-4], // Always stop decoding when first buffer gets here to avoid writing OOB on last.
+ }
+ if use8BitTables {
+ decompress4x_8b_main_loop_amd64(&ctx)
+ } else {
+ decompress4x_main_loop_amd64(&ctx)
+ }
+
+ decoded = ctx.decoded
+ out = out[decoded/4:]
+ }
+
+ // Decode remaining.
+ remainBytes := dstEvery - (decoded / 4)
+ for i := range br {
+ offset := dstEvery * i
+ endsAt := min(offset+remainBytes, len(out))
+ br := &br[i]
+ bitsLeft := br.remaining()
+ for bitsLeft > 0 {
+ br.fill()
+ if offset >= endsAt {
+ return nil, errors.New("corruption detected: stream overrun 4")
+ }
+
+ // Read value and increment offset.
+ val := br.peekBitsFast(d.actualTableLog)
+ v := single[val&tlMask].entry
+ nBits := uint8(v)
+ br.advance(nBits)
+ bitsLeft -= uint(nBits)
+ out[offset] = uint8(v >> 8)
+ offset++
+ }
+ if offset != endsAt {
+ return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
+ }
+ decoded += offset - dstEvery*i
+ err = br.close()
+ if err != nil {
+ return nil, err
+ }
+ }
+ if dstSize != decoded {
+ return nil, errors.New("corruption detected: short output block")
+ }
+ return dst, nil
+}
+
+// decompress4x_main_loop_x86 is an x86 assembler implementation
+// of Decompress1X when tablelog > 8.
+//
+//go:noescape
+func decompress1x_main_loop_amd64(ctx *decompress1xContext)
+
+// decompress4x_main_loop_x86 is an x86 with BMI2 assembler implementation
+// of Decompress1X when tablelog > 8.
+//
+//go:noescape
+func decompress1x_main_loop_bmi2(ctx *decompress1xContext)
+
+type decompress1xContext struct {
+ pbr *bitReaderShifted
+ peekBits uint8
+ out *byte
+ outCap int
+ tbl *dEntrySingle
+ decoded int
+}
+
+// Error reported by asm implementations
+const error_max_decoded_size_exeeded = -1
+
+// Decompress1X will decompress a 1X encoded stream.
+// The cap of the output buffer will be the maximum decompressed size.
+// The length of the supplied input must match the end of a block exactly.
+func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
+ if len(d.dt.single) == 0 {
+ return nil, errors.New("no table loaded")
+ }
+ var br bitReaderShifted
+ err := br.init(src)
+ if err != nil {
+ return dst, err
+ }
+ maxDecodedSize := cap(dst)
+ dst = dst[:maxDecodedSize]
+
+ const tlSize = 1 << tableLogMax
+ const tlMask = tlSize - 1
+
+ if maxDecodedSize >= 4 {
+ ctx := decompress1xContext{
+ pbr: &br,
+ out: &dst[0],
+ outCap: maxDecodedSize,
+ peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
+ tbl: &d.dt.single[0],
+ }
+
+ if cpuinfo.HasBMI2() {
+ decompress1x_main_loop_bmi2(&ctx)
+ } else {
+ decompress1x_main_loop_amd64(&ctx)
+ }
+ if ctx.decoded == error_max_decoded_size_exeeded {
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+
+ dst = dst[:ctx.decoded]
+ }
+
+ // br < 8, so uint8 is fine
+ bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
+ for bitsLeft > 0 {
+ br.fill()
+ if len(dst) >= maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
+ nBits := uint8(v.entry)
+ br.advance(nBits)
+ bitsLeft -= nBits
+ dst = append(dst, uint8(v.entry>>8))
+ }
+ return dst, br.close()
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s
new file mode 100644
index 00000000000..c4c7ab2d1fe
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s
@@ -0,0 +1,830 @@
+// Code generated by command: go run gen.go -out ../decompress_amd64.s -pkg=huff0. DO NOT EDIT.
+
+//go:build amd64 && !appengine && !noasm && gc
+
+// func decompress4x_main_loop_amd64(ctx *decompress4xContext)
+TEXT ·decompress4x_main_loop_amd64(SB), $0-8
+ // Preload values
+ MOVQ ctx+0(FP), AX
+ MOVBQZX 8(AX), DI
+ MOVQ 16(AX), BX
+ MOVQ 48(AX), SI
+ MOVQ 24(AX), R8
+ MOVQ 32(AX), R9
+ MOVQ (AX), R10
+
+ // Main loop
+main_loop:
+ XORL DX, DX
+ CMPQ BX, SI
+ SETGE DL
+
+ // br0.fillFast32()
+ MOVQ 32(R10), R11
+ MOVBQZX 40(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill0
+ MOVQ 24(R10), AX
+ SUBQ $0x20, R12
+ SUBQ $0x04, AX
+ MOVQ (R10), R13
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (AX)(R13*1), R13
+ MOVQ R12, CX
+ SHLQ CL, R13
+ MOVQ AX, 24(R10)
+ ORQ R13, R11
+
+ // exhausted += (br0.off < 4)
+ CMPQ AX, $0x04
+ ADCB $+0, DL
+
+skip_fill0:
+ // val0 := br0.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br0.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br0.peekTopBits(peekBits)
+ MOVQ DI, CX
+ MOVQ R11, R13
+ SHRQ CL, R13
+
+ // v1 := table[val1&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br0.advance(uint8(v1.entry))
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // these two writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ MOVW AX, (BX)
+
+ // update the bitreader structure
+ MOVQ R11, 32(R10)
+ MOVB R12, 40(R10)
+
+ // br1.fillFast32()
+ MOVQ 80(R10), R11
+ MOVBQZX 88(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill1
+ MOVQ 72(R10), AX
+ SUBQ $0x20, R12
+ SUBQ $0x04, AX
+ MOVQ 48(R10), R13
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (AX)(R13*1), R13
+ MOVQ R12, CX
+ SHLQ CL, R13
+ MOVQ AX, 72(R10)
+ ORQ R13, R11
+
+ // exhausted += (br1.off < 4)
+ CMPQ AX, $0x04
+ ADCB $+0, DL
+
+skip_fill1:
+ // val0 := br1.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br1.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br1.peekTopBits(peekBits)
+ MOVQ DI, CX
+ MOVQ R11, R13
+ SHRQ CL, R13
+
+ // v1 := table[val1&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br1.advance(uint8(v1.entry))
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // these two writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ MOVW AX, (BX)(R8*1)
+
+ // update the bitreader structure
+ MOVQ R11, 80(R10)
+ MOVB R12, 88(R10)
+
+ // br2.fillFast32()
+ MOVQ 128(R10), R11
+ MOVBQZX 136(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill2
+ MOVQ 120(R10), AX
+ SUBQ $0x20, R12
+ SUBQ $0x04, AX
+ MOVQ 96(R10), R13
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (AX)(R13*1), R13
+ MOVQ R12, CX
+ SHLQ CL, R13
+ MOVQ AX, 120(R10)
+ ORQ R13, R11
+
+ // exhausted += (br2.off < 4)
+ CMPQ AX, $0x04
+ ADCB $+0, DL
+
+skip_fill2:
+ // val0 := br2.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br2.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br2.peekTopBits(peekBits)
+ MOVQ DI, CX
+ MOVQ R11, R13
+ SHRQ CL, R13
+
+ // v1 := table[val1&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br2.advance(uint8(v1.entry))
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // these two writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ MOVW AX, (BX)(R8*2)
+
+ // update the bitreader structure
+ MOVQ R11, 128(R10)
+ MOVB R12, 136(R10)
+
+ // br3.fillFast32()
+ MOVQ 176(R10), R11
+ MOVBQZX 184(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill3
+ MOVQ 168(R10), AX
+ SUBQ $0x20, R12
+ SUBQ $0x04, AX
+ MOVQ 144(R10), R13
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (AX)(R13*1), R13
+ MOVQ R12, CX
+ SHLQ CL, R13
+ MOVQ AX, 168(R10)
+ ORQ R13, R11
+
+ // exhausted += (br3.off < 4)
+ CMPQ AX, $0x04
+ ADCB $+0, DL
+
+skip_fill3:
+ // val0 := br3.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br3.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br3.peekTopBits(peekBits)
+ MOVQ DI, CX
+ MOVQ R11, R13
+ SHRQ CL, R13
+
+ // v1 := table[val1&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br3.advance(uint8(v1.entry))
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // these two writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ LEAQ (R8)(R8*2), CX
+ MOVW AX, (BX)(CX*1)
+
+ // update the bitreader structure
+ MOVQ R11, 176(R10)
+ MOVB R12, 184(R10)
+ ADDQ $0x02, BX
+ TESTB DL, DL
+ JZ main_loop
+ MOVQ ctx+0(FP), AX
+ SUBQ 16(AX), BX
+ SHLQ $0x02, BX
+ MOVQ BX, 40(AX)
+ RET
+
+// func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext)
+TEXT ·decompress4x_8b_main_loop_amd64(SB), $0-8
+ // Preload values
+ MOVQ ctx+0(FP), CX
+ MOVBQZX 8(CX), DI
+ MOVQ 16(CX), BX
+ MOVQ 48(CX), SI
+ MOVQ 24(CX), R8
+ MOVQ 32(CX), R9
+ MOVQ (CX), R10
+
+ // Main loop
+main_loop:
+ XORL DX, DX
+ CMPQ BX, SI
+ SETGE DL
+
+ // br0.fillFast32()
+ MOVQ 32(R10), R11
+ MOVBQZX 40(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill0
+ MOVQ 24(R10), R13
+ SUBQ $0x20, R12
+ SUBQ $0x04, R13
+ MOVQ (R10), R14
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (R13)(R14*1), R14
+ MOVQ R12, CX
+ SHLQ CL, R14
+ MOVQ R13, 24(R10)
+ ORQ R14, R11
+
+ // exhausted += (br0.off < 4)
+ CMPQ R13, $0x04
+ ADCB $+0, DL
+
+skip_fill0:
+ // val0 := br0.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br0.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br0.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v1 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br0.advance(uint8(v1.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // val2 := br0.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v2 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br0.advance(uint8(v2.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val3 := br0.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v3 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br0.advance(uint8(v3.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // these four writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ // out[id * dstEvery + 3] = uint8(v2.entry >> 8)
+ // out[id * dstEvery + 4] = uint8(v3.entry >> 8)
+ MOVL AX, (BX)
+
+ // update the bitreader structure
+ MOVQ R11, 32(R10)
+ MOVB R12, 40(R10)
+
+ // br1.fillFast32()
+ MOVQ 80(R10), R11
+ MOVBQZX 88(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill1
+ MOVQ 72(R10), R13
+ SUBQ $0x20, R12
+ SUBQ $0x04, R13
+ MOVQ 48(R10), R14
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (R13)(R14*1), R14
+ MOVQ R12, CX
+ SHLQ CL, R14
+ MOVQ R13, 72(R10)
+ ORQ R14, R11
+
+ // exhausted += (br1.off < 4)
+ CMPQ R13, $0x04
+ ADCB $+0, DL
+
+skip_fill1:
+ // val0 := br1.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br1.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br1.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v1 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br1.advance(uint8(v1.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // val2 := br1.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v2 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br1.advance(uint8(v2.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val3 := br1.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v3 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br1.advance(uint8(v3.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // these four writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ // out[id * dstEvery + 3] = uint8(v2.entry >> 8)
+ // out[id * dstEvery + 4] = uint8(v3.entry >> 8)
+ MOVL AX, (BX)(R8*1)
+
+ // update the bitreader structure
+ MOVQ R11, 80(R10)
+ MOVB R12, 88(R10)
+
+ // br2.fillFast32()
+ MOVQ 128(R10), R11
+ MOVBQZX 136(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill2
+ MOVQ 120(R10), R13
+ SUBQ $0x20, R12
+ SUBQ $0x04, R13
+ MOVQ 96(R10), R14
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (R13)(R14*1), R14
+ MOVQ R12, CX
+ SHLQ CL, R14
+ MOVQ R13, 120(R10)
+ ORQ R14, R11
+
+ // exhausted += (br2.off < 4)
+ CMPQ R13, $0x04
+ ADCB $+0, DL
+
+skip_fill2:
+ // val0 := br2.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br2.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br2.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v1 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br2.advance(uint8(v1.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // val2 := br2.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v2 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br2.advance(uint8(v2.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val3 := br2.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v3 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br2.advance(uint8(v3.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // these four writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ // out[id * dstEvery + 3] = uint8(v2.entry >> 8)
+ // out[id * dstEvery + 4] = uint8(v3.entry >> 8)
+ MOVL AX, (BX)(R8*2)
+
+ // update the bitreader structure
+ MOVQ R11, 128(R10)
+ MOVB R12, 136(R10)
+
+ // br3.fillFast32()
+ MOVQ 176(R10), R11
+ MOVBQZX 184(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill3
+ MOVQ 168(R10), R13
+ SUBQ $0x20, R12
+ SUBQ $0x04, R13
+ MOVQ 144(R10), R14
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (R13)(R14*1), R14
+ MOVQ R12, CX
+ SHLQ CL, R14
+ MOVQ R13, 168(R10)
+ ORQ R14, R11
+
+ // exhausted += (br3.off < 4)
+ CMPQ R13, $0x04
+ ADCB $+0, DL
+
+skip_fill3:
+ // val0 := br3.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br3.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br3.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v1 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br3.advance(uint8(v1.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // val2 := br3.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v2 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br3.advance(uint8(v2.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val3 := br3.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v3 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br3.advance(uint8(v3.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // these four writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ // out[id * dstEvery + 3] = uint8(v2.entry >> 8)
+ // out[id * dstEvery + 4] = uint8(v3.entry >> 8)
+ LEAQ (R8)(R8*2), CX
+ MOVL AX, (BX)(CX*1)
+
+ // update the bitreader structure
+ MOVQ R11, 176(R10)
+ MOVB R12, 184(R10)
+ ADDQ $0x04, BX
+ TESTB DL, DL
+ JZ main_loop
+ MOVQ ctx+0(FP), AX
+ SUBQ 16(AX), BX
+ SHLQ $0x02, BX
+ MOVQ BX, 40(AX)
+ RET
+
+// func decompress1x_main_loop_amd64(ctx *decompress1xContext)
+TEXT ·decompress1x_main_loop_amd64(SB), $0-8
+ MOVQ ctx+0(FP), CX
+ MOVQ 16(CX), DX
+ MOVQ 24(CX), BX
+ CMPQ BX, $0x04
+ JB error_max_decoded_size_exceeded
+ LEAQ (DX)(BX*1), BX
+ MOVQ (CX), SI
+ MOVQ (SI), R8
+ MOVQ 24(SI), R9
+ MOVQ 32(SI), R10
+ MOVBQZX 40(SI), R11
+ MOVQ 32(CX), SI
+ MOVBQZX 8(CX), DI
+ JMP loop_condition
+
+main_loop:
+ // Check if we have room for 4 bytes in the output buffer
+ LEAQ 4(DX), CX
+ CMPQ CX, BX
+ JGE error_max_decoded_size_exceeded
+
+ // Decode 4 values
+ CMPQ R11, $0x20
+ JL bitReader_fillFast_1_end
+ SUBQ $0x20, R11
+ SUBQ $0x04, R9
+ MOVL (R8)(R9*1), R12
+ MOVQ R11, CX
+ SHLQ CL, R12
+ ORQ R12, R10
+
+bitReader_fillFast_1_end:
+ MOVQ DI, CX
+ MOVQ R10, R12
+ SHRQ CL, R12
+ MOVW (SI)(R12*2), CX
+ MOVB CH, AL
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLQ CL, R10
+ MOVQ DI, CX
+ MOVQ R10, R12
+ SHRQ CL, R12
+ MOVW (SI)(R12*2), CX
+ MOVB CH, AH
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLQ CL, R10
+ BSWAPL AX
+ CMPQ R11, $0x20
+ JL bitReader_fillFast_2_end
+ SUBQ $0x20, R11
+ SUBQ $0x04, R9
+ MOVL (R8)(R9*1), R12
+ MOVQ R11, CX
+ SHLQ CL, R12
+ ORQ R12, R10
+
+bitReader_fillFast_2_end:
+ MOVQ DI, CX
+ MOVQ R10, R12
+ SHRQ CL, R12
+ MOVW (SI)(R12*2), CX
+ MOVB CH, AH
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLQ CL, R10
+ MOVQ DI, CX
+ MOVQ R10, R12
+ SHRQ CL, R12
+ MOVW (SI)(R12*2), CX
+ MOVB CH, AL
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLQ CL, R10
+ BSWAPL AX
+
+ // Store the decoded values
+ MOVL AX, (DX)
+ ADDQ $0x04, DX
+
+loop_condition:
+ CMPQ R9, $0x08
+ JGE main_loop
+
+ // Update ctx structure
+ MOVQ ctx+0(FP), AX
+ SUBQ 16(AX), DX
+ MOVQ DX, 40(AX)
+ MOVQ (AX), AX
+ MOVQ R9, 24(AX)
+ MOVQ R10, 32(AX)
+ MOVB R11, 40(AX)
+ RET
+
+ // Report error
+error_max_decoded_size_exceeded:
+ MOVQ ctx+0(FP), AX
+ MOVQ $-1, CX
+ MOVQ CX, 40(AX)
+ RET
+
+// func decompress1x_main_loop_bmi2(ctx *decompress1xContext)
+// Requires: BMI2
+TEXT ·decompress1x_main_loop_bmi2(SB), $0-8
+ MOVQ ctx+0(FP), CX
+ MOVQ 16(CX), DX
+ MOVQ 24(CX), BX
+ CMPQ BX, $0x04
+ JB error_max_decoded_size_exceeded
+ LEAQ (DX)(BX*1), BX
+ MOVQ (CX), SI
+ MOVQ (SI), R8
+ MOVQ 24(SI), R9
+ MOVQ 32(SI), R10
+ MOVBQZX 40(SI), R11
+ MOVQ 32(CX), SI
+ MOVBQZX 8(CX), DI
+ JMP loop_condition
+
+main_loop:
+ // Check if we have room for 4 bytes in the output buffer
+ LEAQ 4(DX), CX
+ CMPQ CX, BX
+ JGE error_max_decoded_size_exceeded
+
+ // Decode 4 values
+ CMPQ R11, $0x20
+ JL bitReader_fillFast_1_end
+ SUBQ $0x20, R11
+ SUBQ $0x04, R9
+ MOVL (R8)(R9*1), CX
+ SHLXQ R11, CX, CX
+ ORQ CX, R10
+
+bitReader_fillFast_1_end:
+ SHRXQ DI, R10, CX
+ MOVW (SI)(CX*2), CX
+ MOVB CH, AL
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLXQ CX, R10, R10
+ SHRXQ DI, R10, CX
+ MOVW (SI)(CX*2), CX
+ MOVB CH, AH
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLXQ CX, R10, R10
+ BSWAPL AX
+ CMPQ R11, $0x20
+ JL bitReader_fillFast_2_end
+ SUBQ $0x20, R11
+ SUBQ $0x04, R9
+ MOVL (R8)(R9*1), CX
+ SHLXQ R11, CX, CX
+ ORQ CX, R10
+
+bitReader_fillFast_2_end:
+ SHRXQ DI, R10, CX
+ MOVW (SI)(CX*2), CX
+ MOVB CH, AH
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLXQ CX, R10, R10
+ SHRXQ DI, R10, CX
+ MOVW (SI)(CX*2), CX
+ MOVB CH, AL
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLXQ CX, R10, R10
+ BSWAPL AX
+
+ // Store the decoded values
+ MOVL AX, (DX)
+ ADDQ $0x04, DX
+
+loop_condition:
+ CMPQ R9, $0x08
+ JGE main_loop
+
+ // Update ctx structure
+ MOVQ ctx+0(FP), AX
+ SUBQ 16(AX), DX
+ MOVQ DX, 40(AX)
+ MOVQ (AX), AX
+ MOVQ R9, 24(AX)
+ MOVQ R10, 32(AX)
+ MOVB R11, 40(AX)
+ RET
+
+ // Report error
+error_max_decoded_size_exceeded:
+ MOVQ ctx+0(FP), AX
+ MOVQ $-1, CX
+ MOVQ CX, 40(AX)
+ RET
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_generic.go b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go
new file mode 100644
index 00000000000..61039232224
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go
@@ -0,0 +1,298 @@
+//go:build !amd64 || appengine || !gc || noasm
+
+// This file contains a generic implementation of Decoder.Decompress4X.
+package huff0
+
+import (
+ "errors"
+ "fmt"
+)
+
+// Decompress4X will decompress a 4X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// The *capacity* of the dst slice must match the destination size of
+// the uncompressed data exactly.
+func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
+ if len(d.dt.single) == 0 {
+ return nil, errors.New("no table loaded")
+ }
+ if len(src) < 6+(4*1) {
+ return nil, errors.New("input too small")
+ }
+ if use8BitTables && d.actualTableLog <= 8 {
+ return d.decompress4X8bit(dst, src)
+ }
+
+ var br [4]bitReaderShifted
+ // Decode "jump table"
+ start := 6
+ for i := 0; i < 3; i++ {
+ length := int(src[i*2]) | (int(src[i*2+1]) << 8)
+ if start+length >= len(src) {
+ return nil, errors.New("truncated input (or invalid offset)")
+ }
+ err := br[i].init(src[start : start+length])
+ if err != nil {
+ return nil, err
+ }
+ start += length
+ }
+ err := br[3].init(src[start:])
+ if err != nil {
+ return nil, err
+ }
+
+ // destination, offset to match first output
+ dstSize := cap(dst)
+ dst = dst[:dstSize]
+ out := dst
+ dstEvery := (dstSize + 3) / 4
+
+ const tlSize = 1 << tableLogMax
+ const tlMask = tlSize - 1
+ single := d.dt.single[:tlSize]
+
+ // Use temp table to avoid bound checks/append penalty.
+ buf := d.buffer()
+ var off uint8
+ var decoded int
+
+ // Decode 2 values from each decoder/loop.
+ const bufoff = 256
+ for {
+ if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 {
+ break
+ }
+
+ {
+ const stream = 0
+ const stream2 = 1
+ br[stream].fillFast()
+ br[stream2].fillFast()
+
+ val := br[stream].peekBitsFast(d.actualTableLog)
+ val2 := br[stream2].peekBitsFast(d.actualTableLog)
+ v := single[val&tlMask]
+ v2 := single[val2&tlMask]
+ br[stream].advance(uint8(v.entry))
+ br[stream2].advance(uint8(v2.entry))
+ buf[stream][off] = uint8(v.entry >> 8)
+ buf[stream2][off] = uint8(v2.entry >> 8)
+
+ val = br[stream].peekBitsFast(d.actualTableLog)
+ val2 = br[stream2].peekBitsFast(d.actualTableLog)
+ v = single[val&tlMask]
+ v2 = single[val2&tlMask]
+ br[stream].advance(uint8(v.entry))
+ br[stream2].advance(uint8(v2.entry))
+ buf[stream][off+1] = uint8(v.entry >> 8)
+ buf[stream2][off+1] = uint8(v2.entry >> 8)
+ }
+
+ {
+ const stream = 2
+ const stream2 = 3
+ br[stream].fillFast()
+ br[stream2].fillFast()
+
+ val := br[stream].peekBitsFast(d.actualTableLog)
+ val2 := br[stream2].peekBitsFast(d.actualTableLog)
+ v := single[val&tlMask]
+ v2 := single[val2&tlMask]
+ br[stream].advance(uint8(v.entry))
+ br[stream2].advance(uint8(v2.entry))
+ buf[stream][off] = uint8(v.entry >> 8)
+ buf[stream2][off] = uint8(v2.entry >> 8)
+
+ val = br[stream].peekBitsFast(d.actualTableLog)
+ val2 = br[stream2].peekBitsFast(d.actualTableLog)
+ v = single[val&tlMask]
+ v2 = single[val2&tlMask]
+ br[stream].advance(uint8(v.entry))
+ br[stream2].advance(uint8(v2.entry))
+ buf[stream][off+1] = uint8(v.entry >> 8)
+ buf[stream2][off+1] = uint8(v2.entry >> 8)
+ }
+
+ off += 2
+
+ if off == 0 {
+ if bufoff > dstEvery {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 1")
+ }
+ // There must at least be 3 buffers left.
+ if len(out)-bufoff < dstEvery*3 {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 2")
+ }
+ //copy(out, buf[0][:])
+ //copy(out[dstEvery:], buf[1][:])
+ //copy(out[dstEvery*2:], buf[2][:])
+ //copy(out[dstEvery*3:], buf[3][:])
+ *(*[bufoff]byte)(out) = buf[0]
+ *(*[bufoff]byte)(out[dstEvery:]) = buf[1]
+ *(*[bufoff]byte)(out[dstEvery*2:]) = buf[2]
+ *(*[bufoff]byte)(out[dstEvery*3:]) = buf[3]
+ out = out[bufoff:]
+ decoded += bufoff * 4
+ }
+ }
+ if off > 0 {
+ ioff := int(off)
+ if len(out) < dstEvery*3+ioff {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 3")
+ }
+ copy(out, buf[0][:off])
+ copy(out[dstEvery:], buf[1][:off])
+ copy(out[dstEvery*2:], buf[2][:off])
+ copy(out[dstEvery*3:], buf[3][:off])
+ decoded += int(off) * 4
+ out = out[off:]
+ }
+
+ // Decode remaining.
+ remainBytes := dstEvery - (decoded / 4)
+ for i := range br {
+ offset := dstEvery * i
+ endsAt := offset + remainBytes
+ if endsAt > len(out) {
+ endsAt = len(out)
+ }
+ br := &br[i]
+ bitsLeft := br.remaining()
+ for bitsLeft > 0 {
+ br.fill()
+ if offset >= endsAt {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 4")
+ }
+
+ // Read value and increment offset.
+ val := br.peekBitsFast(d.actualTableLog)
+ v := single[val&tlMask].entry
+ nBits := uint8(v)
+ br.advance(nBits)
+ bitsLeft -= uint(nBits)
+ out[offset] = uint8(v >> 8)
+ offset++
+ }
+ if offset != endsAt {
+ d.bufs.Put(buf)
+ return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
+ }
+ decoded += offset - dstEvery*i
+ err = br.close()
+ if err != nil {
+ return nil, err
+ }
+ }
+ d.bufs.Put(buf)
+ if dstSize != decoded {
+ return nil, errors.New("corruption detected: short output block")
+ }
+ return dst, nil
+}
+
+// Decompress1X will decompress a 1X encoded stream.
+// The cap of the output buffer will be the maximum decompressed size.
+// The length of the supplied input must match the end of a block exactly.
+func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
+ if len(d.dt.single) == 0 {
+ return nil, errors.New("no table loaded")
+ }
+ if use8BitTables && d.actualTableLog <= 8 {
+ return d.decompress1X8Bit(dst, src)
+ }
+ var br bitReaderShifted
+ err := br.init(src)
+ if err != nil {
+ return dst, err
+ }
+ maxDecodedSize := cap(dst)
+ dst = dst[:0]
+
+ // Avoid bounds check by always having full sized table.
+ const tlSize = 1 << tableLogMax
+ const tlMask = tlSize - 1
+ dt := d.dt.single[:tlSize]
+
+ // Use temp table to avoid bound checks/append penalty.
+ bufs := d.buffer()
+ buf := &bufs[0]
+ var off uint8
+
+ for br.off >= 8 {
+ br.fillFast()
+ v := dt[br.peekBitsFast(d.actualTableLog)&tlMask]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ // Refill
+ br.fillFast()
+
+ v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ d.bufs.Put(bufs)
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+
+ if len(dst)+int(off) > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:off]...)
+
+ // br < 8, so uint8 is fine
+ bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
+ for bitsLeft > 0 {
+ br.fill()
+ if false && br.bitsRead >= 32 {
+ if br.off >= 4 {
+ v := br.in[br.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ br.value = (br.value << 32) | uint64(low)
+ br.bitsRead -= 32
+ br.off -= 4
+ } else {
+ for br.off > 0 {
+ br.value = (br.value << 8) | uint64(br.in[br.off-1])
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ }
+ if len(dst) >= maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
+ nBits := uint8(v.entry)
+ br.advance(nBits)
+ bitsLeft -= nBits
+ dst = append(dst, uint8(v.entry>>8))
+ }
+ d.bufs.Put(bufs)
+ return dst, br.close()
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/huff0.go b/vendor/github.com/klauspost/compress/huff0/huff0.go
new file mode 100644
index 00000000000..67d9e05b6cc
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/huff0.go
@@ -0,0 +1,337 @@
+// Package huff0 provides fast huffman encoding as used in zstd.
+//
+// See README.md at https://github.com/klauspost/compress/tree/master/huff0 for details.
+package huff0
+
+import (
+ "errors"
+ "fmt"
+ "math"
+ "math/bits"
+ "sync"
+
+ "github.com/klauspost/compress/fse"
+)
+
+const (
+ maxSymbolValue = 255
+
+ // zstandard limits tablelog to 11, see:
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#huffman-tree-description
+ tableLogMax = 11
+ tableLogDefault = 11
+ minTablelog = 5
+ huffNodesLen = 512
+
+ // BlockSizeMax is maximum input size for a single block uncompressed.
+ BlockSizeMax = 1<<18 - 1
+)
+
+var (
+ // ErrIncompressible is returned when input is judged to be too hard to compress.
+ ErrIncompressible = errors.New("input is not compressible")
+
+ // ErrUseRLE is returned from the compressor when the input is a single byte value repeated.
+ ErrUseRLE = errors.New("input is single value repeated")
+
+ // ErrTooBig is return if input is too large for a single block.
+ ErrTooBig = errors.New("input too big")
+
+ // ErrMaxDecodedSizeExceeded is return if input is too large for a single block.
+ ErrMaxDecodedSizeExceeded = errors.New("maximum output size exceeded")
+)
+
+type ReusePolicy uint8
+
+const (
+ // ReusePolicyAllow will allow reuse if it produces smaller output.
+ ReusePolicyAllow ReusePolicy = iota
+
+ // ReusePolicyPrefer will re-use aggressively if possible.
+ // This will not check if a new table will produce smaller output,
+ // except if the current table is impossible to use or
+ // compressed output is bigger than input.
+ ReusePolicyPrefer
+
+ // ReusePolicyNone will disable re-use of tables.
+ // This is slightly faster than ReusePolicyAllow but may produce larger output.
+ ReusePolicyNone
+
+ // ReusePolicyMust must allow reuse and produce smaller output.
+ ReusePolicyMust
+)
+
+type Scratch struct {
+ count [maxSymbolValue + 1]uint32
+
+ // Per block parameters.
+ // These can be used to override compression parameters of the block.
+ // Do not touch, unless you know what you are doing.
+
+ // Out is output buffer.
+ // If the scratch is re-used before the caller is done processing the output,
+ // set this field to nil.
+ // Otherwise the output buffer will be re-used for next Compression/Decompression step
+ // and allocation will be avoided.
+ Out []byte
+
+ // OutTable will contain the table data only, if a new table has been generated.
+ // Slice of the returned data.
+ OutTable []byte
+
+ // OutData will contain the compressed data.
+ // Slice of the returned data.
+ OutData []byte
+
+ // MaxDecodedSize will set the maximum allowed output size.
+ // This value will automatically be set to BlockSizeMax if not set.
+ // Decoders will return ErrMaxDecodedSizeExceeded is this limit is exceeded.
+ MaxDecodedSize int
+
+ srcLen int
+
+ // MaxSymbolValue will override the maximum symbol value of the next block.
+ MaxSymbolValue uint8
+
+ // TableLog will attempt to override the tablelog for the next block.
+ // Must be <= 11 and >= 5.
+ TableLog uint8
+
+ // Reuse will specify the reuse policy
+ Reuse ReusePolicy
+
+ // WantLogLess allows to specify a log 2 reduction that should at least be achieved,
+ // otherwise the block will be returned as incompressible.
+ // The reduction should then at least be (input size >> WantLogLess)
+ // If WantLogLess == 0 any improvement will do.
+ WantLogLess uint8
+
+ symbolLen uint16 // Length of active part of the symbol table.
+ maxCount int // count of the most probable symbol
+ clearCount bool // clear count
+ actualTableLog uint8 // Selected tablelog.
+ prevTableLog uint8 // Tablelog for previous table
+ prevTable cTable // Table used for previous compression.
+ cTable cTable // compression table
+ dt dTable // decompression table
+ nodes []nodeElt
+ tmpOut [4][]byte
+ fse *fse.Scratch
+ decPool sync.Pool // *[4][256]byte buffers.
+ huffWeight [maxSymbolValue + 1]byte
+}
+
+// TransferCTable will transfer the previously used compression table.
+func (s *Scratch) TransferCTable(src *Scratch) {
+ if cap(s.prevTable) < len(src.prevTable) {
+ s.prevTable = make(cTable, 0, maxSymbolValue+1)
+ }
+ s.prevTable = s.prevTable[:len(src.prevTable)]
+ copy(s.prevTable, src.prevTable)
+ s.prevTableLog = src.prevTableLog
+}
+
+func (s *Scratch) prepare(in []byte) (*Scratch, error) {
+ if len(in) > BlockSizeMax {
+ return nil, ErrTooBig
+ }
+ if s == nil {
+ s = &Scratch{}
+ }
+ if s.MaxSymbolValue == 0 {
+ s.MaxSymbolValue = maxSymbolValue
+ }
+ if s.TableLog == 0 {
+ s.TableLog = tableLogDefault
+ }
+ if s.TableLog > tableLogMax || s.TableLog < minTablelog {
+ return nil, fmt.Errorf(" invalid tableLog %d (%d -> %d)", s.TableLog, minTablelog, tableLogMax)
+ }
+ if s.MaxDecodedSize <= 0 || s.MaxDecodedSize > BlockSizeMax {
+ s.MaxDecodedSize = BlockSizeMax
+ }
+ if s.clearCount && s.maxCount == 0 {
+ for i := range s.count {
+ s.count[i] = 0
+ }
+ s.clearCount = false
+ }
+ if cap(s.Out) == 0 {
+ s.Out = make([]byte, 0, len(in))
+ }
+ s.Out = s.Out[:0]
+
+ s.OutTable = nil
+ s.OutData = nil
+ if cap(s.nodes) < huffNodesLen+1 {
+ s.nodes = make([]nodeElt, 0, huffNodesLen+1)
+ }
+ s.nodes = s.nodes[:0]
+ if s.fse == nil {
+ s.fse = &fse.Scratch{}
+ }
+ s.srcLen = len(in)
+
+ return s, nil
+}
+
+type cTable []cTableEntry
+
+func (c cTable) write(s *Scratch) error {
+ var (
+ // precomputed conversion table
+ bitsToWeight [tableLogMax + 1]byte
+ huffLog = s.actualTableLog
+ // last weight is not saved.
+ maxSymbolValue = uint8(s.symbolLen - 1)
+ huffWeight = s.huffWeight[:256]
+ )
+ const (
+ maxFSETableLog = 6
+ )
+ // convert to weight
+ bitsToWeight[0] = 0
+ for n := uint8(1); n < huffLog+1; n++ {
+ bitsToWeight[n] = huffLog + 1 - n
+ }
+
+ // Acquire histogram for FSE.
+ hist := s.fse.Histogram()
+ hist = hist[:256]
+ for i := range hist[:16] {
+ hist[i] = 0
+ }
+ for n := range maxSymbolValue {
+ v := bitsToWeight[c[n].nBits] & 15
+ huffWeight[n] = v
+ hist[v]++
+ }
+
+ // FSE compress if feasible.
+ if maxSymbolValue >= 2 {
+ huffMaxCnt := uint32(0)
+ huffMax := uint8(0)
+ for i, v := range hist[:16] {
+ if v == 0 {
+ continue
+ }
+ huffMax = byte(i)
+ if v > huffMaxCnt {
+ huffMaxCnt = v
+ }
+ }
+ s.fse.HistogramFinished(huffMax, int(huffMaxCnt))
+ s.fse.TableLog = maxFSETableLog
+ b, err := fse.Compress(huffWeight[:maxSymbolValue], s.fse)
+ if err == nil && len(b) < int(s.symbolLen>>1) {
+ s.Out = append(s.Out, uint8(len(b)))
+ s.Out = append(s.Out, b...)
+ return nil
+ }
+ // Unable to compress (RLE/uncompressible)
+ }
+ // write raw values as 4-bits (max : 15)
+ if maxSymbolValue > (256 - 128) {
+ // should not happen : likely means source cannot be compressed
+ return ErrIncompressible
+ }
+ op := s.Out
+ // special case, pack weights 4 bits/weight.
+ op = append(op, 128|(maxSymbolValue-1))
+ // be sure it doesn't cause msan issue in final combination
+ huffWeight[maxSymbolValue] = 0
+ for n := uint16(0); n < uint16(maxSymbolValue); n += 2 {
+ op = append(op, (huffWeight[n]<<4)|huffWeight[n+1])
+ }
+ s.Out = op
+ return nil
+}
+
+func (c cTable) estTableSize(s *Scratch) (sz int, err error) {
+ var (
+ // precomputed conversion table
+ bitsToWeight [tableLogMax + 1]byte
+ huffLog = s.actualTableLog
+ // last weight is not saved.
+ maxSymbolValue = uint8(s.symbolLen - 1)
+ huffWeight = s.huffWeight[:256]
+ )
+ const (
+ maxFSETableLog = 6
+ )
+ // convert to weight
+ bitsToWeight[0] = 0
+ for n := uint8(1); n < huffLog+1; n++ {
+ bitsToWeight[n] = huffLog + 1 - n
+ }
+
+ // Acquire histogram for FSE.
+ hist := s.fse.Histogram()
+ hist = hist[:256]
+ for i := range hist[:16] {
+ hist[i] = 0
+ }
+ for n := range maxSymbolValue {
+ v := bitsToWeight[c[n].nBits] & 15
+ huffWeight[n] = v
+ hist[v]++
+ }
+
+ // FSE compress if feasible.
+ if maxSymbolValue >= 2 {
+ huffMaxCnt := uint32(0)
+ huffMax := uint8(0)
+ for i, v := range hist[:16] {
+ if v == 0 {
+ continue
+ }
+ huffMax = byte(i)
+ if v > huffMaxCnt {
+ huffMaxCnt = v
+ }
+ }
+ s.fse.HistogramFinished(huffMax, int(huffMaxCnt))
+ s.fse.TableLog = maxFSETableLog
+ b, err := fse.Compress(huffWeight[:maxSymbolValue], s.fse)
+ if err == nil && len(b) < int(s.symbolLen>>1) {
+ sz += 1 + len(b)
+ return sz, nil
+ }
+ // Unable to compress (RLE/uncompressible)
+ }
+ // write raw values as 4-bits (max : 15)
+ if maxSymbolValue > (256 - 128) {
+ // should not happen : likely means source cannot be compressed
+ return 0, ErrIncompressible
+ }
+ // special case, pack weights 4 bits/weight.
+ sz += 1 + int(maxSymbolValue/2)
+ return sz, nil
+}
+
+// estimateSize returns the estimated size in bytes of the input represented in the
+// histogram supplied.
+func (c cTable) estimateSize(hist []uint32) int {
+ nbBits := uint32(7)
+ for i, v := range c[:len(hist)] {
+ nbBits += uint32(v.nBits) * hist[i]
+ }
+ return int(nbBits >> 3)
+}
+
+// minSize returns the minimum possible size considering the shannon limit.
+func (s *Scratch) minSize(total int) int {
+ nbBits := float64(7)
+ fTotal := float64(total)
+ for _, v := range s.count[:s.symbolLen] {
+ n := float64(v)
+ if n > 0 {
+ nbBits += math.Log2(fTotal/n) * n
+ }
+ }
+ return int(nbBits) >> 3
+}
+
+func highBit32(val uint32) (n uint32) {
+ return uint32(bits.Len32(val) - 1)
+}
diff --git a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo.go b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo.go
new file mode 100644
index 00000000000..3954c51219b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo.go
@@ -0,0 +1,34 @@
+// Package cpuinfo gives runtime info about the current CPU.
+//
+// This is a very limited module meant for use internally
+// in this project. For more versatile solution check
+// https://github.com/klauspost/cpuid.
+package cpuinfo
+
+// HasBMI1 checks whether an x86 CPU supports the BMI1 extension.
+func HasBMI1() bool {
+ return hasBMI1
+}
+
+// HasBMI2 checks whether an x86 CPU supports the BMI2 extension.
+func HasBMI2() bool {
+ return hasBMI2
+}
+
+// DisableBMI2 will disable BMI2, for testing purposes.
+// Call returned function to restore previous state.
+func DisableBMI2() func() {
+ old := hasBMI2
+ hasBMI2 = false
+ return func() {
+ hasBMI2 = old
+ }
+}
+
+// HasBMI checks whether an x86 CPU supports both BMI1 and BMI2 extensions.
+func HasBMI() bool {
+ return HasBMI1() && HasBMI2()
+}
+
+var hasBMI1 bool
+var hasBMI2 bool
diff --git a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go
new file mode 100644
index 00000000000..b97f9056f4c
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go
@@ -0,0 +1,10 @@
+//go:build amd64 && !appengine && !noasm && gc
+
+package cpuinfo
+
+// go:noescape
+func x86extensions() (bmi1, bmi2 bool)
+
+func init() {
+ hasBMI1, hasBMI2 = x86extensions()
+}
diff --git a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.s b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.s
new file mode 100644
index 00000000000..4465fbe9e90
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.s
@@ -0,0 +1,36 @@
+// +build !appengine
+// +build gc
+// +build !noasm
+
+#include "textflag.h"
+#include "funcdata.h"
+#include "go_asm.h"
+
+TEXT ·x86extensions(SB), NOSPLIT, $0
+ // 1. determine max EAX value
+ XORQ AX, AX
+ CPUID
+
+ CMPQ AX, $7
+ JB unsupported
+
+ // 2. EAX = 7, ECX = 0 --- see Table 3-8 "Information Returned by CPUID Instruction"
+ MOVQ $7, AX
+ MOVQ $0, CX
+ CPUID
+
+ BTQ $3, BX // bit 3 = BMI1
+ SETCS AL
+
+ BTQ $8, BX // bit 8 = BMI2
+ SETCS AH
+
+ MOVB AL, bmi1+0(FP)
+ MOVB AH, bmi2+1(FP)
+ RET
+
+unsupported:
+ XORQ AX, AX
+ MOVB AL, bmi1+0(FP)
+ MOVB AL, bmi2+1(FP)
+ RET
diff --git a/vendor/github.com/klauspost/compress/internal/le/le.go b/vendor/github.com/klauspost/compress/internal/le/le.go
new file mode 100644
index 00000000000..e54909e16fc
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/le/le.go
@@ -0,0 +1,5 @@
+package le
+
+type Indexer interface {
+ int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
+}
diff --git a/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go b/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go
new file mode 100644
index 00000000000..4f2a0d8c58d
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go
@@ -0,0 +1,42 @@
+//go:build !(amd64 || arm64 || ppc64le || riscv64) || nounsafe || purego || appengine
+
+package le
+
+import (
+ "encoding/binary"
+)
+
+// Load8 will load from b at index i.
+func Load8[I Indexer](b []byte, i I) byte {
+ return b[i]
+}
+
+// Load16 will load from b at index i.
+func Load16[I Indexer](b []byte, i I) uint16 {
+ return binary.LittleEndian.Uint16(b[i:])
+}
+
+// Load32 will load from b at index i.
+func Load32[I Indexer](b []byte, i I) uint32 {
+ return binary.LittleEndian.Uint32(b[i:])
+}
+
+// Load64 will load from b at index i.
+func Load64[I Indexer](b []byte, i I) uint64 {
+ return binary.LittleEndian.Uint64(b[i:])
+}
+
+// Store16 will store v at b.
+func Store16(b []byte, v uint16) {
+ binary.LittleEndian.PutUint16(b, v)
+}
+
+// Store32 will store v at b.
+func Store32(b []byte, v uint32) {
+ binary.LittleEndian.PutUint32(b, v)
+}
+
+// Store64 will store v at b.
+func Store64[I Indexer](b []byte, i I, v uint64) {
+ binary.LittleEndian.PutUint64(b[i:], v)
+}
diff --git a/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go b/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go
new file mode 100644
index 00000000000..218a38bc4a5
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go
@@ -0,0 +1,52 @@
+// We enable 64 bit LE platforms:
+
+//go:build (amd64 || arm64 || ppc64le || riscv64) && !nounsafe && !purego && !appengine
+
+package le
+
+import (
+ "unsafe"
+)
+
+// Load8 will load from b at index i.
+func Load8[I Indexer](b []byte, i I) byte {
+ //return binary.LittleEndian.Uint16(b[i:])
+ //return *(*uint16)(unsafe.Pointer(&b[i]))
+ return *(*byte)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))
+}
+
+// Load16 will load from b at index i.
+func Load16[I Indexer](b []byte, i I) uint16 {
+ //return binary.LittleEndian.Uint16(b[i:])
+ //return *(*uint16)(unsafe.Pointer(&b[i]))
+ return *(*uint16)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))
+}
+
+// Load32 will load from b at index i.
+func Load32[I Indexer](b []byte, i I) uint32 {
+ //return binary.LittleEndian.Uint32(b[i:])
+ //return *(*uint32)(unsafe.Pointer(&b[i]))
+ return *(*uint32)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))
+}
+
+// Load64 will load from b at index i.
+func Load64[I Indexer](b []byte, i I) uint64 {
+ //return binary.LittleEndian.Uint64(b[i:])
+ //return *(*uint64)(unsafe.Pointer(&b[i]))
+ return *(*uint64)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))
+}
+
+// Store16 will store v at b.
+func Store16(b []byte, v uint16) {
+ *(*uint16)(unsafe.Pointer(unsafe.SliceData(b))) = v
+}
+
+// Store32 will store v at b.
+func Store32(b []byte, v uint32) {
+ *(*uint32)(unsafe.Pointer(unsafe.SliceData(b))) = v
+}
+
+// Store64 will store v at b[i:].
+func Store64[I Indexer](b []byte, i I, v uint64) {
+ *(*uint64)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i)) = v
+}
diff --git a/vendor/github.com/klauspost/compress/internal/race/norace.go b/vendor/github.com/klauspost/compress/internal/race/norace.go
new file mode 100644
index 00000000000..affbbbb595c
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/race/norace.go
@@ -0,0 +1,13 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !race
+
+package race
+
+func ReadSlice[T any](s []T) {
+}
+
+func WriteSlice[T any](s []T) {
+}
diff --git a/vendor/github.com/klauspost/compress/internal/race/race.go b/vendor/github.com/klauspost/compress/internal/race/race.go
new file mode 100644
index 00000000000..f5e240dcde4
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/race/race.go
@@ -0,0 +1,26 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build race
+
+package race
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+func ReadSlice[T any](s []T) {
+ if len(s) == 0 {
+ return
+ }
+ runtime.RaceReadRange(unsafe.Pointer(&s[0]), len(s)*int(unsafe.Sizeof(s[0])))
+}
+
+func WriteSlice[T any](s []T) {
+ if len(s) == 0 {
+ return
+ }
+ runtime.RaceWriteRange(unsafe.Pointer(&s[0]), len(s)*int(unsafe.Sizeof(s[0])))
+}
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/LICENSE b/vendor/github.com/klauspost/compress/internal/snapref/LICENSE
new file mode 100644
index 00000000000..6050c10f4c8
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/snapref/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2011 The Snappy-Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/decode.go b/vendor/github.com/klauspost/compress/internal/snapref/decode.go
new file mode 100644
index 00000000000..a2c82fcd226
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/snapref/decode.go
@@ -0,0 +1,264 @@
+// Copyright 2011 The Snappy-Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package snapref
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+)
+
+var (
+ // ErrCorrupt reports that the input is invalid.
+ ErrCorrupt = errors.New("snappy: corrupt input")
+ // ErrTooLarge reports that the uncompressed length is too large.
+ ErrTooLarge = errors.New("snappy: decoded block is too large")
+ // ErrUnsupported reports that the input isn't supported.
+ ErrUnsupported = errors.New("snappy: unsupported input")
+
+ errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length")
+)
+
+// DecodedLen returns the length of the decoded block.
+func DecodedLen(src []byte) (int, error) {
+ v, _, err := decodedLen(src)
+ return v, err
+}
+
+// decodedLen returns the length of the decoded block and the number of bytes
+// that the length header occupied.
+func decodedLen(src []byte) (blockLen, headerLen int, err error) {
+ v, n := binary.Uvarint(src)
+ if n <= 0 || v > 0xffffffff {
+ return 0, 0, ErrCorrupt
+ }
+
+ const wordSize = 32 << (^uint(0) >> 32 & 1)
+ if wordSize == 32 && v > 0x7fffffff {
+ return 0, 0, ErrTooLarge
+ }
+ return int(v), n, nil
+}
+
+const (
+ decodeErrCodeCorrupt = 1
+ decodeErrCodeUnsupportedLiteralLength = 2
+)
+
+// Decode returns the decoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire decoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// Decode handles the Snappy block format, not the Snappy stream format.
+func Decode(dst, src []byte) ([]byte, error) {
+ dLen, s, err := decodedLen(src)
+ if err != nil {
+ return nil, err
+ }
+ if dLen <= len(dst) {
+ dst = dst[:dLen]
+ } else {
+ dst = make([]byte, dLen)
+ }
+ switch decode(dst, src[s:]) {
+ case 0:
+ return dst, nil
+ case decodeErrCodeUnsupportedLiteralLength:
+ return nil, errUnsupportedLiteralLength
+ }
+ return nil, ErrCorrupt
+}
+
+// NewReader returns a new Reader that decompresses from r, using the framing
+// format described at
+// https://github.com/google/snappy/blob/master/framing_format.txt
+func NewReader(r io.Reader) *Reader {
+ return &Reader{
+ r: r,
+ decoded: make([]byte, maxBlockSize),
+ buf: make([]byte, maxEncodedLenOfMaxBlockSize+checksumSize),
+ }
+}
+
+// Reader is an io.Reader that can read Snappy-compressed bytes.
+//
+// Reader handles the Snappy stream format, not the Snappy block format.
+type Reader struct {
+ r io.Reader
+ err error
+ decoded []byte
+ buf []byte
+ // decoded[i:j] contains decoded bytes that have not yet been passed on.
+ i, j int
+ readHeader bool
+}
+
+// Reset discards any buffered data, resets all state, and switches the Snappy
+// reader to read from r. This permits reusing a Reader rather than allocating
+// a new one.
+func (r *Reader) Reset(reader io.Reader) {
+ r.r = reader
+ r.err = nil
+ r.i = 0
+ r.j = 0
+ r.readHeader = false
+}
+
+func (r *Reader) readFull(p []byte, allowEOF bool) (ok bool) {
+ if _, r.err = io.ReadFull(r.r, p); r.err != nil {
+ if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) {
+ r.err = ErrCorrupt
+ }
+ return false
+ }
+ return true
+}
+
+func (r *Reader) fill() error {
+ for r.i >= r.j {
+ if !r.readFull(r.buf[:4], true) {
+ return r.err
+ }
+ chunkType := r.buf[0]
+ if !r.readHeader {
+ if chunkType != chunkTypeStreamIdentifier {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ r.readHeader = true
+ }
+ chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
+ if chunkLen > len(r.buf) {
+ r.err = ErrUnsupported
+ return r.err
+ }
+
+ // The chunk types are specified at
+ // https://github.com/google/snappy/blob/master/framing_format.txt
+ switch chunkType {
+ case chunkTypeCompressedData:
+ // Section 4.2. Compressed data (chunk type 0x00).
+ if chunkLen < checksumSize {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ buf := r.buf[:chunkLen]
+ if !r.readFull(buf, false) {
+ return r.err
+ }
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ buf = buf[checksumSize:]
+
+ n, err := DecodedLen(buf)
+ if err != nil {
+ r.err = err
+ return r.err
+ }
+ if n > len(r.decoded) {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ if _, err := Decode(r.decoded, buf); err != nil {
+ r.err = err
+ return r.err
+ }
+ if crc(r.decoded[:n]) != checksum {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ r.i, r.j = 0, n
+ continue
+
+ case chunkTypeUncompressedData:
+ // Section 4.3. Uncompressed data (chunk type 0x01).
+ if chunkLen < checksumSize {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ buf := r.buf[:checksumSize]
+ if !r.readFull(buf, false) {
+ return r.err
+ }
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ // Read directly into r.decoded instead of via r.buf.
+ n := chunkLen - checksumSize
+ if n > len(r.decoded) {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ if !r.readFull(r.decoded[:n], false) {
+ return r.err
+ }
+ if crc(r.decoded[:n]) != checksum {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ r.i, r.j = 0, n
+ continue
+
+ case chunkTypeStreamIdentifier:
+ // Section 4.1. Stream identifier (chunk type 0xff).
+ if chunkLen != len(magicBody) {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ if !r.readFull(r.buf[:len(magicBody)], false) {
+ return r.err
+ }
+ for i := range len(magicBody) {
+ if r.buf[i] != magicBody[i] {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ }
+ continue
+ }
+
+ if chunkType <= 0x7f {
+ // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
+ r.err = ErrUnsupported
+ return r.err
+ }
+ // Section 4.4 Padding (chunk type 0xfe).
+ // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
+ if !r.readFull(r.buf[:chunkLen], false) {
+ return r.err
+ }
+ }
+
+ return nil
+}
+
+// Read satisfies the io.Reader interface.
+func (r *Reader) Read(p []byte) (int, error) {
+ if r.err != nil {
+ return 0, r.err
+ }
+
+ if err := r.fill(); err != nil {
+ return 0, err
+ }
+
+ n := copy(p, r.decoded[r.i:r.j])
+ r.i += n
+ return n, nil
+}
+
+// ReadByte satisfies the io.ByteReader interface.
+func (r *Reader) ReadByte() (byte, error) {
+ if r.err != nil {
+ return 0, r.err
+ }
+
+ if err := r.fill(); err != nil {
+ return 0, err
+ }
+
+ c := r.decoded[r.i]
+ r.i++
+ return c, nil
+}
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/decode_other.go b/vendor/github.com/klauspost/compress/internal/snapref/decode_other.go
new file mode 100644
index 00000000000..77395a6b8b9
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/snapref/decode_other.go
@@ -0,0 +1,113 @@
+// Copyright 2016 The Snappy-Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package snapref
+
+// decode writes the decoding of src to dst. It assumes that the varint-encoded
+// length of the decompressed bytes has already been read, and that len(dst)
+// equals that length.
+//
+// It returns 0 on success or a decodeErrCodeXxx error code on failure.
+func decode(dst, src []byte) int {
+ var d, s, offset, length int
+ for s < len(src) {
+ switch src[s] & 0x03 {
+ case tagLiteral:
+ x := uint32(src[s] >> 2)
+ switch {
+ case x < 60:
+ s++
+ case x == 60:
+ s += 2
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-1])
+ case x == 61:
+ s += 3
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-2]) | uint32(src[s-1])<<8
+ case x == 62:
+ s += 4
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
+ case x == 63:
+ s += 5
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
+ }
+ length = int(x) + 1
+ if length <= 0 {
+ return decodeErrCodeUnsupportedLiteralLength
+ }
+ if length > len(dst)-d || length > len(src)-s {
+ return decodeErrCodeCorrupt
+ }
+ copy(dst[d:], src[s:s+length])
+ d += length
+ s += length
+ continue
+
+ case tagCopy1:
+ s += 2
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ length = 4 + int(src[s-2])>>2&0x7
+ offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
+
+ case tagCopy2:
+ s += 3
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ length = 1 + int(src[s-3])>>2
+ offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
+
+ case tagCopy4:
+ s += 5
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ length = 1 + int(src[s-5])>>2
+ offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
+ }
+
+ if offset <= 0 || d < offset || length > len(dst)-d {
+ return decodeErrCodeCorrupt
+ }
+ // Copy from an earlier sub-slice of dst to a later sub-slice.
+ // If no overlap, use the built-in copy:
+ if offset >= length {
+ copy(dst[d:d+length], dst[d-offset:])
+ d += length
+ continue
+ }
+
+ // Unlike the built-in copy function, this byte-by-byte copy always runs
+ // forwards, even if the slices overlap. Conceptually, this is:
+ //
+ // d += forwardCopy(dst[d:d+length], dst[d-offset:])
+ //
+ // We align the slices into a and b and show the compiler they are the same size.
+ // This allows the loop to run without bounds checks.
+ a := dst[d : d+length]
+ b := dst[d-offset:]
+ b = b[:len(a)]
+ for i := range a {
+ a[i] = b[i]
+ }
+ d += length
+ }
+ if d != len(dst) {
+ return decodeErrCodeCorrupt
+ }
+ return 0
+}
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/encode.go b/vendor/github.com/klauspost/compress/internal/snapref/encode.go
new file mode 100644
index 00000000000..860a994167a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/snapref/encode.go
@@ -0,0 +1,291 @@
+// Copyright 2011 The Snappy-Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package snapref
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+)
+
+// Encode returns the encoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire encoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// Encode handles the Snappy block format, not the Snappy stream format.
+func Encode(dst, src []byte) []byte {
+ if n := MaxEncodedLen(len(src)); n < 0 {
+ panic(ErrTooLarge)
+ } else if cap(dst) < n {
+ dst = make([]byte, n)
+ } else {
+ dst = dst[:n]
+ }
+
+ // The block starts with the varint-encoded length of the decompressed bytes.
+ d := binary.PutUvarint(dst, uint64(len(src)))
+
+ for len(src) > 0 {
+ p := src
+ src = nil
+ if len(p) > maxBlockSize {
+ p, src = p[:maxBlockSize], p[maxBlockSize:]
+ }
+ if len(p) < minNonLiteralBlockSize {
+ d += emitLiteral(dst[d:], p)
+ } else {
+ d += encodeBlock(dst[d:], p)
+ }
+ }
+ return dst[:d]
+}
+
+// inputMargin is the minimum number of extra input bytes to keep, inside
+// encodeBlock's inner loop. On some architectures, this margin lets us
+// implement a fast path for emitLiteral, where the copy of short (<= 16 byte)
+// literals can be implemented as a single load to and store from a 16-byte
+// register. That literal's actual length can be as short as 1 byte, so this
+// can copy up to 15 bytes too much, but that's OK as subsequent iterations of
+// the encoding loop will fix up the copy overrun, and this inputMargin ensures
+// that we don't overrun the dst and src buffers.
+const inputMargin = 16 - 1
+
+// minNonLiteralBlockSize is the minimum size of the input to encodeBlock that
+// could be encoded with a copy tag. This is the minimum with respect to the
+// algorithm used by encodeBlock, not a minimum enforced by the file format.
+//
+// The encoded output must start with at least a 1 byte literal, as there are
+// no previous bytes to copy. A minimal (1 byte) copy after that, generated
+// from an emitCopy call in encodeBlock's main loop, would require at least
+// another inputMargin bytes, for the reason above: we want any emitLiteral
+// calls inside encodeBlock's main loop to use the fast path if possible, which
+// requires being able to overrun by inputMargin bytes. Thus,
+// minNonLiteralBlockSize equals 1 + 1 + inputMargin.
+//
+// The C++ code doesn't use this exact threshold, but it could, as discussed at
+// https://groups.google.com/d/topic/snappy-compression/oGbhsdIJSJ8/discussion
+// The difference between Go (2+inputMargin) and C++ (inputMargin) is purely an
+// optimization. It should not affect the encoded form. This is tested by
+// TestSameEncodingAsCppShortCopies.
+const minNonLiteralBlockSize = 1 + 1 + inputMargin
+
+// MaxEncodedLen returns the maximum length of a snappy block, given its
+// uncompressed length.
+//
+// It will return a negative value if srcLen is too large to encode.
+func MaxEncodedLen(srcLen int) int {
+ n := uint64(srcLen)
+ if n > 0xffffffff {
+ return -1
+ }
+ // Compressed data can be defined as:
+ // compressed := item* literal*
+ // item := literal* copy
+ //
+ // The trailing literal sequence has a space blowup of at most 62/60
+ // since a literal of length 60 needs one tag byte + one extra byte
+ // for length information.
+ //
+ // Item blowup is trickier to measure. Suppose the "copy" op copies
+ // 4 bytes of data. Because of a special check in the encoding code,
+ // we produce a 4-byte copy only if the offset is < 65536. Therefore
+ // the copy op takes 3 bytes to encode, and this type of item leads
+ // to at most the 62/60 blowup for representing literals.
+ //
+ // Suppose the "copy" op copies 5 bytes of data. If the offset is big
+ // enough, it will take 5 bytes to encode the copy op. Therefore the
+ // worst case here is a one-byte literal followed by a five-byte copy.
+ // That is, 6 bytes of input turn into 7 bytes of "compressed" data.
+ //
+ // This last factor dominates the blowup, so the final estimate is:
+ n = 32 + n + n/6
+ if n > 0xffffffff {
+ return -1
+ }
+ return int(n)
+}
+
+var errClosed = errors.New("snappy: Writer is closed")
+
+// NewWriter returns a new Writer that compresses to w.
+//
+// The Writer returned does not buffer writes. There is no need to Flush or
+// Close such a Writer.
+//
+// Deprecated: the Writer returned is not suitable for many small writes, only
+// for few large writes. Use NewBufferedWriter instead, which is efficient
+// regardless of the frequency and shape of the writes, and remember to Close
+// that Writer when done.
+func NewWriter(w io.Writer) *Writer {
+ return &Writer{
+ w: w,
+ obuf: make([]byte, obufLen),
+ }
+}
+
+// NewBufferedWriter returns a new Writer that compresses to w, using the
+// framing format described at
+// https://github.com/google/snappy/blob/master/framing_format.txt
+//
+// The Writer returned buffers writes. Users must call Close to guarantee all
+// data has been forwarded to the underlying io.Writer. They may also call
+// Flush zero or more times before calling Close.
+func NewBufferedWriter(w io.Writer) *Writer {
+ return &Writer{
+ w: w,
+ ibuf: make([]byte, 0, maxBlockSize),
+ obuf: make([]byte, obufLen),
+ }
+}
+
+// Writer is an io.Writer that can write Snappy-compressed bytes.
+//
+// Writer handles the Snappy stream format, not the Snappy block format.
+type Writer struct {
+ w io.Writer
+ err error
+
+ // ibuf is a buffer for the incoming (uncompressed) bytes.
+ //
+ // Its use is optional. For backwards compatibility, Writers created by the
+ // NewWriter function have ibuf == nil, do not buffer incoming bytes, and
+ // therefore do not need to be Flush'ed or Close'd.
+ ibuf []byte
+
+ // obuf is a buffer for the outgoing (compressed) bytes.
+ obuf []byte
+
+ // wroteStreamHeader is whether we have written the stream header.
+ wroteStreamHeader bool
+}
+
+// Reset discards the writer's state and switches the Snappy writer to write to
+// w. This permits reusing a Writer rather than allocating a new one.
+func (w *Writer) Reset(writer io.Writer) {
+ w.w = writer
+ w.err = nil
+ if w.ibuf != nil {
+ w.ibuf = w.ibuf[:0]
+ }
+ w.wroteStreamHeader = false
+}
+
+// Write satisfies the io.Writer interface.
+func (w *Writer) Write(p []byte) (nRet int, errRet error) {
+ if w.ibuf == nil {
+ // Do not buffer incoming bytes. This does not perform or compress well
+ // if the caller of Writer.Write writes many small slices. This
+ // behavior is therefore deprecated, but still supported for backwards
+ // compatibility with code that doesn't explicitly Flush or Close.
+ return w.write(p)
+ }
+
+ // The remainder of this method is based on bufio.Writer.Write from the
+ // standard library.
+
+ for len(p) > (cap(w.ibuf)-len(w.ibuf)) && w.err == nil {
+ var n int
+ if len(w.ibuf) == 0 {
+ // Large write, empty buffer.
+ // Write directly from p to avoid copy.
+ n, _ = w.write(p)
+ } else {
+ n = copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
+ w.ibuf = w.ibuf[:len(w.ibuf)+n]
+ w.Flush()
+ }
+ nRet += n
+ p = p[n:]
+ }
+ if w.err != nil {
+ return nRet, w.err
+ }
+ n := copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
+ w.ibuf = w.ibuf[:len(w.ibuf)+n]
+ nRet += n
+ return nRet, nil
+}
+
+func (w *Writer) write(p []byte) (nRet int, errRet error) {
+ if w.err != nil {
+ return 0, w.err
+ }
+ for len(p) > 0 {
+ obufStart := len(magicChunk)
+ if !w.wroteStreamHeader {
+ w.wroteStreamHeader = true
+ copy(w.obuf, magicChunk)
+ obufStart = 0
+ }
+
+ var uncompressed []byte
+ if len(p) > maxBlockSize {
+ uncompressed, p = p[:maxBlockSize], p[maxBlockSize:]
+ } else {
+ uncompressed, p = p, nil
+ }
+ checksum := crc(uncompressed)
+
+ // Compress the buffer, discarding the result if the improvement
+ // isn't at least 12.5%.
+ compressed := Encode(w.obuf[obufHeaderLen:], uncompressed)
+ chunkType := uint8(chunkTypeCompressedData)
+ chunkLen := 4 + len(compressed)
+ obufEnd := obufHeaderLen + len(compressed)
+ if len(compressed) >= len(uncompressed)-len(uncompressed)/8 {
+ chunkType = chunkTypeUncompressedData
+ chunkLen = 4 + len(uncompressed)
+ obufEnd = obufHeaderLen
+ }
+
+ // Fill in the per-chunk header that comes before the body.
+ w.obuf[len(magicChunk)+0] = chunkType
+ w.obuf[len(magicChunk)+1] = uint8(chunkLen >> 0)
+ w.obuf[len(magicChunk)+2] = uint8(chunkLen >> 8)
+ w.obuf[len(magicChunk)+3] = uint8(chunkLen >> 16)
+ w.obuf[len(magicChunk)+4] = uint8(checksum >> 0)
+ w.obuf[len(magicChunk)+5] = uint8(checksum >> 8)
+ w.obuf[len(magicChunk)+6] = uint8(checksum >> 16)
+ w.obuf[len(magicChunk)+7] = uint8(checksum >> 24)
+
+ if _, err := w.w.Write(w.obuf[obufStart:obufEnd]); err != nil {
+ w.err = err
+ return nRet, err
+ }
+ if chunkType == chunkTypeUncompressedData {
+ if _, err := w.w.Write(uncompressed); err != nil {
+ w.err = err
+ return nRet, err
+ }
+ }
+ nRet += len(uncompressed)
+ }
+ return nRet, nil
+}
+
+// Flush flushes the Writer to its underlying io.Writer.
+func (w *Writer) Flush() error {
+ if w.err != nil {
+ return w.err
+ }
+ if len(w.ibuf) == 0 {
+ return nil
+ }
+ w.write(w.ibuf)
+ w.ibuf = w.ibuf[:0]
+ return w.err
+}
+
+// Close calls Flush and then closes the Writer.
+func (w *Writer) Close() error {
+ w.Flush()
+ ret := w.err
+ if w.err == nil {
+ w.err = errClosed
+ }
+ return ret
+}
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go b/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go
new file mode 100644
index 00000000000..2754bac6f16
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go
@@ -0,0 +1,250 @@
+// Copyright 2016 The Snappy-Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package snapref
+
+func load32(b []byte, i int) uint32 {
+ b = b[i : i+4 : len(b)] // Help the compiler eliminate bounds checks on the next line.
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func load64(b []byte, i int) uint64 {
+ b = b[i : i+8 : len(b)] // Help the compiler eliminate bounds checks on the next line.
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+}
+
+// emitLiteral writes a literal chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes
+// 1 <= len(lit) && len(lit) <= 65536
+func emitLiteral(dst, lit []byte) int {
+ i, n := 0, uint(len(lit)-1)
+ switch {
+ case n < 60:
+ dst[0] = uint8(n)<<2 | tagLiteral
+ i = 1
+ case n < 1<<8:
+ dst[0] = 60<<2 | tagLiteral
+ dst[1] = uint8(n)
+ i = 2
+ default:
+ dst[0] = 61<<2 | tagLiteral
+ dst[1] = uint8(n)
+ dst[2] = uint8(n >> 8)
+ i = 3
+ }
+ return i + copy(dst[i:], lit)
+}
+
+// emitCopy writes a copy chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes
+// 1 <= offset && offset <= 65535
+// 4 <= length && length <= 65535
+func emitCopy(dst []byte, offset, length int) int {
+ i := 0
+ // The maximum length for a single tagCopy1 or tagCopy2 op is 64 bytes. The
+ // threshold for this loop is a little higher (at 68 = 64 + 4), and the
+ // length emitted down below is a little lower (at 60 = 64 - 4), because
+ // it's shorter to encode a length 67 copy as a length 60 tagCopy2 followed
+ // by a length 7 tagCopy1 (which encodes as 3+2 bytes) than to encode it as
+ // a length 64 tagCopy2 followed by a length 3 tagCopy2 (which encodes as
+ // 3+3 bytes). The magic 4 in the 64±4 is because the minimum length for a
+ // tagCopy1 op is 4 bytes, which is why a length 3 copy has to be an
+ // encodes-as-3-bytes tagCopy2 instead of an encodes-as-2-bytes tagCopy1.
+ for length >= 68 {
+ // Emit a length 64 copy, encoded as 3 bytes.
+ dst[i+0] = 63<<2 | tagCopy2
+ dst[i+1] = uint8(offset)
+ dst[i+2] = uint8(offset >> 8)
+ i += 3
+ length -= 64
+ }
+ if length > 64 {
+ // Emit a length 60 copy, encoded as 3 bytes.
+ dst[i+0] = 59<<2 | tagCopy2
+ dst[i+1] = uint8(offset)
+ dst[i+2] = uint8(offset >> 8)
+ i += 3
+ length -= 60
+ }
+ if length >= 12 || offset >= 2048 {
+ // Emit the remaining copy, encoded as 3 bytes.
+ dst[i+0] = uint8(length-1)<<2 | tagCopy2
+ dst[i+1] = uint8(offset)
+ dst[i+2] = uint8(offset >> 8)
+ return i + 3
+ }
+ // Emit the remaining copy, encoded as 2 bytes.
+ dst[i+0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
+ dst[i+1] = uint8(offset)
+ return i + 2
+}
+
+func hash(u, shift uint32) uint32 {
+ return (u * 0x1e35a7bd) >> shift
+}
+
+// EncodeBlockInto exposes encodeBlock but checks dst size.
+func EncodeBlockInto(dst, src []byte) (d int) {
+ if MaxEncodedLen(len(src)) > len(dst) {
+ return 0
+ }
+
+ // encodeBlock breaks on too big blocks, so split.
+ for len(src) > 0 {
+ p := src
+ src = nil
+ if len(p) > maxBlockSize {
+ p, src = p[:maxBlockSize], p[maxBlockSize:]
+ }
+ if len(p) < minNonLiteralBlockSize {
+ d += emitLiteral(dst[d:], p)
+ } else {
+ d += encodeBlock(dst[d:], p)
+ }
+ }
+ return d
+}
+
+// encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlock(dst, src []byte) (d int) {
+ // Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive.
+ // The table element type is uint16, as s < sLimit and sLimit < len(src)
+ // and len(src) <= maxBlockSize and maxBlockSize == 65536.
+ const (
+ maxTableSize = 1 << 14
+ // tableMask is redundant, but helps the compiler eliminate bounds
+ // checks.
+ tableMask = maxTableSize - 1
+ )
+ shift := uint32(32 - 8)
+ for tableSize := 1 << 8; tableSize < maxTableSize && tableSize < len(src); tableSize *= 2 {
+ shift--
+ }
+ // In Go, all array elements are zero-initialized, so there is no advantage
+ // to a smaller tableSize per se. However, it matches the C++ algorithm,
+ // and in the asm versions of this code, we can get away with zeroing only
+ // the first tableSize elements.
+ var table [maxTableSize]uint16
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ nextHash := hash(load32(src, s), shift)
+
+ for {
+ // Copied from the C++ snappy implementation:
+ //
+ // Heuristic match skipping: If 32 bytes are scanned with no matches
+ // found, start looking only at every other byte. If 32 more bytes are
+ // scanned (or skipped), look at every third byte, etc.. When a match
+ // is found, immediately go back to looking at every byte. This is a
+ // small loss (~5% performance, ~0.1% density) for compressible data
+ // due to more bookkeeping, but for non-compressible data (such as
+ // JPEG) it's a huge win since the compressor quickly "realizes" the
+ // data is incompressible and doesn't bother looking for matches
+ // everywhere.
+ //
+ // The "skip" variable keeps track of how many bytes there are since
+ // the last match; dividing it by 32 (ie. right-shifting by five) gives
+ // the number of bytes to move ahead for each iteration.
+ skip := 32
+
+ nextS := s
+ candidate := 0
+ for {
+ s = nextS
+ bytesBetweenHashLookups := skip >> 5
+ nextS = s + bytesBetweenHashLookups
+ skip += bytesBetweenHashLookups
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ candidate = int(table[nextHash&tableMask])
+ table[nextHash&tableMask] = uint16(s)
+ nextHash = hash(load32(src, nextS), shift)
+ if load32(src, s) == load32(src, candidate) {
+ break
+ }
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+ d += emitLiteral(dst[d:], src[nextEmit:s])
+
+ // Call emitCopy, and then see if another emitCopy could be our next
+ // move. Repeat until we find no match for the input immediately after
+ // what was consumed by the last emitCopy call.
+ //
+ // If we exit this loop normally then we need to call emitLiteral next,
+ // though we don't yet know how big the literal will be. We handle that
+ // by proceeding to the next iteration of the main loop. We also can
+ // exit this loop via goto if we get close to exhausting the input.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+ base := s
+
+ // Extend the 4-byte match as long as possible.
+ //
+ // This is an inlined version of:
+ // s = extendMatch(src, candidate+4, s+4)
+ s += 4
+ for i := candidate + 4; s < len(src) && src[i] == src[s]; i, s = i+1, s+1 {
+ }
+
+ d += emitCopy(dst[d:], base-candidate, s-base)
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ // We could immediately start working at s now, but to improve
+ // compression we first update the hash table at s-1 and at s. If
+ // another emitCopy is not our next move, also calculate nextHash
+ // at s+1. At least on GOARCH=amd64, these three hash calculations
+ // are faster as one load64 call (with some shifts) instead of
+ // three load32 calls.
+ x := load64(src, s-1)
+ prevHash := hash(uint32(x>>0), shift)
+ table[prevHash&tableMask] = uint16(s - 1)
+ currHash := hash(uint32(x>>8), shift)
+ candidate = int(table[currHash&tableMask])
+ table[currHash&tableMask] = uint16(s)
+ if uint32(x>>8) != load32(src, candidate) {
+ nextHash = hash(uint32(x>>16), shift)
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/snappy.go b/vendor/github.com/klauspost/compress/internal/snapref/snappy.go
new file mode 100644
index 00000000000..34d01f4aa63
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/snapref/snappy.go
@@ -0,0 +1,98 @@
+// Copyright 2011 The Snappy-Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package snapref implements the Snappy compression format. It aims for very
+// high speeds and reasonable compression.
+//
+// There are actually two Snappy formats: block and stream. They are related,
+// but different: trying to decompress block-compressed data as a Snappy stream
+// will fail, and vice versa. The block format is the Decode and Encode
+// functions and the stream format is the Reader and Writer types.
+//
+// The block format, the more common case, is used when the complete size (the
+// number of bytes) of the original data is known upfront, at the time
+// compression starts. The stream format, also known as the framing format, is
+// for when that isn't always true.
+//
+// The canonical, C++ implementation is at https://github.com/google/snappy and
+// it only implements the block format.
+package snapref
+
+import (
+ "hash/crc32"
+)
+
+/*
+Each encoded block begins with the varint-encoded length of the decoded data,
+followed by a sequence of chunks. Chunks begin and end on byte boundaries. The
+first byte of each chunk is broken into its 2 least and 6 most significant bits
+called l and m: l ranges in [0, 4) and m ranges in [0, 64). l is the chunk tag.
+Zero means a literal tag. All other values mean a copy tag.
+
+For literal tags:
+ - If m < 60, the next 1 + m bytes are literal bytes.
+ - Otherwise, let n be the little-endian unsigned integer denoted by the next
+ m - 59 bytes. The next 1 + n bytes after that are literal bytes.
+
+For copy tags, length bytes are copied from offset bytes ago, in the style of
+Lempel-Ziv compression algorithms. In particular:
+ - For l == 1, the offset ranges in [0, 1<<11) and the length in [4, 12).
+ The length is 4 + the low 3 bits of m. The high 3 bits of m form bits 8-10
+ of the offset. The next byte is bits 0-7 of the offset.
+ - For l == 2, the offset ranges in [0, 1<<16) and the length in [1, 65).
+ The length is 1 + m. The offset is the little-endian unsigned integer
+ denoted by the next 2 bytes.
+ - For l == 3, this tag is a legacy format that is no longer issued by most
+ encoders. Nonetheless, the offset ranges in [0, 1<<32) and the length in
+ [1, 65). The length is 1 + m. The offset is the little-endian unsigned
+ integer denoted by the next 4 bytes.
+*/
+const (
+ tagLiteral = 0x00
+ tagCopy1 = 0x01
+ tagCopy2 = 0x02
+ tagCopy4 = 0x03
+)
+
+const (
+ checksumSize = 4
+ chunkHeaderSize = 4
+ magicChunk = "\xff\x06\x00\x00" + magicBody
+ magicBody = "sNaPpY"
+
+ // maxBlockSize is the maximum size of the input to encodeBlock. It is not
+ // part of the wire format per se, but some parts of the encoder assume
+ // that an offset fits into a uint16.
+ //
+ // Also, for the framing format (Writer type instead of Encode function),
+ // https://github.com/google/snappy/blob/master/framing_format.txt says
+ // that "the uncompressed data in a chunk must be no longer than 65536
+ // bytes".
+ maxBlockSize = 65536
+
+ // maxEncodedLenOfMaxBlockSize equals MaxEncodedLen(maxBlockSize), but is
+ // hard coded to be a const instead of a variable, so that obufLen can also
+ // be a const. Their equivalence is confirmed by
+ // TestMaxEncodedLenOfMaxBlockSize.
+ maxEncodedLenOfMaxBlockSize = 76490
+
+ obufHeaderLen = len(magicChunk) + checksumSize + chunkHeaderSize
+ obufLen = obufHeaderLen + maxEncodedLenOfMaxBlockSize
+)
+
+const (
+ chunkTypeCompressedData = 0x00
+ chunkTypeUncompressedData = 0x01
+ chunkTypePadding = 0xfe
+ chunkTypeStreamIdentifier = 0xff
+)
+
+var crcTable = crc32.MakeTable(crc32.Castagnoli)
+
+// crc implements the checksum specified in section 3 of
+// https://github.com/google/snappy/blob/master/framing_format.txt
+func crc(b []byte) uint32 {
+ c := crc32.Update(0, crcTable, b)
+ return uint32(c>>15|c<<17) + 0xa282ead8
+}
diff --git a/vendor/github.com/klauspost/compress/s2/.gitignore b/vendor/github.com/klauspost/compress/s2/.gitignore
new file mode 100644
index 00000000000..3a89c6e3e26
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/.gitignore
@@ -0,0 +1,15 @@
+testdata/bench
+
+# These explicitly listed benchmark data files are for an obsolete version of
+# snappy_test.go.
+testdata/alice29.txt
+testdata/asyoulik.txt
+testdata/fireworks.jpeg
+testdata/geo.protodata
+testdata/html
+testdata/html_x_4
+testdata/kppkn.gtb
+testdata/lcet10.txt
+testdata/paper-100k.pdf
+testdata/plrabn12.txt
+testdata/urls.10K
diff --git a/vendor/github.com/klauspost/compress/s2/LICENSE b/vendor/github.com/klauspost/compress/s2/LICENSE
new file mode 100644
index 00000000000..1d2d645bd93
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2011 The Snappy-Go Authors. All rights reserved.
+Copyright (c) 2019 Klaus Post. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/klauspost/compress/s2/README.md b/vendor/github.com/klauspost/compress/s2/README.md
new file mode 100644
index 00000000000..b0bf59fbbd2
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/README.md
@@ -0,0 +1,1134 @@
+# MinLZ
+
+I have taken the experiences from this library and created a backwards compatible compression package called MinLZ.
+
+That package will seamlessly decode S2 content, making the transition from this package fairly trivial.
+
+There are many improvements to pretty much all aspects of S2 since we have "broken free" of the Snappy format specification.
+You can read a writeup on [Design and Improvements over S2](https://gist.github.com/klauspost/a25b66198cdbdf7b5b224f670c894ed5).
+
+The only aspect not covered is custom dictionary encoding. While I do intend to fix errors in this package,
+I do not expect to make significant improvements, since I consider MinLZ a better basis for going forward.
+
+See https://github.com/minio/minlz for all details.
+
+# S2 Compression
+
+S2 is an extension of [Snappy](https://github.com/google/snappy).
+
+S2 is aimed for high throughput, which is why it features concurrent compression for bigger payloads.
+
+Decoding is compatible with Snappy compressed content, but content compressed with S2 cannot be decompressed by Snappy.
+This means that S2 can seamlessly replace Snappy without converting compressed content.
+
+S2 can produce Snappy compatible output, faster and better than Snappy.
+If you want full benefit of the changes you should use s2 without Snappy compatibility.
+
+S2 is designed to have high throughput on content that cannot be compressed.
+This is important, so you don't have to worry about spending CPU cycles on already compressed data.
+
+## Benefits over Snappy
+
+* Better compression
+* Adjustable compression (3 levels)
+* Concurrent stream compression
+* Faster decompression, even for Snappy compatible content
+* Concurrent Snappy/S2 stream decompression
+* Skip forward in compressed stream
+* Random seeking with indexes
+* Compatible with reading Snappy compressed content
+* Smaller block size overhead on incompressible blocks
+* Block concatenation
+* Block Dictionary support
+* Uncompressed stream mode
+* Automatic stream size padding
+* Snappy compatible block compression
+
+## Drawbacks over Snappy
+
+* Not optimized for 32 bit systems
+* Streams use slightly more memory due to larger blocks and concurrency (configurable)
+
+# Usage
+
+Installation: `go get -u github.com/klauspost/compress/s2`
+
+Full package documentation:
+
+[![godoc][1]][2]
+
+[1]: https://godoc.org/github.com/klauspost/compress?status.svg
+[2]: https://godoc.org/github.com/klauspost/compress/s2
+
+## Compression
+
+```Go
+func EncodeStream(src io.Reader, dst io.Writer) error {
+ enc := s2.NewWriter(dst)
+ _, err := io.Copy(enc, src)
+ if err != nil {
+ enc.Close()
+ return err
+ }
+ // Blocks until compression is done.
+ return enc.Close()
+}
+```
+
+You should always call `enc.Close()`, otherwise you will leak resources and your encode will be incomplete.
+
+For the best throughput, you should attempt to reuse the `Writer` using the `Reset()` method.
+
+The Writer in S2 is always buffered, therefore `NewBufferedWriter` in Snappy can be replaced with `NewWriter` in S2.
+It is possible to flush any buffered data using the `Flush()` method.
+This will block until all data sent to the encoder has been written to the output.
+
+S2 also supports the `io.ReaderFrom` interface, which will consume all input from a reader.
+
+As a final method to compress data, if you have a single block of data you would like to have encoded as a stream,
+a slightly more efficient method is to use the `EncodeBuffer` method.
+This will take ownership of the buffer until the stream is closed.
+
+```Go
+func EncodeStream(src []byte, dst io.Writer) error {
+ enc := s2.NewWriter(dst)
+ // The encoder owns the buffer until Flush or Close is called.
+ err := enc.EncodeBuffer(src)
+ if err != nil {
+ enc.Close()
+ return err
+ }
+ // Blocks until compression is done.
+ return enc.Close()
+}
+```
+
+Each call to `EncodeBuffer` will result in discrete blocks being created without buffering,
+so it should only be used a single time per stream.
+If you need to write several blocks, you should use the regular io.Writer interface.
+
+
+## Decompression
+
+```Go
+func DecodeStream(src io.Reader, dst io.Writer) error {
+ dec := s2.NewReader(src)
+ _, err := io.Copy(dst, dec)
+ return err
+}
+```
+
+Similar to the Writer, a Reader can be reused using the `Reset` method.
+
+For the best possible throughput, there is a `EncodeBuffer(buf []byte)` function available.
+However, it requires that the provided buffer isn't used after it is handed over to S2 and until the stream is flushed or closed.
+
+For smaller data blocks, there is also a non-streaming interface: `Encode()`, `EncodeBetter()` and `Decode()`.
+Do however note that these functions (similar to Snappy) does not provide validation of data,
+so data corruption may be undetected. Stream encoding provides CRC checks of data.
+
+It is possible to efficiently skip forward in a compressed stream using the `Skip()` method.
+For big skips the decompressor is able to skip blocks without decompressing them.
+
+## Single Blocks
+
+Similar to Snappy S2 offers single block compression.
+Blocks do not offer the same flexibility and safety as streams,
+but may be preferable for very small payloads, less than 100K.
+
+Using a simple `dst := s2.Encode(nil, src)` will compress `src` and return the compressed result.
+It is possible to provide a destination buffer.
+If the buffer has a capacity of `s2.MaxEncodedLen(len(src))` it will be used.
+If not a new will be allocated.
+
+Alternatively `EncodeBetter`/`EncodeBest` can also be used for better, but slightly slower compression.
+
+Similarly to decompress a block you can use `dst, err := s2.Decode(nil, src)`.
+Again an optional destination buffer can be supplied.
+The `s2.DecodedLen(src)` can be used to get the minimum capacity needed.
+If that is not satisfied a new buffer will be allocated.
+
+Block function always operate on a single goroutine since it should only be used for small payloads.
+
+# Commandline tools
+
+Some very simply commandline tools are provided; `s2c` for compression and `s2d` for decompression.
+
+Binaries can be downloaded on the [Releases Page](https://github.com/klauspost/compress/releases).
+
+Installing then requires Go to be installed. To install them, use:
+
+`go install github.com/klauspost/compress/s2/cmd/s2c@latest && go install github.com/klauspost/compress/s2/cmd/s2d@latest`
+
+To build binaries to the current folder use:
+
+`go build github.com/klauspost/compress/s2/cmd/s2c && go build github.com/klauspost/compress/s2/cmd/s2d`
+
+
+## s2c
+
+```
+Usage: s2c [options] file1 file2
+
+Compresses all files supplied as input separately.
+Output files are written as 'filename.ext.s2' or 'filename.ext.snappy'.
+By default output files will be overwritten.
+Use - as the only file name to read from stdin and write to stdout.
+
+Wildcards are accepted: testdir/*.txt will compress all files in testdir ending with .txt
+Directories can be wildcards as well. testdir/*/*.txt will match testdir/subdir/b.txt
+
+File names beginning with 'http://' and 'https://' will be downloaded and compressed.
+Only http response code 200 is accepted.
+
+Options:
+ -bench int
+ Run benchmark n times. No output will be written
+ -blocksize string
+ Max block size. Examples: 64K, 256K, 1M, 4M. Must be power of two and <= 4MB (default "4M")
+ -c Write all output to stdout. Multiple input files will be concatenated
+ -cpu int
+ Compress using this amount of threads (default 32)
+ -faster
+ Compress faster, but with a minor compression loss
+ -help
+ Display help
+ -index
+ Add seek index (default true)
+ -o string
+ Write output to another file. Single input file only
+ -pad string
+ Pad size to a multiple of this value, Examples: 500, 64K, 256K, 1M, 4M, etc (default "1")
+ -q Don't write any output to terminal, except errors
+ -rm
+ Delete source file(s) after successful compression
+ -safe
+ Do not overwrite output files
+ -slower
+ Compress more, but a lot slower
+ -snappy
+ Generate Snappy compatible output stream
+ -verify
+ Verify written files
+
+```
+
+## s2d
+
+```
+Usage: s2d [options] file1 file2
+
+Decompresses all files supplied as input. Input files must end with '.s2' or '.snappy'.
+Output file names have the extension removed. By default output files will be overwritten.
+Use - as the only file name to read from stdin and write to stdout.
+
+Wildcards are accepted: testdir/*.txt will compress all files in testdir ending with .txt
+Directories can be wildcards as well. testdir/*/*.txt will match testdir/subdir/b.txt
+
+File names beginning with 'http://' and 'https://' will be downloaded and decompressed.
+Extensions on downloaded files are ignored. Only http response code 200 is accepted.
+
+Options:
+ -bench int
+ Run benchmark n times. No output will be written
+ -c Write all output to stdout. Multiple input files will be concatenated
+ -help
+ Display help
+ -o string
+ Write output to another file. Single input file only
+ -offset string
+ Start at offset. Examples: 92, 64K, 256K, 1M, 4M. Requires Index
+ -q Don't write any output to terminal, except errors
+ -rm
+ Delete source file(s) after successful decompression
+ -safe
+ Do not overwrite output files
+ -tail string
+ Return last of compressed file. Examples: 92, 64K, 256K, 1M, 4M. Requires Index
+ -verify
+ Verify files, but do not write output
+```
+
+## s2sx: self-extracting archives
+
+s2sx allows creating self-extracting archives with no dependencies.
+
+By default, executables are created for the same platforms as the host os,
+but this can be overridden with `-os` and `-arch` parameters.
+
+Extracted files have 0666 permissions, except when untar option used.
+
+```
+Usage: s2sx [options] file1 file2
+
+Compresses all files supplied as input separately.
+If files have '.s2' extension they are assumed to be compressed already.
+Output files are written as 'filename.s2sx' and with '.exe' for windows targets.
+If output is big, an additional file with ".more" is written. This must be included as well.
+By default output files will be overwritten.
+
+Wildcards are accepted: testdir/*.txt will compress all files in testdir ending with .txt
+Directories can be wildcards as well. testdir/*/*.txt will match testdir/subdir/b.txt
+
+Options:
+ -arch string
+ Destination architecture (default "amd64")
+ -c Write all output to stdout. Multiple input files will be concatenated
+ -cpu int
+ Compress using this amount of threads (default 32)
+ -help
+ Display help
+ -max string
+ Maximum executable size. Rest will be written to another file. (default "1G")
+ -os string
+ Destination operating system (default "windows")
+ -q Don't write any output to terminal, except errors
+ -rm
+ Delete source file(s) after successful compression
+ -safe
+ Do not overwrite output files
+ -untar
+ Untar on destination
+```
+
+Available platforms are:
+
+ * darwin-amd64
+ * darwin-arm64
+ * linux-amd64
+ * linux-arm
+ * linux-arm64
+ * linux-mips64
+ * linux-ppc64le
+ * windows-386
+ * windows-amd64
+
+By default, there is a size limit of 1GB for the output executable.
+
+When this is exceeded the remaining file content is written to a file called
+output+`.more`. This file must be included for a successful extraction and
+placed alongside the executable for a successful extraction.
+
+This file *must* have the same name as the executable, so if the executable is renamed,
+so must the `.more` file.
+
+This functionality is disabled with stdin/stdout.
+
+### Self-extracting TAR files
+
+If you wrap a TAR file you can specify `-untar` to make it untar on the destination host.
+
+Files are extracted to the current folder with the path specified in the tar file.
+
+Note that tar files are not validated before they are wrapped.
+
+For security reasons files that move below the root folder are not allowed.
+
+# Performance
+
+This section will focus on comparisons to Snappy.
+This package is solely aimed at replacing Snappy as a high speed compression package.
+If you are mainly looking for better compression [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd)
+gives better compression, but typically at speeds slightly below "better" mode in this package.
+
+Compression is increased compared to Snappy, mostly around 5-20% and the throughput is typically 25-40% increased (single threaded) compared to the Snappy Go implementation.
+
+Streams are concurrently compressed. The stream will be distributed among all available CPU cores for the best possible throughput.
+
+A "better" compression mode is also available. This allows to trade a bit of speed for a minor compression gain.
+The content compressed in this mode is fully compatible with the standard decoder.
+
+Snappy vs S2 **compression** speed on 16 core (32 thread) computer, using all threads and a single thread (1 CPU):
+
+| File | S2 Speed | S2 Throughput | S2 % smaller | S2 "better" | "better" throughput | "better" % smaller |
+|---------------------------------------------------------------------------------------------------------|----------|---------------|--------------|-------------|---------------------|--------------------|
+| [rawstudio-mint14.tar](https://files.klauspost.com/compress/rawstudio-mint14.7z) | 16.33x | 10556 MB/s | 8.0% | 6.04x | 5252 MB/s | 14.7% |
+| (1 CPU) | 1.08x | 940 MB/s | - | 0.46x | 400 MB/s | - |
+| [github-june-2days-2019.json](https://files.klauspost.com/compress/github-june-2days-2019.json.zst) | 16.51x | 15224 MB/s | 31.70% | 9.47x | 8734 MB/s | 37.71% |
+| (1 CPU) | 1.26x | 1157 MB/s | - | 0.60x | 556 MB/s | - |
+| [github-ranks-backup.bin](https://files.klauspost.com/compress/github-ranks-backup.bin.zst) | 15.14x | 12598 MB/s | -5.76% | 6.23x | 5675 MB/s | 3.62% |
+| (1 CPU) | 1.02x | 932 MB/s | - | 0.47x | 432 MB/s | - |
+| [consensus.db.10gb](https://files.klauspost.com/compress/consensus.db.10gb.zst) | 11.21x | 12116 MB/s | 15.95% | 3.24x | 3500 MB/s | 18.00% |
+| (1 CPU) | 1.05x | 1135 MB/s | - | 0.27x | 292 MB/s | - |
+| [apache.log](https://files.klauspost.com/compress/apache.log.zst) | 8.55x | 16673 MB/s | 20.54% | 5.85x | 11420 MB/s | 24.97% |
+| (1 CPU) | 1.91x | 1771 MB/s | - | 0.53x | 1041 MB/s | - |
+| [gob-stream](https://files.klauspost.com/compress/gob-stream.7z) | 15.76x | 14357 MB/s | 24.01% | 8.67x | 7891 MB/s | 33.68% |
+| (1 CPU) | 1.17x | 1064 MB/s | - | 0.65x | 595 MB/s | - |
+| [10gb.tar](http://mattmahoney.net/dc/10gb.html) | 13.33x | 9835 MB/s | 2.34% | 6.85x | 4863 MB/s | 9.96% |
+| (1 CPU) | 0.97x | 689 MB/s | - | 0.55x | 387 MB/s | - |
+| sharnd.out.2gb | 9.11x | 13213 MB/s | 0.01% | 1.49x | 9184 MB/s | 0.01% |
+| (1 CPU) | 0.88x | 5418 MB/s | - | 0.77x | 5417 MB/s | - |
+| [sofia-air-quality-dataset csv](https://files.klauspost.com/compress/sofia-air-quality-dataset.tar.zst) | 22.00x | 11477 MB/s | 18.73% | 11.15x | 5817 MB/s | 27.88% |
+| (1 CPU) | 1.23x | 642 MB/s | - | 0.71x | 642 MB/s | - |
+| [silesia.tar](http://sun.aei.polsl.pl/~sdeor/corpus/silesia.zip) | 11.23x | 6520 MB/s | 5.9% | 5.35x | 3109 MB/s | 15.88% |
+| (1 CPU) | 1.05x | 607 MB/s | - | 0.52x | 304 MB/s | - |
+| [enwik9](https://files.klauspost.com/compress/enwik9.zst) | 19.28x | 8440 MB/s | 4.04% | 9.31x | 4076 MB/s | 18.04% |
+| (1 CPU) | 1.12x | 488 MB/s | - | 0.57x | 250 MB/s | - |
+
+### Legend
+
+* `S2 Speed`: Speed of S2 compared to Snappy, using 16 cores and 1 core.
+* `S2 Throughput`: Throughput of S2 in MB/s.
+* `S2 % smaller`: How many percent of the Snappy output size is S2 better.
+* `S2 "better"`: Speed when enabling "better" compression mode in S2 compared to Snappy.
+* `"better" throughput`: Speed when enabling "better" compression mode in S2 compared to Snappy.
+* `"better" % smaller`: How many percent of the Snappy output size is S2 better when using "better" compression.
+
+There is a good speedup across the board when using a single thread and a significant speedup when using multiple threads.
+
+Machine generated data gets by far the biggest compression boost, with size being reduced by up to 35% of Snappy size.
+
+The "better" compression mode sees a good improvement in all cases, but usually at a performance cost.
+
+Incompressible content (`sharnd.out.2gb`, 2GB random data) sees the smallest speedup.
+This is likely dominated by synchronization overhead, which is confirmed by the fact that single threaded performance is higher (see above).
+
+## Decompression
+
+S2 attempts to create content that is also fast to decompress, except in "better" mode where the smallest representation is used.
+
+S2 vs Snappy **decompression** speed. Both operating on single core:
+
+| File | S2 Throughput | vs. Snappy | Better Throughput | vs. Snappy |
+|-----------------------------------------------------------------------------------------------------|---------------|------------|-------------------|------------|
+| [rawstudio-mint14.tar](https://files.klauspost.com/compress/rawstudio-mint14.7z) | 2117 MB/s | 1.14x | 1738 MB/s | 0.94x |
+| [github-june-2days-2019.json](https://files.klauspost.com/compress/github-june-2days-2019.json.zst) | 2401 MB/s | 1.25x | 2307 MB/s | 1.20x |
+| [github-ranks-backup.bin](https://files.klauspost.com/compress/github-ranks-backup.bin.zst) | 2075 MB/s | 0.98x | 1764 MB/s | 0.83x |
+| [consensus.db.10gb](https://files.klauspost.com/compress/consensus.db.10gb.zst) | 2967 MB/s | 1.05x | 2885 MB/s | 1.02x |
+| [adresser.json](https://files.klauspost.com/compress/adresser.json.zst) | 4141 MB/s | 1.07x | 4184 MB/s | 1.08x |
+| [gob-stream](https://files.klauspost.com/compress/gob-stream.7z) | 2264 MB/s | 1.12x | 2185 MB/s | 1.08x |
+| [10gb.tar](http://mattmahoney.net/dc/10gb.html) | 1525 MB/s | 1.03x | 1347 MB/s | 0.91x |
+| sharnd.out.2gb | 3813 MB/s | 0.79x | 3900 MB/s | 0.81x |
+| [enwik9](http://mattmahoney.net/dc/textdata.html) | 1246 MB/s | 1.29x | 967 MB/s | 1.00x |
+| [silesia.tar](http://sun.aei.polsl.pl/~sdeor/corpus/silesia.zip) | 1433 MB/s | 1.12x | 1203 MB/s | 0.94x |
+| [enwik10](https://encode.su/threads/3315-enwik10-benchmark-results) | 1284 MB/s | 1.32x | 1010 MB/s | 1.04x |
+
+### Legend
+
+* `S2 Throughput`: Decompression speed of S2 encoded content.
+* `Better Throughput`: Decompression speed of S2 "better" encoded content.
+* `vs Snappy`: Decompression speed of S2 "better" mode compared to Snappy and absolute speed.
+
+
+While the decompression code hasn't changed, there is a significant speedup in decompression speed.
+S2 prefers longer matches and will typically only find matches that are 6 bytes or longer.
+While this reduces compression a bit, it improves decompression speed.
+
+The "better" compression mode will actively look for shorter matches, which is why it has a decompression speed quite similar to Snappy.
+
+Without assembly decompression is also very fast; single goroutine decompression speed. No assembly:
+
+| File | S2 Throughput | S2 throughput |
+|--------------------------------|---------------|---------------|
+| consensus.db.10gb.s2 | 1.84x | 2289.8 MB/s |
+| 10gb.tar.s2 | 1.30x | 867.07 MB/s |
+| rawstudio-mint14.tar.s2 | 1.66x | 1329.65 MB/s |
+| github-june-2days-2019.json.s2 | 2.36x | 1831.59 MB/s |
+| github-ranks-backup.bin.s2 | 1.73x | 1390.7 MB/s |
+| enwik9.s2 | 1.67x | 681.53 MB/s |
+| adresser.json.s2 | 3.41x | 4230.53 MB/s |
+| silesia.tar.s2 | 1.52x | 811.58 |
+
+Even though S2 typically compresses better than Snappy, decompression speed is always better.
+
+### Concurrent Stream Decompression
+
+For full stream decompression S2 offers a [DecodeConcurrent](https://pkg.go.dev/github.com/klauspost/compress/s2#Reader.DecodeConcurrent)
+that will decode a full stream using multiple goroutines.
+
+Example scaling, AMD Ryzen 3950X, 16 cores, decompression using `s2d -bench=3 `, best of 3:
+
+| Input | `-cpu=1` | `-cpu=2` | `-cpu=4` | `-cpu=8` | `-cpu=16` |
+|-------------------------------------------|------------|------------|------------|------------|-------------|
+| enwik10.snappy | 1098.6MB/s | 1819.8MB/s | 3625.6MB/s | 6910.6MB/s | 10818.2MB/s |
+| enwik10.s2 | 1303.5MB/s | 2606.1MB/s | 4847.9MB/s | 8878.4MB/s | 9592.1MB/s |
+| sofia-air-quality-dataset.tar.snappy | 1302.0MB/s | 2165.0MB/s | 4244.5MB/s | 8241.0MB/s | 12920.5MB/s |
+| sofia-air-quality-dataset.tar.s2 | 1399.2MB/s | 2463.2MB/s | 5196.5MB/s | 9639.8MB/s | 11439.5MB/s |
+| sofia-air-quality-dataset.tar.s2 (no asm) | 837.5MB/s | 1652.6MB/s | 3183.6MB/s | 5945.0MB/s | 9620.7MB/s |
+
+Scaling can be expected to be pretty linear until memory bandwidth is saturated.
+
+For now the DecodeConcurrent can only be used for full streams without seeking or combining with regular reads.
+
+## Block compression
+
+
+When compressing blocks no concurrent compression is performed just as Snappy.
+This is because blocks are for smaller payloads and generally will not benefit from concurrent compression.
+
+An important change is that incompressible blocks will not be more than at most 10 bytes bigger than the input.
+In rare, worst case scenario Snappy blocks could be significantly bigger than the input.
+
+### Mixed content blocks
+
+The most reliable is a wide dataset.
+For this we use [`webdevdata.org-2015-01-07-subset`](https://files.klauspost.com/compress/webdevdata.org-2015-01-07-4GB-subset.7z),
+53927 files, total input size: 4,014,735,833 bytes. Single goroutine used.
+
+| * | Input | Output | Reduction | MB/s |
+|-------------------|------------|------------|------------|------------|
+| S2 | 4014735833 | 1059723369 | 73.60% | **936.73** |
+| S2 Better | 4014735833 | 961580539 | 76.05% | 451.10 |
+| S2 Best | 4014735833 | 899182886 | **77.60%** | 46.84 |
+| Snappy | 4014735833 | 1128706759 | 71.89% | 790.15 |
+| S2, Snappy Output | 4014735833 | 1093823291 | 72.75% | 936.60 |
+| LZ4 | 4014735833 | 1063768713 | 73.50% | 452.02 |
+
+S2 delivers both the best single threaded throughput with regular mode and the best compression rate with "best".
+"Better" mode provides the same compression speed as LZ4 with better compression ratio.
+
+When outputting Snappy compatible output it still delivers better throughput (150MB/s more) and better compression.
+
+As can be seen from the other benchmarks decompression should also be easier on the S2 generated output.
+
+Though they cannot be compared due to different decompression speeds here are the speed/size comparisons for
+other Go compressors:
+
+| * | Input | Output | Reduction | MB/s |
+|-------------------|------------|------------|-----------|--------|
+| Zstd Fastest (Go) | 4014735833 | 794608518 | 80.21% | 236.04 |
+| Zstd Best (Go) | 4014735833 | 704603356 | 82.45% | 35.63 |
+| Deflate (Go) l1 | 4014735833 | 871294239 | 78.30% | 214.04 |
+| Deflate (Go) l9 | 4014735833 | 730389060 | 81.81% | 41.17 |
+
+### Standard block compression
+
+Benchmarking single block performance is subject to a lot more variation since it only tests a limited number of file patterns.
+So individual benchmarks should only be seen as a guideline and the overall picture is more important.
+
+These micro-benchmarks are with data in cache and trained branch predictors. For a more realistic benchmark see the mixed content above.
+
+Block compression. Parallel benchmark running on 16 cores, 16 goroutines.
+
+AMD64 assembly is use for both S2 and Snappy.
+
+| Absolute Perf | Snappy size | S2 Size | Snappy Speed | S2 Speed | Snappy dec | S2 dec |
+|-----------------------|-------------|---------|--------------|-------------|-------------|-------------|
+| html | 22843 | 20868 | 16246 MB/s | 18617 MB/s | 40972 MB/s | 49263 MB/s |
+| urls.10K | 335492 | 286541 | 7943 MB/s | 10201 MB/s | 22523 MB/s | 26484 MB/s |
+| fireworks.jpeg | 123034 | 123100 | 349544 MB/s | 303228 MB/s | 718321 MB/s | 827552 MB/s |
+| fireworks.jpeg (200B) | 146 | 155 | 8869 MB/s | 20180 MB/s | 33691 MB/s | 52421 MB/s |
+| paper-100k.pdf | 85304 | 84202 | 167546 MB/s | 112988 MB/s | 326905 MB/s | 291944 MB/s |
+| html_x_4 | 92234 | 20870 | 15194 MB/s | 54457 MB/s | 30843 MB/s | 32217 MB/s |
+| alice29.txt | 88034 | 85934 | 5936 MB/s | 6540 MB/s | 12882 MB/s | 20044 MB/s |
+| asyoulik.txt | 77503 | 79575 | 5517 MB/s | 6657 MB/s | 12735 MB/s | 22806 MB/s |
+| lcet10.txt | 234661 | 220383 | 6235 MB/s | 6303 MB/s | 14519 MB/s | 18697 MB/s |
+| plrabn12.txt | 319267 | 318196 | 5159 MB/s | 6074 MB/s | 11923 MB/s | 19901 MB/s |
+| geo.protodata | 23335 | 18606 | 21220 MB/s | 25432 MB/s | 56271 MB/s | 62540 MB/s |
+| kppkn.gtb | 69526 | 65019 | 9732 MB/s | 8905 MB/s | 18491 MB/s | 18969 MB/s |
+| alice29.txt (128B) | 80 | 82 | 6691 MB/s | 17179 MB/s | 31883 MB/s | 38874 MB/s |
+| alice29.txt (1000B) | 774 | 774 | 12204 MB/s | 13273 MB/s | 48056 MB/s | 52341 MB/s |
+| alice29.txt (10000B) | 6648 | 6933 | 10044 MB/s | 12824 MB/s | 32378 MB/s | 46322 MB/s |
+| alice29.txt (20000B) | 12686 | 13516 | 7733 MB/s | 12160 MB/s | 30566 MB/s | 58969 MB/s |
+
+
+Speed is generally at or above Snappy. Small blocks gets a significant speedup, although at the expense of size.
+
+Decompression speed is better than Snappy, except in one case.
+
+Since payloads are very small the variance in terms of size is rather big, so they should only be seen as a general guideline.
+
+Size is on average around Snappy, but varies on content type.
+In cases where compression is worse, it usually is compensated by a speed boost.
+
+
+### Better compression
+
+Benchmarking single block performance is subject to a lot more variation since it only tests a limited number of file patterns.
+So individual benchmarks should only be seen as a guideline and the overall picture is more important.
+
+| Absolute Perf | Snappy size | Better Size | Snappy Speed | Better Speed | Snappy dec | Better dec |
+|-----------------------|-------------|-------------|--------------|--------------|-------------|-------------|
+| html | 22843 | 18972 | 16246 MB/s | 8621 MB/s | 40972 MB/s | 40292 MB/s |
+| urls.10K | 335492 | 248079 | 7943 MB/s | 5104 MB/s | 22523 MB/s | 20981 MB/s |
+| fireworks.jpeg | 123034 | 123100 | 349544 MB/s | 84429 MB/s | 718321 MB/s | 823698 MB/s |
+| fireworks.jpeg (200B) | 146 | 149 | 8869 MB/s | 7125 MB/s | 33691 MB/s | 30101 MB/s |
+| paper-100k.pdf | 85304 | 82887 | 167546 MB/s | 11087 MB/s | 326905 MB/s | 198869 MB/s |
+| html_x_4 | 92234 | 18982 | 15194 MB/s | 29316 MB/s | 30843 MB/s | 30937 MB/s |
+| alice29.txt | 88034 | 71611 | 5936 MB/s | 3709 MB/s | 12882 MB/s | 16611 MB/s |
+| asyoulik.txt | 77503 | 65941 | 5517 MB/s | 3380 MB/s | 12735 MB/s | 14975 MB/s |
+| lcet10.txt | 234661 | 184939 | 6235 MB/s | 3537 MB/s | 14519 MB/s | 16634 MB/s |
+| plrabn12.txt | 319267 | 264990 | 5159 MB/s | 2960 MB/s | 11923 MB/s | 13382 MB/s |
+| geo.protodata | 23335 | 17689 | 21220 MB/s | 10859 MB/s | 56271 MB/s | 57961 MB/s |
+| kppkn.gtb | 69526 | 55398 | 9732 MB/s | 5206 MB/s | 18491 MB/s | 16524 MB/s |
+| alice29.txt (128B) | 80 | 78 | 6691 MB/s | 7422 MB/s | 31883 MB/s | 34225 MB/s |
+| alice29.txt (1000B) | 774 | 746 | 12204 MB/s | 5734 MB/s | 48056 MB/s | 42068 MB/s |
+| alice29.txt (10000B) | 6648 | 6218 | 10044 MB/s | 6055 MB/s | 32378 MB/s | 28813 MB/s |
+| alice29.txt (20000B) | 12686 | 11492 | 7733 MB/s | 3143 MB/s | 30566 MB/s | 27315 MB/s |
+
+
+Except for the mostly incompressible JPEG image compression is better and usually in the
+double digits in terms of percentage reduction over Snappy.
+
+The PDF sample shows a significant slowdown compared to Snappy, as this mode tries harder
+to compress the data. Very small blocks are also not favorable for better compression, so throughput is way down.
+
+This mode aims to provide better compression at the expense of performance and achieves that
+without a huge performance penalty, except on very small blocks.
+
+Decompression speed suffers a little compared to the regular S2 mode,
+but still manages to be close to Snappy in spite of increased compression.
+
+# Best compression mode
+
+S2 offers a "best" compression mode.
+
+This will compress as much as possible with little regard to CPU usage.
+
+Mainly for offline compression, but where decompression speed should still
+be high and compatible with other S2 compressed data.
+
+Some examples compared on 16 core CPU, amd64 assembly used:
+
+```
+* enwik10
+Default... 10000000000 -> 4759950115 [47.60%]; 1.03s, 9263.0MB/s
+Better... 10000000000 -> 4084706676 [40.85%]; 2.16s, 4415.4MB/s
+Best... 10000000000 -> 3615520079 [36.16%]; 42.259s, 225.7MB/s
+
+* github-june-2days-2019.json
+Default... 6273951764 -> 1041700255 [16.60%]; 431ms, 13882.3MB/s
+Better... 6273951764 -> 945841238 [15.08%]; 547ms, 10938.4MB/s
+Best... 6273951764 -> 826392576 [13.17%]; 9.455s, 632.8MB/s
+
+* nyc-taxi-data-10M.csv
+Default... 3325605752 -> 1093516949 [32.88%]; 324ms, 9788.7MB/s
+Better... 3325605752 -> 885394158 [26.62%]; 491ms, 6459.4MB/s
+Best... 3325605752 -> 773681257 [23.26%]; 8.29s, 412.0MB/s
+
+* 10gb.tar
+Default... 10065157632 -> 5915541066 [58.77%]; 1.028s, 9337.4MB/s
+Better... 10065157632 -> 5453844650 [54.19%]; 1.597s, 4862.7MB/s
+Best... 10065157632 -> 5192495021 [51.59%]; 32.78s, 308.2MB/
+
+* consensus.db.10gb
+Default... 10737418240 -> 4549762344 [42.37%]; 882ms, 12118.4MB/s
+Better... 10737418240 -> 4438535064 [41.34%]; 1.533s, 3500.9MB/s
+Best... 10737418240 -> 4210602774 [39.21%]; 42.96s, 254.4MB/s
+```
+
+Decompression speed should be around the same as using the 'better' compression mode.
+
+## Dictionaries
+
+*Note: S2 dictionary compression is currently at an early implementation stage, with no assembly for
+neither encoding nor decoding. Performance improvements can be expected in the future.*
+
+Adding dictionaries allow providing a custom dictionary that will serve as lookup in the beginning of blocks.
+
+The same dictionary *must* be used for both encoding and decoding.
+S2 does not keep track of whether the same dictionary is used,
+and using the wrong dictionary will most often not result in an error when decompressing.
+
+Blocks encoded *without* dictionaries can be decompressed seamlessly *with* a dictionary.
+This means it is possible to switch from an encoding without dictionaries to an encoding with dictionaries
+and treat the blocks similarly.
+
+Similar to [zStandard dictionaries](https://github.com/facebook/zstd#the-case-for-small-data-compression),
+the same usage scenario applies to S2 dictionaries.
+
+> Training works if there is some correlation in a family of small data samples. The more data-specific a dictionary is, the more efficient it is (there is no universal dictionary). Hence, deploying one dictionary per type of data will provide the greatest benefits. Dictionary gains are mostly effective in the first few KB. Then, the compression algorithm will gradually use previously decoded content to better compress the rest of the file.
+
+S2 further limits the dictionary to only be enabled on the first 64KB of a block.
+This will remove any negative (speed) impacts of the dictionaries on bigger blocks.
+
+### Compression
+
+Using the [github_users_sample_set](https://github.com/facebook/zstd/releases/download/v1.1.3/github_users_sample_set.tar.zst)
+and a 64KB dictionary trained with zStandard the following sizes can be achieved.
+
+| | Default | Better | Best |
+|--------------------|------------------|------------------|-----------------------|
+| Without Dictionary | 3362023 (44.92%) | 3083163 (41.19%) | 3057944 (40.86%) |
+| With Dictionary | 921524 (12.31%) | 873154 (11.67%) | 785503 bytes (10.49%) |
+
+So for highly repetitive content, this case provides an almost 3x reduction in size.
+
+For less uniform data we will use the Go source code tree.
+Compressing First 64KB of all `.go` files in `go/src`, Go 1.19.5, 8912 files, 51253563 bytes input:
+
+| | Default | Better | Best |
+|--------------------|-------------------|-------------------|-------------------|
+| Without Dictionary | 22955767 (44.79%) | 20189613 (39.39% | 19482828 (38.01%) |
+| With Dictionary | 19654568 (38.35%) | 16289357 (31.78%) | 15184589 (29.63%) |
+| Saving/file | 362 bytes | 428 bytes | 472 bytes |
+
+
+### Creating Dictionaries
+
+There are no tools to create dictionaries in S2.
+However, there are multiple ways to create a useful dictionary:
+
+#### Using a Sample File
+
+If your input is very uniform, you can just use a sample file as the dictionary.
+
+For example in the `github_users_sample_set` above, the average compression only goes up from
+10.49% to 11.48% by using the first file as dictionary compared to using a dedicated dictionary.
+
+```Go
+ // Read a sample
+ sample, err := os.ReadFile("sample.json")
+
+ // Create a dictionary.
+ dict := s2.MakeDict(sample, nil)
+
+ // b := dict.Bytes() will provide a dictionary that can be saved
+ // and reloaded with s2.NewDict(b).
+
+ // To encode:
+ encoded := dict.Encode(nil, file)
+
+ // To decode:
+ decoded, err := dict.Decode(nil, file)
+```
+
+#### Using Zstandard
+
+Zstandard dictionaries can easily be converted to S2 dictionaries.
+
+This can be helpful to generate dictionaries for files that don't have a fixed structure.
+
+
+Example, with training set files placed in `./training-set`:
+
+`λ zstd -r --train-fastcover training-set/* --maxdict=65536 -o name.dict`
+
+This will create a dictionary of 64KB, that can be converted to a dictionary like this:
+
+```Go
+ // Decode the Zstandard dictionary.
+ insp, err := zstd.InspectDictionary(zdict)
+ if err != nil {
+ panic(err)
+ }
+
+ // We are only interested in the contents.
+ // Assume that files start with "// Copyright (c) 2023".
+ // Search for the longest match for that.
+ // This may save a few bytes.
+ dict := s2.MakeDict(insp.Content(), []byte("// Copyright (c) 2023"))
+
+ // b := dict.Bytes() will provide a dictionary that can be saved
+ // and reloaded with s2.NewDict(b).
+
+ // We can now encode using this dictionary
+ encodedWithDict := dict.Encode(nil, payload)
+
+ // To decode content:
+ decoded, err := dict.Decode(nil, encodedWithDict)
+```
+
+It is recommended to save the dictionary returned by ` b:= dict.Bytes()`, since that will contain only the S2 dictionary.
+
+This dictionary can later be loaded using `s2.NewDict(b)`. The dictionary then no longer requires `zstd` to be initialized.
+
+Also note how `s2.MakeDict` allows you to search for a common starting sequence of your files.
+This can be omitted, at the expense of a few bytes.
+
+# Snappy Compatibility
+
+S2 now offers full compatibility with Snappy.
+
+This means that the efficient encoders of S2 can be used to generate fully Snappy compatible output.
+
+There is a [snappy](https://github.com/klauspost/compress/tree/master/snappy) package that can be used by
+simply changing imports from `github.com/golang/snappy` to `github.com/klauspost/compress/snappy`.
+This uses "better" mode for all operations.
+If you would like more control, you can use the s2 package as described below:
+
+## Blocks
+
+Snappy compatible blocks can be generated with the S2 encoder.
+Compression and speed is typically a bit better `MaxEncodedLen` is also smaller for smaller memory usage. Replace
+
+| Snappy | S2 replacement |
+|---------------------------|-----------------------|
+| snappy.Encode(...) | s2.EncodeSnappy(...) |
+| snappy.MaxEncodedLen(...) | s2.MaxEncodedLen(...) |
+
+`s2.EncodeSnappy` can be replaced with `s2.EncodeSnappyBetter` or `s2.EncodeSnappyBest` to get more efficiently compressed snappy compatible output.
+
+`s2.ConcatBlocks` is compatible with snappy blocks.
+
+Comparison of [`webdevdata.org-2015-01-07-subset`](https://files.klauspost.com/compress/webdevdata.org-2015-01-07-4GB-subset.7z),
+53927 files, total input size: 4,014,735,833 bytes. amd64, single goroutine used:
+
+| Encoder | Size | MB/s | Reduction |
+|-----------------------|------------|------------|------------|
+| snappy.Encode | 1128706759 | 725.59 | 71.89% |
+| s2.EncodeSnappy | 1093823291 | **899.16** | 72.75% |
+| s2.EncodeSnappyBetter | 1001158548 | 578.49 | 75.06% |
+| s2.EncodeSnappyBest | 944507998 | 66.00 | **76.47%** |
+
+## Streams
+
+For streams, replace `enc = snappy.NewBufferedWriter(w)` with `enc = s2.NewWriter(w, s2.WriterSnappyCompat())`.
+All other options are available, but note that block size limit is different for snappy.
+
+Comparison of different streams, AMD Ryzen 3950x, 16 cores. Size and throughput:
+
+| File | snappy.NewWriter | S2 Snappy | S2 Snappy, Better | S2 Snappy, Best |
+|-----------------------------|--------------------------|---------------------------|--------------------------|-------------------------|
+| nyc-taxi-data-10M.csv | 1316042016 - 539.47MB/s | 1307003093 - 10132.73MB/s | 1174534014 - 5002.44MB/s | 1115904679 - 177.97MB/s |
+| enwik10 (xml) | 5088294643 - 451.13MB/s | 5175840939 - 9440.69MB/s | 4560784526 - 4487.21MB/s | 4340299103 - 158.92MB/s |
+| 10gb.tar (mixed) | 6056946612 - 729.73MB/s | 6208571995 - 9978.05MB/s | 5741646126 - 4919.98MB/s | 5548973895 - 180.44MB/s |
+| github-june-2days-2019.json | 1525176492 - 933.00MB/s | 1476519054 - 13150.12MB/s | 1400547532 - 5803.40MB/s | 1321887137 - 204.29MB/s |
+| consensus.db.10gb (db) | 5412897703 - 1102.14MB/s | 5354073487 - 13562.91MB/s | 5335069899 - 5294.73MB/s | 5201000954 - 175.72MB/s |
+
+# Decompression
+
+All decompression functions map directly to equivalent s2 functions.
+
+| Snappy | S2 replacement |
+|------------------------|--------------------|
+| snappy.Decode(...) | s2.Decode(...) |
+| snappy.DecodedLen(...) | s2.DecodedLen(...) |
+| snappy.NewReader(...) | s2.NewReader(...) |
+
+Features like [quick forward skipping without decompression](https://pkg.go.dev/github.com/klauspost/compress/s2#Reader.Skip)
+are also available for Snappy streams.
+
+If you know you are only decompressing snappy streams, setting [`ReaderMaxBlockSize(64<<10)`](https://pkg.go.dev/github.com/klauspost/compress/s2#ReaderMaxBlockSize)
+on your Reader will reduce memory consumption.
+
+# Concatenating blocks and streams.
+
+Concatenating streams will concatenate the output of both without recompressing them.
+While this is inefficient in terms of compression it might be usable in certain scenarios.
+The 10 byte 'stream identifier' of the second stream can optionally be stripped, but it is not a requirement.
+
+Blocks can be concatenated using the `ConcatBlocks` function.
+
+Snappy blocks/streams can safely be concatenated with S2 blocks and streams.
+Streams with indexes (see below) will currently not work on concatenated streams.
+
+# Stream Seek Index
+
+S2 and Snappy streams can have indexes. These indexes will allow random seeking within the compressed data.
+
+The index can either be appended to the stream as a skippable block or returned for separate storage.
+
+When the index is appended to a stream it will be skipped by regular decoders,
+so the output remains compatible with other decoders.
+
+## Creating an Index
+
+To automatically add an index to a stream, add `WriterAddIndex()` option to your writer.
+Then the index will be added to the stream when `Close()` is called.
+
+```
+ // Add Index to stream...
+ enc := s2.NewWriter(w, s2.WriterAddIndex())
+ io.Copy(enc, r)
+ enc.Close()
+```
+
+If you want to store the index separately, you can use `CloseIndex()` instead of the regular `Close()`.
+This will return the index. Note that `CloseIndex()` should only be called once, and you shouldn't call `Close()`.
+
+```
+ // Get index for separate storage...
+ enc := s2.NewWriter(w)
+ io.Copy(enc, r)
+ index, err := enc.CloseIndex()
+```
+
+The `index` can then be used needing to read from the stream.
+This means the index can be used without needing to seek to the end of the stream
+or for manually forwarding streams. See below.
+
+Finally, an existing S2/Snappy stream can be indexed using the `s2.IndexStream(r io.Reader)` function.
+
+## Using Indexes
+
+To use indexes there is a `ReadSeeker(random bool, index []byte) (*ReadSeeker, error)` function available.
+
+Calling ReadSeeker will return an [io.ReadSeeker](https://pkg.go.dev/io#ReadSeeker) compatible version of the reader.
+
+If 'random' is specified the returned io.Seeker can be used for random seeking, otherwise only forward seeking is supported.
+Enabling random seeking requires the original input to support the [io.Seeker](https://pkg.go.dev/io#Seeker) interface.
+
+```
+ dec := s2.NewReader(r)
+ rs, err := dec.ReadSeeker(false, nil)
+ rs.Seek(wantOffset, io.SeekStart)
+```
+
+Get a seeker to seek forward. Since no index is provided, the index is read from the stream.
+This requires that an index was added and that `r` supports the [io.Seeker](https://pkg.go.dev/io#Seeker) interface.
+
+A custom index can be specified which will be used if supplied.
+When using a custom index, it will not be read from the input stream.
+
+```
+ dec := s2.NewReader(r)
+ rs, err := dec.ReadSeeker(false, index)
+ rs.Seek(wantOffset, io.SeekStart)
+```
+
+This will read the index from `index`. Since we specify non-random (forward only) seeking `r` does not have to be an io.Seeker
+
+```
+ dec := s2.NewReader(r)
+ rs, err := dec.ReadSeeker(true, index)
+ rs.Seek(wantOffset, io.SeekStart)
+```
+
+Finally, since we specify that we want to do random seeking `r` must be an io.Seeker.
+
+The returned [ReadSeeker](https://pkg.go.dev/github.com/klauspost/compress/s2#ReadSeeker) contains a shallow reference to the existing Reader,
+meaning changes performed to one is reflected in the other.
+
+To check if a stream contains an index at the end, the `(*Index).LoadStream(rs io.ReadSeeker) error` can be used.
+
+## Manually Forwarding Streams
+
+Indexes can also be read outside the decoder using the [Index](https://pkg.go.dev/github.com/klauspost/compress/s2#Index) type.
+This can be used for parsing indexes, either separate or in streams.
+
+In some cases it may not be possible to serve a seekable stream.
+This can for instance be an HTTP stream, where the Range request
+is sent at the start of the stream.
+
+With a little bit of extra code it is still possible to use indexes
+to forward to specific offset with a single forward skip.
+
+It is possible to load the index manually like this:
+```
+ var index s2.Index
+ _, err = index.Load(idxBytes)
+```
+
+This can be used to figure out how much to offset the compressed stream:
+
+```
+ compressedOffset, uncompressedOffset, err := index.Find(wantOffset)
+```
+
+The `compressedOffset` is the number of bytes that should be skipped
+from the beginning of the compressed file.
+
+The `uncompressedOffset` will then be offset of the uncompressed bytes returned
+when decoding from that position. This will always be <= wantOffset.
+
+When creating a decoder it must be specified that it should *not* expect a stream identifier
+at the beginning of the stream. Assuming the io.Reader `r` has been forwarded to `compressedOffset`
+we create the decoder like this:
+
+```
+ dec := s2.NewReader(r, s2.ReaderIgnoreStreamIdentifier())
+```
+
+We are not completely done. We still need to forward the stream the uncompressed bytes we didn't want.
+This is done using the regular "Skip" function:
+
+```
+ err = dec.Skip(wantOffset - uncompressedOffset)
+```
+
+This will ensure that we are at exactly the offset we want, and reading from `dec` will start at the requested offset.
+
+# Compact storage
+
+For compact storage [RemoveIndexHeaders](https://pkg.go.dev/github.com/klauspost/compress/s2#RemoveIndexHeaders) can be used to remove any redundant info from
+a serialized index. If you remove the header it must be restored before [Loading](https://pkg.go.dev/github.com/klauspost/compress/s2#Index.Load).
+
+This is expected to save 20 bytes. These can be restored using [RestoreIndexHeaders](https://pkg.go.dev/github.com/klauspost/compress/s2#RestoreIndexHeaders). This removes a layer of security, but is the most compact representation. Returns nil if headers contains errors.
+
+## Index Format:
+
+Each block is structured as a snappy skippable block, with the chunk ID 0x99.
+
+The block can be read from the front, but contains information so it can be read from the back as well.
+
+Numbers are stored as fixed size little endian values or [zigzag encoded](https://developers.google.com/protocol-buffers/docs/encoding#signed_integers) [base 128 varints](https://developers.google.com/protocol-buffers/docs/encoding),
+with un-encoded value length of 64 bits, unless other limits are specified.
+
+| Content | Format |
+|--------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|
+| ID, `[1]byte` | Always 0x99. |
+| Data Length, `[3]byte` | 3 byte little-endian length of the chunk in bytes, following this. |
+| Header `[6]byte` | Header, must be `[115, 50, 105, 100, 120, 0]` or in text: "s2idx\x00". |
+| UncompressedSize, Varint | Total Uncompressed size. |
+| CompressedSize, Varint | Total Compressed size if known. Should be -1 if unknown. |
+| EstBlockSize, Varint | Block Size, used for guessing uncompressed offsets. Must be >= 0. |
+| Entries, Varint | Number of Entries in index, must be < 65536 and >=0. |
+| HasUncompressedOffsets `byte` | 0 if no uncompressed offsets are present, 1 if present. Other values are invalid. |
+| UncompressedOffsets, [Entries]VarInt | Uncompressed offsets. See below how to decode. |
+| CompressedOffsets, [Entries]VarInt | Compressed offsets. See below how to decode. |
+| Block Size, `[4]byte` | Little Endian total encoded size (including header and trailer). Can be used for searching backwards to start of block. |
+| Trailer `[6]byte` | Trailer, must be `[0, 120, 100, 105, 50, 115]` or in text: "\x00xdi2s". Can be used for identifying block from end of stream. |
+
+For regular streams the uncompressed offsets are fully predictable,
+so `HasUncompressedOffsets` allows to specify that compressed blocks all have
+exactly `EstBlockSize` bytes of uncompressed content.
+
+Entries *must* be in order, starting with the lowest offset,
+and there *must* be no uncompressed offset duplicates.
+Entries *may* point to the start of a skippable block,
+but it is then not allowed to also have an entry for the next block since
+that would give an uncompressed offset duplicate.
+
+There is no requirement for all blocks to be represented in the index.
+In fact there is a maximum of 65536 block entries in an index.
+
+The writer can use any method to reduce the number of entries.
+An implicit block start at 0,0 can be assumed.
+
+### Decoding entries:
+
+```
+// Read Uncompressed entries.
+// Each assumes EstBlockSize delta from previous.
+for each entry {
+ uOff = 0
+ if HasUncompressedOffsets == 1 {
+ uOff = ReadVarInt // Read value from stream
+ }
+
+ // Except for the first entry, use previous values.
+ if entryNum == 0 {
+ entry[entryNum].UncompressedOffset = uOff
+ continue
+ }
+
+ // Uncompressed uses previous offset and adds EstBlockSize
+ entry[entryNum].UncompressedOffset = entry[entryNum-1].UncompressedOffset + EstBlockSize + uOff
+}
+
+
+// Guess that the first block will be 50% of uncompressed size.
+// Integer truncating division must be used.
+CompressGuess := EstBlockSize / 2
+
+// Read Compressed entries.
+// Each assumes CompressGuess delta from previous.
+// CompressGuess is adjusted for each value.
+for each entry {
+ cOff = ReadVarInt // Read value from stream
+
+ // Except for the first entry, use previous values.
+ if entryNum == 0 {
+ entry[entryNum].CompressedOffset = cOff
+ continue
+ }
+
+ // Compressed uses previous and our estimate.
+ entry[entryNum].CompressedOffset = entry[entryNum-1].CompressedOffset + CompressGuess + cOff
+
+ // Adjust compressed offset for next loop, integer truncating division must be used.
+ CompressGuess += cOff/2
+}
+```
+
+To decode from any given uncompressed offset `(wantOffset)`:
+
+* Iterate entries until `entry[n].UncompressedOffset > wantOffset`.
+* Start decoding from `entry[n-1].CompressedOffset`.
+* Discard `entry[n-1].UncompressedOffset - wantOffset` bytes from the decoded stream.
+
+See [using indexes](https://github.com/klauspost/compress/tree/master/s2#using-indexes) for functions that perform the operations with a simpler interface.
+
+
+# Format Extensions
+
+* Frame [Stream identifier](https://github.com/google/snappy/blob/master/framing_format.txt#L68) changed from `sNaPpY` to `S2sTwO`.
+* [Framed compressed blocks](https://github.com/google/snappy/blob/master/format_description.txt) can be up to 4MB (up from 64KB).
+* Compressed blocks can have an offset of `0`, which indicates to repeat the last seen offset.
+
+Repeat offsets must be encoded as a [2.2.1. Copy with 1-byte offset (01)](https://github.com/google/snappy/blob/master/format_description.txt#L89), where the offset is 0.
+
+The length is specified by reading the 3-bit length specified in the tag and decode using this table:
+
+| Length | Actual Length |
+|--------|----------------------|
+| 0 | 4 |
+| 1 | 5 |
+| 2 | 6 |
+| 3 | 7 |
+| 4 | 8 |
+| 5 | 8 + read 1 byte |
+| 6 | 260 + read 2 bytes |
+| 7 | 65540 + read 3 bytes |
+
+This allows any repeat offset + length to be represented by 2 to 5 bytes.
+It also allows to emit matches longer than 64 bytes with one copy + one repeat instead of several 64 byte copies.
+
+Lengths are stored as little endian values.
+
+The first copy of a block cannot be a repeat offset and the offset is reset on every block in streams.
+
+Default streaming block size is 1MB.
+
+# Dictionary Encoding
+
+Adding dictionaries allow providing a custom dictionary that will serve as lookup in the beginning of blocks.
+
+A dictionary provides an initial repeat value that can be used to point to a common header.
+
+Other than that the dictionary contains values that can be used as back-references.
+
+Often used data should be placed at the *end* of the dictionary since offsets < 2048 bytes will be smaller.
+
+## Format
+
+Dictionary *content* must at least 16 bytes and less or equal to 64KiB (65536 bytes).
+
+Encoding: `[repeat value (uvarint)][dictionary content...]`
+
+Before the dictionary content, an unsigned base-128 (uvarint) encoded value specifying the initial repeat offset.
+This value is an offset into the dictionary content and not a back-reference offset,
+so setting this to 0 will make the repeat value point to the first value of the dictionary.
+
+The value must be less than the dictionary length-8
+
+## Encoding
+
+From the decoder point of view the dictionary content is seen as preceding the encoded content.
+
+`[dictionary content][decoded output]`
+
+Backreferences to the dictionary are encoded as ordinary backreferences that have an offset before the start of the decoded block.
+
+Matches copying from the dictionary are **not** allowed to cross from the dictionary into the decoded data.
+However, if a copy ends at the end of the dictionary the next repeat will point to the start of the decoded buffer, which is allowed.
+
+The first match can be a repeat value, which will use the repeat offset stored in the dictionary.
+
+When 64KB (65536 bytes) has been en/decoded it is no longer allowed to reference the dictionary,
+neither by a copy nor repeat operations.
+If the boundary is crossed while copying from the dictionary, the operation should complete,
+but the next instruction is not allowed to reference the dictionary.
+
+Valid blocks encoded *without* a dictionary can be decoded with any dictionary.
+There are no checks whether the supplied dictionary is the correct for a block.
+Because of this there is no overhead by using a dictionary.
+
+## Example
+
+This is the dictionary content. Elements are separated by `[]`.
+
+Dictionary: `[0x0a][Yesterday 25 bananas were added to Benjamins brown bag]`.
+
+Initial repeat offset is set at 10, which is the letter `2`.
+
+Encoded `[LIT "10"][REPEAT len=10][LIT "hich"][MATCH off=50 len=6][MATCH off=31 len=6][MATCH off=61 len=10]`
+
+Decoded: `[10][ bananas w][hich][ were ][brown ][were added]`
+
+Output: `10 bananas which were brown were added`
+
+
+## Streams
+
+For streams each block can use the dictionary.
+
+The dictionary cannot not currently be provided on the stream.
+
+
+# LICENSE
+
+This code is based on the [Snappy-Go](https://github.com/golang/snappy) implementation.
+
+Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
diff --git a/vendor/github.com/klauspost/compress/s2/decode.go b/vendor/github.com/klauspost/compress/s2/decode.go
new file mode 100644
index 00000000000..264ffd0a9b4
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/decode.go
@@ -0,0 +1,443 @@
+// Copyright 2011 The Snappy-Go Authors. All rights reserved.
+// Copyright (c) 2019 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "strconv"
+
+ "github.com/klauspost/compress/internal/race"
+)
+
+var (
+ // ErrCorrupt reports that the input is invalid.
+ ErrCorrupt = errors.New("s2: corrupt input")
+ // ErrCRC reports that the input failed CRC validation (streams only)
+ ErrCRC = errors.New("s2: corrupt input, crc mismatch")
+ // ErrTooLarge reports that the uncompressed length is too large.
+ ErrTooLarge = errors.New("s2: decoded block is too large")
+ // ErrUnsupported reports that the input isn't supported.
+ ErrUnsupported = errors.New("s2: unsupported input")
+)
+
+// DecodedLen returns the length of the decoded block.
+func DecodedLen(src []byte) (int, error) {
+ v, _, err := decodedLen(src)
+ return v, err
+}
+
+// decodedLen returns the length of the decoded block and the number of bytes
+// that the length header occupied.
+func decodedLen(src []byte) (blockLen, headerLen int, err error) {
+ v, n := binary.Uvarint(src)
+ if n <= 0 || v > 0xffffffff {
+ return 0, 0, ErrCorrupt
+ }
+
+ const wordSize = 32 << (^uint(0) >> 32 & 1)
+ if wordSize == 32 && v > 0x7fffffff {
+ return 0, 0, ErrTooLarge
+ }
+ return int(v), n, nil
+}
+
+const (
+ decodeErrCodeCorrupt = 1
+)
+
+// Decode returns the decoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire decoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+func Decode(dst, src []byte) ([]byte, error) {
+ dLen, s, err := decodedLen(src)
+ if err != nil {
+ return nil, err
+ }
+ if dLen <= cap(dst) {
+ dst = dst[:dLen]
+ } else {
+ dst = make([]byte, dLen)
+ }
+
+ race.WriteSlice(dst)
+ race.ReadSlice(src[s:])
+
+ if s2Decode(dst, src[s:]) != 0 {
+ return nil, ErrCorrupt
+ }
+ return dst, nil
+}
+
+// s2DecodeDict writes the decoding of src to dst. It assumes that the varint-encoded
+// length of the decompressed bytes has already been read, and that len(dst)
+// equals that length.
+//
+// It returns 0 on success or a decodeErrCodeXxx error code on failure.
+func s2DecodeDict(dst, src []byte, dict *Dict) int {
+ if dict == nil {
+ return s2Decode(dst, src)
+ }
+ const debug = false
+ const debugErrs = debug
+
+ if debug {
+ fmt.Println("Starting decode, dst len:", len(dst))
+ }
+ var d, s, length int
+ offset := len(dict.dict) - dict.repeat
+
+ // As long as we can read at least 5 bytes...
+ for s < len(src)-5 {
+ // Removing bounds checks is SLOWER, when if doing
+ // in := src[s:s+5]
+ // Checked on Go 1.18
+ switch src[s] & 0x03 {
+ case tagLiteral:
+ x := uint32(src[s] >> 2)
+ switch {
+ case x < 60:
+ s++
+ case x == 60:
+ s += 2
+ x = uint32(src[s-1])
+ case x == 61:
+ in := src[s : s+3]
+ x = uint32(in[1]) | uint32(in[2])<<8
+ s += 3
+ case x == 62:
+ in := src[s : s+4]
+ // Load as 32 bit and shift down.
+ x = uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24
+ x >>= 8
+ s += 4
+ case x == 63:
+ in := src[s : s+5]
+ x = uint32(in[1]) | uint32(in[2])<<8 | uint32(in[3])<<16 | uint32(in[4])<<24
+ s += 5
+ }
+ length = int(x) + 1
+ if debug {
+ fmt.Println("literals, length:", length, "d-after:", d+length)
+ }
+ if length > len(dst)-d || length > len(src)-s || (strconv.IntSize == 32 && length <= 0) {
+ if debugErrs {
+ fmt.Println("corrupt literal: length:", length, "d-left:", len(dst)-d, "src-left:", len(src)-s)
+ }
+ return decodeErrCodeCorrupt
+ }
+
+ copy(dst[d:], src[s:s+length])
+ d += length
+ s += length
+ continue
+
+ case tagCopy1:
+ s += 2
+ toffset := int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
+ length = int(src[s-2]) >> 2 & 0x7
+ if toffset == 0 {
+ if debug {
+ fmt.Print("(repeat) ")
+ }
+ // keep last offset
+ switch length {
+ case 5:
+ length = int(src[s]) + 4
+ s += 1
+ case 6:
+ in := src[s : s+2]
+ length = int(uint32(in[0])|(uint32(in[1])<<8)) + (1 << 8)
+ s += 2
+ case 7:
+ in := src[s : s+3]
+ length = int((uint32(in[2])<<16)|(uint32(in[1])<<8)|uint32(in[0])) + (1 << 16)
+ s += 3
+ default: // 0-> 4
+ }
+ } else {
+ offset = toffset
+ }
+ length += 4
+ case tagCopy2:
+ in := src[s : s+3]
+ offset = int(uint32(in[1]) | uint32(in[2])<<8)
+ length = 1 + int(in[0])>>2
+ s += 3
+
+ case tagCopy4:
+ in := src[s : s+5]
+ offset = int(uint32(in[1]) | uint32(in[2])<<8 | uint32(in[3])<<16 | uint32(in[4])<<24)
+ length = 1 + int(in[0])>>2
+ s += 5
+ }
+
+ if offset <= 0 || length > len(dst)-d {
+ if debugErrs {
+ fmt.Println("match error; offset:", offset, "length:", length, "dst-left:", len(dst)-d)
+ }
+ return decodeErrCodeCorrupt
+ }
+
+ // copy from dict
+ if d < offset {
+ if d > MaxDictSrcOffset {
+ if debugErrs {
+ fmt.Println("dict after", MaxDictSrcOffset, "d:", d, "offset:", offset, "length:", length)
+ }
+ return decodeErrCodeCorrupt
+ }
+ startOff := len(dict.dict) - offset + d
+ if startOff < 0 || startOff+length > len(dict.dict) {
+ if debugErrs {
+ fmt.Printf("offset (%d) + length (%d) bigger than dict (%d)\n", offset, length, len(dict.dict))
+ }
+ return decodeErrCodeCorrupt
+ }
+ if debug {
+ fmt.Println("dict copy, length:", length, "offset:", offset, "d-after:", d+length, "dict start offset:", startOff)
+ }
+ copy(dst[d:d+length], dict.dict[startOff:])
+ d += length
+ continue
+ }
+
+ if debug {
+ fmt.Println("copy, length:", length, "offset:", offset, "d-after:", d+length)
+ }
+
+ // Copy from an earlier sub-slice of dst to a later sub-slice.
+ // If no overlap, use the built-in copy:
+ if offset > length {
+ copy(dst[d:d+length], dst[d-offset:])
+ d += length
+ continue
+ }
+
+ // Unlike the built-in copy function, this byte-by-byte copy always runs
+ // forwards, even if the slices overlap. Conceptually, this is:
+ //
+ // d += forwardCopy(dst[d:d+length], dst[d-offset:])
+ //
+ // We align the slices into a and b and show the compiler they are the same size.
+ // This allows the loop to run without bounds checks.
+ a := dst[d : d+length]
+ b := dst[d-offset:]
+ b = b[:len(a)]
+ for i := range a {
+ a[i] = b[i]
+ }
+ d += length
+ }
+
+ // Remaining with extra checks...
+ for s < len(src) {
+ switch src[s] & 0x03 {
+ case tagLiteral:
+ x := uint32(src[s] >> 2)
+ switch {
+ case x < 60:
+ s++
+ case x == 60:
+ s += 2
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ if debugErrs {
+ fmt.Println("src went oob")
+ }
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-1])
+ case x == 61:
+ s += 3
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ if debugErrs {
+ fmt.Println("src went oob")
+ }
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-2]) | uint32(src[s-1])<<8
+ case x == 62:
+ s += 4
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ if debugErrs {
+ fmt.Println("src went oob")
+ }
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
+ case x == 63:
+ s += 5
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ if debugErrs {
+ fmt.Println("src went oob")
+ }
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
+ }
+ length = int(x) + 1
+ if length > len(dst)-d || length > len(src)-s || (strconv.IntSize == 32 && length <= 0) {
+ if debugErrs {
+ fmt.Println("corrupt literal: length:", length, "d-left:", len(dst)-d, "src-left:", len(src)-s)
+ }
+ return decodeErrCodeCorrupt
+ }
+ if debug {
+ fmt.Println("literals, length:", length, "d-after:", d+length)
+ }
+
+ copy(dst[d:], src[s:s+length])
+ d += length
+ s += length
+ continue
+
+ case tagCopy1:
+ s += 2
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ if debugErrs {
+ fmt.Println("src went oob")
+ }
+ return decodeErrCodeCorrupt
+ }
+ length = int(src[s-2]) >> 2 & 0x7
+ toffset := int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
+ if toffset == 0 {
+ if debug {
+ fmt.Print("(repeat) ")
+ }
+ // keep last offset
+ switch length {
+ case 5:
+ s += 1
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ if debugErrs {
+ fmt.Println("src went oob")
+ }
+ return decodeErrCodeCorrupt
+ }
+ length = int(uint32(src[s-1])) + 4
+ case 6:
+ s += 2
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ if debugErrs {
+ fmt.Println("src went oob")
+ }
+ return decodeErrCodeCorrupt
+ }
+ length = int(uint32(src[s-2])|(uint32(src[s-1])<<8)) + (1 << 8)
+ case 7:
+ s += 3
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ if debugErrs {
+ fmt.Println("src went oob")
+ }
+ return decodeErrCodeCorrupt
+ }
+ length = int(uint32(src[s-3])|(uint32(src[s-2])<<8)|(uint32(src[s-1])<<16)) + (1 << 16)
+ default: // 0-> 4
+ }
+ } else {
+ offset = toffset
+ }
+ length += 4
+ case tagCopy2:
+ s += 3
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ if debugErrs {
+ fmt.Println("src went oob")
+ }
+ return decodeErrCodeCorrupt
+ }
+ length = 1 + int(src[s-3])>>2
+ offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
+
+ case tagCopy4:
+ s += 5
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ if debugErrs {
+ fmt.Println("src went oob")
+ }
+ return decodeErrCodeCorrupt
+ }
+ length = 1 + int(src[s-5])>>2
+ offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
+ }
+
+ if offset <= 0 || length > len(dst)-d {
+ if debugErrs {
+ fmt.Println("match error; offset:", offset, "length:", length, "dst-left:", len(dst)-d)
+ }
+ return decodeErrCodeCorrupt
+ }
+
+ // copy from dict
+ if d < offset {
+ if d > MaxDictSrcOffset {
+ if debugErrs {
+ fmt.Println("dict after", MaxDictSrcOffset, "d:", d, "offset:", offset, "length:", length)
+ }
+ return decodeErrCodeCorrupt
+ }
+ rOff := len(dict.dict) - (offset - d)
+ if debug {
+ fmt.Println("starting dict entry from dict offset", len(dict.dict)-rOff)
+ }
+ if rOff+length > len(dict.dict) {
+ if debugErrs {
+ fmt.Println("err: END offset", rOff+length, "bigger than dict", len(dict.dict), "dict offset:", rOff, "length:", length)
+ }
+ return decodeErrCodeCorrupt
+ }
+ if rOff < 0 {
+ if debugErrs {
+ fmt.Println("err: START offset", rOff, "less than 0", len(dict.dict), "dict offset:", rOff, "length:", length)
+ }
+ return decodeErrCodeCorrupt
+ }
+ copy(dst[d:d+length], dict.dict[rOff:])
+ d += length
+ continue
+ }
+
+ if debug {
+ fmt.Println("copy, length:", length, "offset:", offset, "d-after:", d+length)
+ }
+
+ // Copy from an earlier sub-slice of dst to a later sub-slice.
+ // If no overlap, use the built-in copy:
+ if offset > length {
+ copy(dst[d:d+length], dst[d-offset:])
+ d += length
+ continue
+ }
+
+ // Unlike the built-in copy function, this byte-by-byte copy always runs
+ // forwards, even if the slices overlap. Conceptually, this is:
+ //
+ // d += forwardCopy(dst[d:d+length], dst[d-offset:])
+ //
+ // We align the slices into a and b and show the compiler they are the same size.
+ // This allows the loop to run without bounds checks.
+ a := dst[d : d+length]
+ b := dst[d-offset:]
+ b = b[:len(a)]
+ for i := range a {
+ a[i] = b[i]
+ }
+ d += length
+ }
+
+ if d != len(dst) {
+ if debugErrs {
+ fmt.Println("wanted length", len(dst), "got", d)
+ }
+ return decodeErrCodeCorrupt
+ }
+ return 0
+}
diff --git a/vendor/github.com/klauspost/compress/s2/decode_amd64.s b/vendor/github.com/klauspost/compress/s2/decode_amd64.s
new file mode 100644
index 00000000000..1216df78f5d
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/decode_amd64.s
@@ -0,0 +1,568 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright (c) 2019 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !appengine
+// +build gc
+// +build !noasm
+
+#include "textflag.h"
+
+#define R_TMP0 AX
+#define R_TMP1 BX
+#define R_LEN CX
+#define R_OFF DX
+#define R_SRC SI
+#define R_DST DI
+#define R_DBASE R8
+#define R_DLEN R9
+#define R_DEND R10
+#define R_SBASE R11
+#define R_SLEN R12
+#define R_SEND R13
+#define R_TMP2 R14
+#define R_TMP3 R15
+
+// The asm code generally follows the pure Go code in decode_other.go, except
+// where marked with a "!!!".
+
+// func decode(dst, src []byte) int
+//
+// All local variables fit into registers. The non-zero stack size is only to
+// spill registers and push args when issuing a CALL. The register allocation:
+// - R_TMP0 scratch
+// - R_TMP1 scratch
+// - R_LEN length or x (shared)
+// - R_OFF offset
+// - R_SRC &src[s]
+// - R_DST &dst[d]
+// + R_DBASE dst_base
+// + R_DLEN dst_len
+// + R_DEND dst_base + dst_len
+// + R_SBASE src_base
+// + R_SLEN src_len
+// + R_SEND src_base + src_len
+// - R_TMP2 used by doCopy
+// - R_TMP3 used by doCopy
+//
+// The registers R_DBASE-R_SEND (marked with a "+") are set at the start of the
+// function, and after a CALL returns, and are not otherwise modified.
+//
+// The d variable is implicitly R_DST - R_DBASE, and len(dst)-d is R_DEND - R_DST.
+// The s variable is implicitly R_SRC - R_SBASE, and len(src)-s is R_SEND - R_SRC.
+TEXT ·s2Decode(SB), NOSPLIT, $56-56
+ // Initialize R_SRC, R_DST and R_DBASE-R_SEND.
+ MOVQ dst_base+0(FP), R_DBASE
+ MOVQ dst_len+8(FP), R_DLEN
+ MOVQ R_DBASE, R_DST
+ MOVQ R_DBASE, R_DEND
+ ADDQ R_DLEN, R_DEND
+ MOVQ src_base+24(FP), R_SBASE
+ MOVQ src_len+32(FP), R_SLEN
+ MOVQ R_SBASE, R_SRC
+ MOVQ R_SBASE, R_SEND
+ ADDQ R_SLEN, R_SEND
+ XORQ R_OFF, R_OFF
+
+loop:
+ // for s < len(src)
+ CMPQ R_SRC, R_SEND
+ JEQ end
+
+ // R_LEN = uint32(src[s])
+ //
+ // switch src[s] & 0x03
+ MOVBLZX (R_SRC), R_LEN
+ MOVL R_LEN, R_TMP1
+ ANDL $3, R_TMP1
+ CMPL R_TMP1, $1
+ JAE tagCopy
+
+ // ----------------------------------------
+ // The code below handles literal tags.
+
+ // case tagLiteral:
+ // x := uint32(src[s] >> 2)
+ // switch
+ SHRL $2, R_LEN
+ CMPL R_LEN, $60
+ JAE tagLit60Plus
+
+ // case x < 60:
+ // s++
+ INCQ R_SRC
+
+doLit:
+ // This is the end of the inner "switch", when we have a literal tag.
+ //
+ // We assume that R_LEN == x and x fits in a uint32, where x is the variable
+ // used in the pure Go decode_other.go code.
+
+ // length = int(x) + 1
+ //
+ // Unlike the pure Go code, we don't need to check if length <= 0 because
+ // R_LEN can hold 64 bits, so the increment cannot overflow.
+ INCQ R_LEN
+
+ // Prepare to check if copying length bytes will run past the end of dst or
+ // src.
+ //
+ // R_TMP0 = len(dst) - d
+ // R_TMP1 = len(src) - s
+ MOVQ R_DEND, R_TMP0
+ SUBQ R_DST, R_TMP0
+ MOVQ R_SEND, R_TMP1
+ SUBQ R_SRC, R_TMP1
+
+ // !!! Try a faster technique for short (16 or fewer bytes) copies.
+ //
+ // if length > 16 || len(dst)-d < 16 || len(src)-s < 16 {
+ // goto callMemmove // Fall back on calling runtime·memmove.
+ // }
+ //
+ // The C++ snappy code calls this TryFastAppend. It also checks len(src)-s
+ // against 21 instead of 16, because it cannot assume that all of its input
+ // is contiguous in memory and so it needs to leave enough source bytes to
+ // read the next tag without refilling buffers, but Go's Decode assumes
+ // contiguousness (the src argument is a []byte).
+ CMPQ R_LEN, $16
+ JGT callMemmove
+ CMPQ R_TMP0, $16
+ JLT callMemmove
+ CMPQ R_TMP1, $16
+ JLT callMemmove
+
+ // !!! Implement the copy from src to dst as a 16-byte load and store.
+ // (Decode's documentation says that dst and src must not overlap.)
+ //
+ // This always copies 16 bytes, instead of only length bytes, but that's
+ // OK. If the input is a valid Snappy encoding then subsequent iterations
+ // will fix up the overrun. Otherwise, Decode returns a nil []byte (and a
+ // non-nil error), so the overrun will be ignored.
+ //
+ // Note that on amd64, it is legal and cheap to issue unaligned 8-byte or
+ // 16-byte loads and stores. This technique probably wouldn't be as
+ // effective on architectures that are fussier about alignment.
+ MOVOU 0(R_SRC), X0
+ MOVOU X0, 0(R_DST)
+
+ // d += length
+ // s += length
+ ADDQ R_LEN, R_DST
+ ADDQ R_LEN, R_SRC
+ JMP loop
+
+callMemmove:
+ // if length > len(dst)-d || length > len(src)-s { etc }
+ CMPQ R_LEN, R_TMP0
+ JGT errCorrupt
+ CMPQ R_LEN, R_TMP1
+ JGT errCorrupt
+
+ // copy(dst[d:], src[s:s+length])
+ //
+ // This means calling runtime·memmove(&dst[d], &src[s], length), so we push
+ // R_DST, R_SRC and R_LEN as arguments. Coincidentally, we also need to spill those
+ // three registers to the stack, to save local variables across the CALL.
+ MOVQ R_DST, 0(SP)
+ MOVQ R_SRC, 8(SP)
+ MOVQ R_LEN, 16(SP)
+ MOVQ R_DST, 24(SP)
+ MOVQ R_SRC, 32(SP)
+ MOVQ R_LEN, 40(SP)
+ MOVQ R_OFF, 48(SP)
+ CALL runtime·memmove(SB)
+
+ // Restore local variables: unspill registers from the stack and
+ // re-calculate R_DBASE-R_SEND.
+ MOVQ 24(SP), R_DST
+ MOVQ 32(SP), R_SRC
+ MOVQ 40(SP), R_LEN
+ MOVQ 48(SP), R_OFF
+ MOVQ dst_base+0(FP), R_DBASE
+ MOVQ dst_len+8(FP), R_DLEN
+ MOVQ R_DBASE, R_DEND
+ ADDQ R_DLEN, R_DEND
+ MOVQ src_base+24(FP), R_SBASE
+ MOVQ src_len+32(FP), R_SLEN
+ MOVQ R_SBASE, R_SEND
+ ADDQ R_SLEN, R_SEND
+
+ // d += length
+ // s += length
+ ADDQ R_LEN, R_DST
+ ADDQ R_LEN, R_SRC
+ JMP loop
+
+tagLit60Plus:
+ // !!! This fragment does the
+ //
+ // s += x - 58; if uint(s) > uint(len(src)) { etc }
+ //
+ // checks. In the asm version, we code it once instead of once per switch case.
+ ADDQ R_LEN, R_SRC
+ SUBQ $58, R_SRC
+ CMPQ R_SRC, R_SEND
+ JA errCorrupt
+
+ // case x == 60:
+ CMPL R_LEN, $61
+ JEQ tagLit61
+ JA tagLit62Plus
+
+ // x = uint32(src[s-1])
+ MOVBLZX -1(R_SRC), R_LEN
+ JMP doLit
+
+tagLit61:
+ // case x == 61:
+ // x = uint32(src[s-2]) | uint32(src[s-1])<<8
+ MOVWLZX -2(R_SRC), R_LEN
+ JMP doLit
+
+tagLit62Plus:
+ CMPL R_LEN, $62
+ JA tagLit63
+
+ // case x == 62:
+ // x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
+ // We read one byte, safe to read one back, since we are just reading tag.
+ // x = binary.LittleEndian.Uint32(src[s-1:]) >> 8
+ MOVL -4(R_SRC), R_LEN
+ SHRL $8, R_LEN
+ JMP doLit
+
+tagLit63:
+ // case x == 63:
+ // x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
+ MOVL -4(R_SRC), R_LEN
+ JMP doLit
+
+// The code above handles literal tags.
+// ----------------------------------------
+// The code below handles copy tags.
+
+tagCopy4:
+ // case tagCopy4:
+ // s += 5
+ ADDQ $5, R_SRC
+
+ // if uint(s) > uint(len(src)) { etc }
+ CMPQ R_SRC, R_SEND
+ JA errCorrupt
+
+ // length = 1 + int(src[s-5])>>2
+ SHRQ $2, R_LEN
+ INCQ R_LEN
+
+ // offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
+ MOVLQZX -4(R_SRC), R_OFF
+ JMP doCopy
+
+tagCopy2:
+ // case tagCopy2:
+ // s += 3
+ ADDQ $3, R_SRC
+
+ // if uint(s) > uint(len(src)) { etc }
+ CMPQ R_SRC, R_SEND
+ JA errCorrupt
+
+ // length = 1 + int(src[s-3])>>2
+ SHRQ $2, R_LEN
+ INCQ R_LEN
+
+ // offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
+ MOVWQZX -2(R_SRC), R_OFF
+ JMP doCopy
+
+tagCopy:
+ // We have a copy tag. We assume that:
+ // - R_TMP1 == src[s] & 0x03
+ // - R_LEN == src[s]
+ CMPQ R_TMP1, $2
+ JEQ tagCopy2
+ JA tagCopy4
+
+ // case tagCopy1:
+ // s += 2
+ ADDQ $2, R_SRC
+
+ // if uint(s) > uint(len(src)) { etc }
+ CMPQ R_SRC, R_SEND
+ JA errCorrupt
+
+ // offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
+ // length = 4 + int(src[s-2])>>2&0x7
+ MOVBQZX -1(R_SRC), R_TMP1
+ MOVQ R_LEN, R_TMP0
+ SHRQ $2, R_LEN
+ ANDQ $0xe0, R_TMP0
+ ANDQ $7, R_LEN
+ SHLQ $3, R_TMP0
+ ADDQ $4, R_LEN
+ ORQ R_TMP1, R_TMP0
+
+ // check if repeat code, ZF set by ORQ.
+ JZ repeatCode
+
+ // This is a regular copy, transfer our temporary value to R_OFF (length)
+ MOVQ R_TMP0, R_OFF
+ JMP doCopy
+
+// This is a repeat code.
+repeatCode:
+ // If length < 9, reuse last offset, with the length already calculated.
+ CMPQ R_LEN, $9
+ JL doCopyRepeat
+
+ // Read additional bytes for length.
+ JE repeatLen1
+
+ // Rare, so the extra branch shouldn't hurt too much.
+ CMPQ R_LEN, $10
+ JE repeatLen2
+ JMP repeatLen3
+
+// Read repeat lengths.
+repeatLen1:
+ // s ++
+ ADDQ $1, R_SRC
+
+ // if uint(s) > uint(len(src)) { etc }
+ CMPQ R_SRC, R_SEND
+ JA errCorrupt
+
+ // length = src[s-1] + 8
+ MOVBQZX -1(R_SRC), R_LEN
+ ADDL $8, R_LEN
+ JMP doCopyRepeat
+
+repeatLen2:
+ // s +=2
+ ADDQ $2, R_SRC
+
+ // if uint(s) > uint(len(src)) { etc }
+ CMPQ R_SRC, R_SEND
+ JA errCorrupt
+
+ // length = uint32(src[s-2]) | (uint32(src[s-1])<<8) + (1 << 8)
+ MOVWQZX -2(R_SRC), R_LEN
+ ADDL $260, R_LEN
+ JMP doCopyRepeat
+
+repeatLen3:
+ // s +=3
+ ADDQ $3, R_SRC
+
+ // if uint(s) > uint(len(src)) { etc }
+ CMPQ R_SRC, R_SEND
+ JA errCorrupt
+
+ // length = uint32(src[s-3]) | (uint32(src[s-2])<<8) | (uint32(src[s-1])<<16) + (1 << 16)
+ // Read one byte further back (just part of the tag, shifted out)
+ MOVL -4(R_SRC), R_LEN
+ SHRL $8, R_LEN
+ ADDL $65540, R_LEN
+ JMP doCopyRepeat
+
+doCopy:
+ // This is the end of the outer "switch", when we have a copy tag.
+ //
+ // We assume that:
+ // - R_LEN == length && R_LEN > 0
+ // - R_OFF == offset
+
+ // if d < offset { etc }
+ MOVQ R_DST, R_TMP1
+ SUBQ R_DBASE, R_TMP1
+ CMPQ R_TMP1, R_OFF
+ JLT errCorrupt
+
+ // Repeat values can skip the test above, since any offset > 0 will be in dst.
+doCopyRepeat:
+ // if offset <= 0 { etc }
+ CMPQ R_OFF, $0
+ JLE errCorrupt
+
+ // if length > len(dst)-d { etc }
+ MOVQ R_DEND, R_TMP1
+ SUBQ R_DST, R_TMP1
+ CMPQ R_LEN, R_TMP1
+ JGT errCorrupt
+
+ // forwardCopy(dst[d:d+length], dst[d-offset:]); d += length
+ //
+ // Set:
+ // - R_TMP2 = len(dst)-d
+ // - R_TMP3 = &dst[d-offset]
+ MOVQ R_DEND, R_TMP2
+ SUBQ R_DST, R_TMP2
+ MOVQ R_DST, R_TMP3
+ SUBQ R_OFF, R_TMP3
+
+ // !!! Try a faster technique for short (16 or fewer bytes) forward copies.
+ //
+ // First, try using two 8-byte load/stores, similar to the doLit technique
+ // above. Even if dst[d:d+length] and dst[d-offset:] can overlap, this is
+ // still OK if offset >= 8. Note that this has to be two 8-byte load/stores
+ // and not one 16-byte load/store, and the first store has to be before the
+ // second load, due to the overlap if offset is in the range [8, 16).
+ //
+ // if length > 16 || offset < 8 || len(dst)-d < 16 {
+ // goto slowForwardCopy
+ // }
+ // copy 16 bytes
+ // d += length
+ CMPQ R_LEN, $16
+ JGT slowForwardCopy
+ CMPQ R_OFF, $8
+ JLT slowForwardCopy
+ CMPQ R_TMP2, $16
+ JLT slowForwardCopy
+ MOVQ 0(R_TMP3), R_TMP0
+ MOVQ R_TMP0, 0(R_DST)
+ MOVQ 8(R_TMP3), R_TMP1
+ MOVQ R_TMP1, 8(R_DST)
+ ADDQ R_LEN, R_DST
+ JMP loop
+
+slowForwardCopy:
+ // !!! If the forward copy is longer than 16 bytes, or if offset < 8, we
+ // can still try 8-byte load stores, provided we can overrun up to 10 extra
+ // bytes. As above, the overrun will be fixed up by subsequent iterations
+ // of the outermost loop.
+ //
+ // The C++ snappy code calls this technique IncrementalCopyFastPath. Its
+ // commentary says:
+ //
+ // ----
+ //
+ // The main part of this loop is a simple copy of eight bytes at a time
+ // until we've copied (at least) the requested amount of bytes. However,
+ // if d and d-offset are less than eight bytes apart (indicating a
+ // repeating pattern of length < 8), we first need to expand the pattern in
+ // order to get the correct results. For instance, if the buffer looks like
+ // this, with the eight-byte and patterns marked as
+ // intervals:
+ //
+ // abxxxxxxxxxxxx
+ // [------] d-offset
+ // [------] d
+ //
+ // a single eight-byte copy from to will repeat the pattern
+ // once, after which we can move two bytes without moving :
+ //
+ // ababxxxxxxxxxx
+ // [------] d-offset
+ // [------] d
+ //
+ // and repeat the exercise until the two no longer overlap.
+ //
+ // This allows us to do very well in the special case of one single byte
+ // repeated many times, without taking a big hit for more general cases.
+ //
+ // The worst case of extra writing past the end of the match occurs when
+ // offset == 1 and length == 1; the last copy will read from byte positions
+ // [0..7] and write to [4..11], whereas it was only supposed to write to
+ // position 1. Thus, ten excess bytes.
+ //
+ // ----
+ //
+ // That "10 byte overrun" worst case is confirmed by Go's
+ // TestSlowForwardCopyOverrun, which also tests the fixUpSlowForwardCopy
+ // and finishSlowForwardCopy algorithm.
+ //
+ // if length > len(dst)-d-10 {
+ // goto verySlowForwardCopy
+ // }
+ SUBQ $10, R_TMP2
+ CMPQ R_LEN, R_TMP2
+ JGT verySlowForwardCopy
+
+ // We want to keep the offset, so we use R_TMP2 from here.
+ MOVQ R_OFF, R_TMP2
+
+makeOffsetAtLeast8:
+ // !!! As above, expand the pattern so that offset >= 8 and we can use
+ // 8-byte load/stores.
+ //
+ // for offset < 8 {
+ // copy 8 bytes from dst[d-offset:] to dst[d:]
+ // length -= offset
+ // d += offset
+ // offset += offset
+ // // The two previous lines together means that d-offset, and therefore
+ // // R_TMP3, is unchanged.
+ // }
+ CMPQ R_TMP2, $8
+ JGE fixUpSlowForwardCopy
+ MOVQ (R_TMP3), R_TMP1
+ MOVQ R_TMP1, (R_DST)
+ SUBQ R_TMP2, R_LEN
+ ADDQ R_TMP2, R_DST
+ ADDQ R_TMP2, R_TMP2
+ JMP makeOffsetAtLeast8
+
+fixUpSlowForwardCopy:
+ // !!! Add length (which might be negative now) to d (implied by R_DST being
+ // &dst[d]) so that d ends up at the right place when we jump back to the
+ // top of the loop. Before we do that, though, we save R_DST to R_TMP0 so that, if
+ // length is positive, copying the remaining length bytes will write to the
+ // right place.
+ MOVQ R_DST, R_TMP0
+ ADDQ R_LEN, R_DST
+
+finishSlowForwardCopy:
+ // !!! Repeat 8-byte load/stores until length <= 0. Ending with a negative
+ // length means that we overrun, but as above, that will be fixed up by
+ // subsequent iterations of the outermost loop.
+ CMPQ R_LEN, $0
+ JLE loop
+ MOVQ (R_TMP3), R_TMP1
+ MOVQ R_TMP1, (R_TMP0)
+ ADDQ $8, R_TMP3
+ ADDQ $8, R_TMP0
+ SUBQ $8, R_LEN
+ JMP finishSlowForwardCopy
+
+verySlowForwardCopy:
+ // verySlowForwardCopy is a simple implementation of forward copy. In C
+ // parlance, this is a do/while loop instead of a while loop, since we know
+ // that length > 0. In Go syntax:
+ //
+ // for {
+ // dst[d] = dst[d - offset]
+ // d++
+ // length--
+ // if length == 0 {
+ // break
+ // }
+ // }
+ MOVB (R_TMP3), R_TMP1
+ MOVB R_TMP1, (R_DST)
+ INCQ R_TMP3
+ INCQ R_DST
+ DECQ R_LEN
+ JNZ verySlowForwardCopy
+ JMP loop
+
+// The code above handles copy tags.
+// ----------------------------------------
+
+end:
+ // This is the end of the "for s < len(src)".
+ //
+ // if d != len(dst) { etc }
+ CMPQ R_DST, R_DEND
+ JNE errCorrupt
+
+ // return 0
+ MOVQ $0, ret+48(FP)
+ RET
+
+errCorrupt:
+ // return decodeErrCodeCorrupt
+ MOVQ $1, ret+48(FP)
+ RET
diff --git a/vendor/github.com/klauspost/compress/s2/decode_arm64.s b/vendor/github.com/klauspost/compress/s2/decode_arm64.s
new file mode 100644
index 00000000000..78e463f342b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/decode_arm64.s
@@ -0,0 +1,574 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !appengine
+// +build gc
+// +build !noasm
+
+#include "textflag.h"
+
+#define R_TMP0 R2
+#define R_TMP1 R3
+#define R_LEN R4
+#define R_OFF R5
+#define R_SRC R6
+#define R_DST R7
+#define R_DBASE R8
+#define R_DLEN R9
+#define R_DEND R10
+#define R_SBASE R11
+#define R_SLEN R12
+#define R_SEND R13
+#define R_TMP2 R14
+#define R_TMP3 R15
+
+// TEST_SRC will check if R_SRC is <= SRC_END
+#define TEST_SRC() \
+ CMP R_SEND, R_SRC \
+ BGT errCorrupt
+
+// MOVD R_SRC, R_TMP1
+// SUB R_SBASE, R_TMP1, R_TMP1
+// CMP R_SLEN, R_TMP1
+// BGT errCorrupt
+
+// The asm code generally follows the pure Go code in decode_other.go, except
+// where marked with a "!!!".
+
+// func decode(dst, src []byte) int
+//
+// All local variables fit into registers. The non-zero stack size is only to
+// spill registers and push args when issuing a CALL. The register allocation:
+// - R_TMP0 scratch
+// - R_TMP1 scratch
+// - R_LEN length or x
+// - R_OFF offset
+// - R_SRC &src[s]
+// - R_DST &dst[d]
+// + R_DBASE dst_base
+// + R_DLEN dst_len
+// + R_DEND dst_base + dst_len
+// + R_SBASE src_base
+// + R_SLEN src_len
+// + R_SEND src_base + src_len
+// - R_TMP2 used by doCopy
+// - R_TMP3 used by doCopy
+//
+// The registers R_DBASE-R_SEND (marked with a "+") are set at the start of the
+// function, and after a CALL returns, and are not otherwise modified.
+//
+// The d variable is implicitly R_DST - R_DBASE, and len(dst)-d is R_DEND - R_DST.
+// The s variable is implicitly R_SRC - R_SBASE, and len(src)-s is R_SEND - R_SRC.
+TEXT ·s2Decode(SB), NOSPLIT, $56-56
+ // Initialize R_SRC, R_DST and R_DBASE-R_SEND.
+ MOVD dst_base+0(FP), R_DBASE
+ MOVD dst_len+8(FP), R_DLEN
+ MOVD R_DBASE, R_DST
+ MOVD R_DBASE, R_DEND
+ ADD R_DLEN, R_DEND, R_DEND
+ MOVD src_base+24(FP), R_SBASE
+ MOVD src_len+32(FP), R_SLEN
+ MOVD R_SBASE, R_SRC
+ MOVD R_SBASE, R_SEND
+ ADD R_SLEN, R_SEND, R_SEND
+ MOVD $0, R_OFF
+
+loop:
+ // for s < len(src)
+ CMP R_SEND, R_SRC
+ BEQ end
+
+ // R_LEN = uint32(src[s])
+ //
+ // switch src[s] & 0x03
+ MOVBU (R_SRC), R_LEN
+ MOVW R_LEN, R_TMP1
+ ANDW $3, R_TMP1
+ MOVW $1, R1
+ CMPW R1, R_TMP1
+ BGE tagCopy
+
+ // ----------------------------------------
+ // The code below handles literal tags.
+
+ // case tagLiteral:
+ // x := uint32(src[s] >> 2)
+ // switch
+ MOVW $60, R1
+ LSRW $2, R_LEN, R_LEN
+ CMPW R_LEN, R1
+ BLS tagLit60Plus
+
+ // case x < 60:
+ // s++
+ ADD $1, R_SRC, R_SRC
+
+doLit:
+ // This is the end of the inner "switch", when we have a literal tag.
+ //
+ // We assume that R_LEN == x and x fits in a uint32, where x is the variable
+ // used in the pure Go decode_other.go code.
+
+ // length = int(x) + 1
+ //
+ // Unlike the pure Go code, we don't need to check if length <= 0 because
+ // R_LEN can hold 64 bits, so the increment cannot overflow.
+ ADD $1, R_LEN, R_LEN
+
+ // Prepare to check if copying length bytes will run past the end of dst or
+ // src.
+ //
+ // R_TMP0 = len(dst) - d
+ // R_TMP1 = len(src) - s
+ MOVD R_DEND, R_TMP0
+ SUB R_DST, R_TMP0, R_TMP0
+ MOVD R_SEND, R_TMP1
+ SUB R_SRC, R_TMP1, R_TMP1
+
+ // !!! Try a faster technique for short (16 or fewer bytes) copies.
+ //
+ // if length > 16 || len(dst)-d < 16 || len(src)-s < 16 {
+ // goto callMemmove // Fall back on calling runtime·memmove.
+ // }
+ //
+ // The C++ snappy code calls this TryFastAppend. It also checks len(src)-s
+ // against 21 instead of 16, because it cannot assume that all of its input
+ // is contiguous in memory and so it needs to leave enough source bytes to
+ // read the next tag without refilling buffers, but Go's Decode assumes
+ // contiguousness (the src argument is a []byte).
+ CMP $16, R_LEN
+ BGT callMemmove
+ CMP $16, R_TMP0
+ BLT callMemmove
+ CMP $16, R_TMP1
+ BLT callMemmove
+
+ // !!! Implement the copy from src to dst as a 16-byte load and store.
+ // (Decode's documentation says that dst and src must not overlap.)
+ //
+ // This always copies 16 bytes, instead of only length bytes, but that's
+ // OK. If the input is a valid Snappy encoding then subsequent iterations
+ // will fix up the overrun. Otherwise, Decode returns a nil []byte (and a
+ // non-nil error), so the overrun will be ignored.
+ //
+ // Note that on arm64, it is legal and cheap to issue unaligned 8-byte or
+ // 16-byte loads and stores. This technique probably wouldn't be as
+ // effective on architectures that are fussier about alignment.
+ LDP 0(R_SRC), (R_TMP2, R_TMP3)
+ STP (R_TMP2, R_TMP3), 0(R_DST)
+
+ // d += length
+ // s += length
+ ADD R_LEN, R_DST, R_DST
+ ADD R_LEN, R_SRC, R_SRC
+ B loop
+
+callMemmove:
+ // if length > len(dst)-d || length > len(src)-s { etc }
+ CMP R_TMP0, R_LEN
+ BGT errCorrupt
+ CMP R_TMP1, R_LEN
+ BGT errCorrupt
+
+ // copy(dst[d:], src[s:s+length])
+ //
+ // This means calling runtime·memmove(&dst[d], &src[s], length), so we push
+ // R_DST, R_SRC and R_LEN as arguments. Coincidentally, we also need to spill those
+ // three registers to the stack, to save local variables across the CALL.
+ MOVD R_DST, 8(RSP)
+ MOVD R_SRC, 16(RSP)
+ MOVD R_LEN, 24(RSP)
+ MOVD R_DST, 32(RSP)
+ MOVD R_SRC, 40(RSP)
+ MOVD R_LEN, 48(RSP)
+ MOVD R_OFF, 56(RSP)
+ CALL runtime·memmove(SB)
+
+ // Restore local variables: unspill registers from the stack and
+ // re-calculate R_DBASE-R_SEND.
+ MOVD 32(RSP), R_DST
+ MOVD 40(RSP), R_SRC
+ MOVD 48(RSP), R_LEN
+ MOVD 56(RSP), R_OFF
+ MOVD dst_base+0(FP), R_DBASE
+ MOVD dst_len+8(FP), R_DLEN
+ MOVD R_DBASE, R_DEND
+ ADD R_DLEN, R_DEND, R_DEND
+ MOVD src_base+24(FP), R_SBASE
+ MOVD src_len+32(FP), R_SLEN
+ MOVD R_SBASE, R_SEND
+ ADD R_SLEN, R_SEND, R_SEND
+
+ // d += length
+ // s += length
+ ADD R_LEN, R_DST, R_DST
+ ADD R_LEN, R_SRC, R_SRC
+ B loop
+
+tagLit60Plus:
+ // !!! This fragment does the
+ //
+ // s += x - 58; if uint(s) > uint(len(src)) { etc }
+ //
+ // checks. In the asm version, we code it once instead of once per switch case.
+ ADD R_LEN, R_SRC, R_SRC
+ SUB $58, R_SRC, R_SRC
+ TEST_SRC()
+
+ // case x == 60:
+ MOVW $61, R1
+ CMPW R1, R_LEN
+ BEQ tagLit61
+ BGT tagLit62Plus
+
+ // x = uint32(src[s-1])
+ MOVBU -1(R_SRC), R_LEN
+ B doLit
+
+tagLit61:
+ // case x == 61:
+ // x = uint32(src[s-2]) | uint32(src[s-1])<<8
+ MOVHU -2(R_SRC), R_LEN
+ B doLit
+
+tagLit62Plus:
+ CMPW $62, R_LEN
+ BHI tagLit63
+
+ // case x == 62:
+ // x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
+ MOVHU -3(R_SRC), R_LEN
+ MOVBU -1(R_SRC), R_TMP1
+ ORR R_TMP1<<16, R_LEN
+ B doLit
+
+tagLit63:
+ // case x == 63:
+ // x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
+ MOVWU -4(R_SRC), R_LEN
+ B doLit
+
+ // The code above handles literal tags.
+ // ----------------------------------------
+ // The code below handles copy tags.
+
+tagCopy4:
+ // case tagCopy4:
+ // s += 5
+ ADD $5, R_SRC, R_SRC
+
+ // if uint(s) > uint(len(src)) { etc }
+ MOVD R_SRC, R_TMP1
+ SUB R_SBASE, R_TMP1, R_TMP1
+ CMP R_SLEN, R_TMP1
+ BGT errCorrupt
+
+ // length = 1 + int(src[s-5])>>2
+ MOVD $1, R1
+ ADD R_LEN>>2, R1, R_LEN
+
+ // offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
+ MOVWU -4(R_SRC), R_OFF
+ B doCopy
+
+tagCopy2:
+ // case tagCopy2:
+ // s += 3
+ ADD $3, R_SRC, R_SRC
+
+ // if uint(s) > uint(len(src)) { etc }
+ TEST_SRC()
+
+ // length = 1 + int(src[s-3])>>2
+ MOVD $1, R1
+ ADD R_LEN>>2, R1, R_LEN
+
+ // offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
+ MOVHU -2(R_SRC), R_OFF
+ B doCopy
+
+tagCopy:
+ // We have a copy tag. We assume that:
+ // - R_TMP1 == src[s] & 0x03
+ // - R_LEN == src[s]
+ CMP $2, R_TMP1
+ BEQ tagCopy2
+ BGT tagCopy4
+
+ // case tagCopy1:
+ // s += 2
+ ADD $2, R_SRC, R_SRC
+
+ // if uint(s) > uint(len(src)) { etc }
+ TEST_SRC()
+
+ // offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
+ // Calculate offset in R_TMP0 in case it is a repeat.
+ MOVD R_LEN, R_TMP0
+ AND $0xe0, R_TMP0
+ MOVBU -1(R_SRC), R_TMP1
+ ORR R_TMP0<<3, R_TMP1, R_TMP0
+
+ // length = 4 + int(src[s-2])>>2&0x7
+ MOVD $7, R1
+ AND R_LEN>>2, R1, R_LEN
+ ADD $4, R_LEN, R_LEN
+
+ // check if repeat code with offset 0.
+ CMP $0, R_TMP0
+ BEQ repeatCode
+
+ // This is a regular copy, transfer our temporary value to R_OFF (offset)
+ MOVD R_TMP0, R_OFF
+ B doCopy
+
+ // This is a repeat code.
+repeatCode:
+ // If length < 9, reuse last offset, with the length already calculated.
+ CMP $9, R_LEN
+ BLT doCopyRepeat
+ BEQ repeatLen1
+ CMP $10, R_LEN
+ BEQ repeatLen2
+
+repeatLen3:
+ // s +=3
+ ADD $3, R_SRC, R_SRC
+
+ // if uint(s) > uint(len(src)) { etc }
+ TEST_SRC()
+
+ // length = uint32(src[s-3]) | (uint32(src[s-2])<<8) | (uint32(src[s-1])<<16) + 65540
+ MOVBU -1(R_SRC), R_TMP0
+ MOVHU -3(R_SRC), R_LEN
+ ORR R_TMP0<<16, R_LEN, R_LEN
+ ADD $65540, R_LEN, R_LEN
+ B doCopyRepeat
+
+repeatLen2:
+ // s +=2
+ ADD $2, R_SRC, R_SRC
+
+ // if uint(s) > uint(len(src)) { etc }
+ TEST_SRC()
+
+ // length = uint32(src[s-2]) | (uint32(src[s-1])<<8) + 260
+ MOVHU -2(R_SRC), R_LEN
+ ADD $260, R_LEN, R_LEN
+ B doCopyRepeat
+
+repeatLen1:
+ // s +=1
+ ADD $1, R_SRC, R_SRC
+
+ // if uint(s) > uint(len(src)) { etc }
+ TEST_SRC()
+
+ // length = src[s-1] + 8
+ MOVBU -1(R_SRC), R_LEN
+ ADD $8, R_LEN, R_LEN
+ B doCopyRepeat
+
+doCopy:
+ // This is the end of the outer "switch", when we have a copy tag.
+ //
+ // We assume that:
+ // - R_LEN == length && R_LEN > 0
+ // - R_OFF == offset
+
+ // if d < offset { etc }
+ MOVD R_DST, R_TMP1
+ SUB R_DBASE, R_TMP1, R_TMP1
+ CMP R_OFF, R_TMP1
+ BLT errCorrupt
+
+ // Repeat values can skip the test above, since any offset > 0 will be in dst.
+doCopyRepeat:
+
+ // if offset <= 0 { etc }
+ CMP $0, R_OFF
+ BLE errCorrupt
+
+ // if length > len(dst)-d { etc }
+ MOVD R_DEND, R_TMP1
+ SUB R_DST, R_TMP1, R_TMP1
+ CMP R_TMP1, R_LEN
+ BGT errCorrupt
+
+ // forwardCopy(dst[d:d+length], dst[d-offset:]); d += length
+ //
+ // Set:
+ // - R_TMP2 = len(dst)-d
+ // - R_TMP3 = &dst[d-offset]
+ MOVD R_DEND, R_TMP2
+ SUB R_DST, R_TMP2, R_TMP2
+ MOVD R_DST, R_TMP3
+ SUB R_OFF, R_TMP3, R_TMP3
+
+ // !!! Try a faster technique for short (16 or fewer bytes) forward copies.
+ //
+ // First, try using two 8-byte load/stores, similar to the doLit technique
+ // above. Even if dst[d:d+length] and dst[d-offset:] can overlap, this is
+ // still OK if offset >= 8. Note that this has to be two 8-byte load/stores
+ // and not one 16-byte load/store, and the first store has to be before the
+ // second load, due to the overlap if offset is in the range [8, 16).
+ //
+ // if length > 16 || offset < 8 || len(dst)-d < 16 {
+ // goto slowForwardCopy
+ // }
+ // copy 16 bytes
+ // d += length
+ CMP $16, R_LEN
+ BGT slowForwardCopy
+ CMP $8, R_OFF
+ BLT slowForwardCopy
+ CMP $16, R_TMP2
+ BLT slowForwardCopy
+ MOVD 0(R_TMP3), R_TMP0
+ MOVD R_TMP0, 0(R_DST)
+ MOVD 8(R_TMP3), R_TMP1
+ MOVD R_TMP1, 8(R_DST)
+ ADD R_LEN, R_DST, R_DST
+ B loop
+
+slowForwardCopy:
+ // !!! If the forward copy is longer than 16 bytes, or if offset < 8, we
+ // can still try 8-byte load stores, provided we can overrun up to 10 extra
+ // bytes. As above, the overrun will be fixed up by subsequent iterations
+ // of the outermost loop.
+ //
+ // The C++ snappy code calls this technique IncrementalCopyFastPath. Its
+ // commentary says:
+ //
+ // ----
+ //
+ // The main part of this loop is a simple copy of eight bytes at a time
+ // until we've copied (at least) the requested amount of bytes. However,
+ // if d and d-offset are less than eight bytes apart (indicating a
+ // repeating pattern of length < 8), we first need to expand the pattern in
+ // order to get the correct results. For instance, if the buffer looks like
+ // this, with the eight-byte and patterns marked as
+ // intervals:
+ //
+ // abxxxxxxxxxxxx
+ // [------] d-offset
+ // [------] d
+ //
+ // a single eight-byte copy from to will repeat the pattern
+ // once, after which we can move two bytes without moving :
+ //
+ // ababxxxxxxxxxx
+ // [------] d-offset
+ // [------] d
+ //
+ // and repeat the exercise until the two no longer overlap.
+ //
+ // This allows us to do very well in the special case of one single byte
+ // repeated many times, without taking a big hit for more general cases.
+ //
+ // The worst case of extra writing past the end of the match occurs when
+ // offset == 1 and length == 1; the last copy will read from byte positions
+ // [0..7] and write to [4..11], whereas it was only supposed to write to
+ // position 1. Thus, ten excess bytes.
+ //
+ // ----
+ //
+ // That "10 byte overrun" worst case is confirmed by Go's
+ // TestSlowForwardCopyOverrun, which also tests the fixUpSlowForwardCopy
+ // and finishSlowForwardCopy algorithm.
+ //
+ // if length > len(dst)-d-10 {
+ // goto verySlowForwardCopy
+ // }
+ SUB $10, R_TMP2, R_TMP2
+ CMP R_TMP2, R_LEN
+ BGT verySlowForwardCopy
+
+ // We want to keep the offset, so we use R_TMP2 from here.
+ MOVD R_OFF, R_TMP2
+
+makeOffsetAtLeast8:
+ // !!! As above, expand the pattern so that offset >= 8 and we can use
+ // 8-byte load/stores.
+ //
+ // for offset < 8 {
+ // copy 8 bytes from dst[d-offset:] to dst[d:]
+ // length -= offset
+ // d += offset
+ // offset += offset
+ // // The two previous lines together means that d-offset, and therefore
+ // // R_TMP3, is unchanged.
+ // }
+ CMP $8, R_TMP2
+ BGE fixUpSlowForwardCopy
+ MOVD (R_TMP3), R_TMP1
+ MOVD R_TMP1, (R_DST)
+ SUB R_TMP2, R_LEN, R_LEN
+ ADD R_TMP2, R_DST, R_DST
+ ADD R_TMP2, R_TMP2, R_TMP2
+ B makeOffsetAtLeast8
+
+fixUpSlowForwardCopy:
+ // !!! Add length (which might be negative now) to d (implied by R_DST being
+ // &dst[d]) so that d ends up at the right place when we jump back to the
+ // top of the loop. Before we do that, though, we save R_DST to R_TMP0 so that, if
+ // length is positive, copying the remaining length bytes will write to the
+ // right place.
+ MOVD R_DST, R_TMP0
+ ADD R_LEN, R_DST, R_DST
+
+finishSlowForwardCopy:
+ // !!! Repeat 8-byte load/stores until length <= 0. Ending with a negative
+ // length means that we overrun, but as above, that will be fixed up by
+ // subsequent iterations of the outermost loop.
+ MOVD $0, R1
+ CMP R1, R_LEN
+ BLE loop
+ MOVD (R_TMP3), R_TMP1
+ MOVD R_TMP1, (R_TMP0)
+ ADD $8, R_TMP3, R_TMP3
+ ADD $8, R_TMP0, R_TMP0
+ SUB $8, R_LEN, R_LEN
+ B finishSlowForwardCopy
+
+verySlowForwardCopy:
+ // verySlowForwardCopy is a simple implementation of forward copy. In C
+ // parlance, this is a do/while loop instead of a while loop, since we know
+ // that length > 0. In Go syntax:
+ //
+ // for {
+ // dst[d] = dst[d - offset]
+ // d++
+ // length--
+ // if length == 0 {
+ // break
+ // }
+ // }
+ MOVB (R_TMP3), R_TMP1
+ MOVB R_TMP1, (R_DST)
+ ADD $1, R_TMP3, R_TMP3
+ ADD $1, R_DST, R_DST
+ SUB $1, R_LEN, R_LEN
+ CBNZ R_LEN, verySlowForwardCopy
+ B loop
+
+ // The code above handles copy tags.
+ // ----------------------------------------
+
+end:
+ // This is the end of the "for s < len(src)".
+ //
+ // if d != len(dst) { etc }
+ CMP R_DEND, R_DST
+ BNE errCorrupt
+
+ // return 0
+ MOVD $0, ret+48(FP)
+ RET
+
+errCorrupt:
+ // return decodeErrCodeCorrupt
+ MOVD $1, R_TMP0
+ MOVD R_TMP0, ret+48(FP)
+ RET
diff --git a/vendor/github.com/klauspost/compress/s2/decode_asm.go b/vendor/github.com/klauspost/compress/s2/decode_asm.go
new file mode 100644
index 00000000000..cb3576edd47
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/decode_asm.go
@@ -0,0 +1,17 @@
+// Copyright 2016 The Snappy-Go Authors. All rights reserved.
+// Copyright (c) 2019 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (amd64 || arm64) && !appengine && gc && !noasm
+// +build amd64 arm64
+// +build !appengine
+// +build gc
+// +build !noasm
+
+package s2
+
+// decode has the same semantics as in decode_other.go.
+//
+//go:noescape
+func s2Decode(dst, src []byte) int
diff --git a/vendor/github.com/klauspost/compress/s2/decode_other.go b/vendor/github.com/klauspost/compress/s2/decode_other.go
new file mode 100644
index 00000000000..2905ba2774d
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/decode_other.go
@@ -0,0 +1,287 @@
+// Copyright 2016 The Snappy-Go Authors. All rights reserved.
+// Copyright (c) 2019 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (!amd64 && !arm64) || appengine || !gc || noasm
+
+package s2
+
+import (
+ "fmt"
+ "strconv"
+
+ "github.com/klauspost/compress/internal/le"
+)
+
+// decode writes the decoding of src to dst. It assumes that the varint-encoded
+// length of the decompressed bytes has already been read, and that len(dst)
+// equals that length.
+//
+// It returns 0 on success or a decodeErrCodeXxx error code on failure.
+func s2Decode(dst, src []byte) int {
+ const debug = false
+ if debug {
+ fmt.Println("Starting decode, dst len:", len(dst))
+ }
+ var d, s, length int
+ offset := 0
+
+ // As long as we can read at least 5 bytes...
+ for s < len(src)-5 {
+ // Removing bounds checks is SLOWER, when if doing
+ // in := src[s:s+5]
+ // Checked on Go 1.18
+ switch src[s] & 0x03 {
+ case tagLiteral:
+ x := uint32(src[s] >> 2)
+ switch {
+ case x < 60:
+ s++
+ case x == 60:
+ x = uint32(src[s+1])
+ s += 2
+ case x == 61:
+ x = uint32(le.Load16(src, s+1))
+ s += 3
+ case x == 62:
+ // Load as 32 bit and shift down.
+ x = le.Load32(src, s)
+ x >>= 8
+ s += 4
+ case x == 63:
+ x = le.Load32(src, s+1)
+ s += 5
+ }
+ length = int(x) + 1
+ if length > len(dst)-d || length > len(src)-s || (strconv.IntSize == 32 && length <= 0) {
+ if debug {
+ fmt.Println("corrupt: lit size", length)
+ }
+ return decodeErrCodeCorrupt
+ }
+ if debug {
+ fmt.Println("literals, length:", length, "d-after:", d+length)
+ }
+
+ copy(dst[d:], src[s:s+length])
+ d += length
+ s += length
+ continue
+
+ case tagCopy1:
+ s += 2
+ toffset := int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
+ length = int(src[s-2]) >> 2 & 0x7
+ if toffset == 0 {
+ if debug {
+ fmt.Print("(repeat) ")
+ }
+ // keep last offset
+ switch length {
+ case 5:
+ length = int(src[s]) + 4
+ s += 1
+ case 6:
+ length = int(le.Load16(src, s)) + 1<<8
+ s += 2
+ case 7:
+ in := src[s : s+3]
+ length = int((uint32(in[2])<<16)|(uint32(in[1])<<8)|uint32(in[0])) + (1 << 16)
+ s += 3
+ default: // 0-> 4
+ }
+ } else {
+ offset = toffset
+ }
+ length += 4
+ case tagCopy2:
+ offset = int(le.Load16(src, s+1))
+ length = 1 + int(src[s])>>2
+ s += 3
+
+ case tagCopy4:
+ offset = int(le.Load32(src, s+1))
+ length = 1 + int(src[s])>>2
+ s += 5
+ }
+
+ if offset <= 0 || d < offset || length > len(dst)-d {
+ if debug {
+ fmt.Println("corrupt: match, length", length, "offset:", offset, "dst avail:", len(dst)-d, "dst pos:", d)
+ }
+
+ return decodeErrCodeCorrupt
+ }
+
+ if debug {
+ fmt.Println("copy, length:", length, "offset:", offset, "d-after:", d+length)
+ }
+
+ // Copy from an earlier sub-slice of dst to a later sub-slice.
+ // If no overlap, use the built-in copy:
+ if offset > length {
+ copy(dst[d:d+length], dst[d-offset:])
+ d += length
+ continue
+ }
+
+ // Unlike the built-in copy function, this byte-by-byte copy always runs
+ // forwards, even if the slices overlap. Conceptually, this is:
+ //
+ // d += forwardCopy(dst[d:d+length], dst[d-offset:])
+ //
+ // We align the slices into a and b and show the compiler they are the same size.
+ // This allows the loop to run without bounds checks.
+ a := dst[d : d+length]
+ b := dst[d-offset:]
+ b = b[:len(a)]
+ for i := range a {
+ a[i] = b[i]
+ }
+ d += length
+ }
+
+ // Remaining with extra checks...
+ for s < len(src) {
+ switch src[s] & 0x03 {
+ case tagLiteral:
+ x := uint32(src[s] >> 2)
+ switch {
+ case x < 60:
+ s++
+ case x == 60:
+ s += 2
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-1])
+ case x == 61:
+ s += 3
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-2]) | uint32(src[s-1])<<8
+ case x == 62:
+ s += 4
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
+ case x == 63:
+ s += 5
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
+ }
+ length = int(x) + 1
+ if length > len(dst)-d || length > len(src)-s || (strconv.IntSize == 32 && length <= 0) {
+ if debug {
+ fmt.Println("corrupt: lit size", length)
+ }
+ return decodeErrCodeCorrupt
+ }
+ if debug {
+ fmt.Println("literals, length:", length, "d-after:", d+length)
+ }
+
+ copy(dst[d:], src[s:s+length])
+ d += length
+ s += length
+ continue
+
+ case tagCopy1:
+ s += 2
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ length = int(src[s-2]) >> 2 & 0x7
+ toffset := int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
+ if toffset == 0 {
+ if debug {
+ fmt.Print("(repeat) ")
+ }
+ // keep last offset
+ switch length {
+ case 5:
+ s += 1
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ length = int(uint32(src[s-1])) + 4
+ case 6:
+ s += 2
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ length = int(uint32(src[s-2])|(uint32(src[s-1])<<8)) + (1 << 8)
+ case 7:
+ s += 3
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ length = int(uint32(src[s-3])|(uint32(src[s-2])<<8)|(uint32(src[s-1])<<16)) + (1 << 16)
+ default: // 0-> 4
+ }
+ } else {
+ offset = toffset
+ }
+ length += 4
+ case tagCopy2:
+ s += 3
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ length = 1 + int(src[s-3])>>2
+ offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
+
+ case tagCopy4:
+ s += 5
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ length = 1 + int(src[s-5])>>2
+ offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
+ }
+
+ if offset <= 0 || d < offset || length > len(dst)-d {
+ if debug {
+ fmt.Println("corrupt: match, length", length, "offset:", offset, "dst avail:", len(dst)-d, "dst pos:", d)
+ }
+ return decodeErrCodeCorrupt
+ }
+
+ if debug {
+ fmt.Println("copy, length:", length, "offset:", offset, "d-after:", d+length)
+ }
+
+ // Copy from an earlier sub-slice of dst to a later sub-slice.
+ // If no overlap, use the built-in copy:
+ if offset > length {
+ copy(dst[d:d+length], dst[d-offset:])
+ d += length
+ continue
+ }
+
+ // Unlike the built-in copy function, this byte-by-byte copy always runs
+ // forwards, even if the slices overlap. Conceptually, this is:
+ //
+ // d += forwardCopy(dst[d:d+length], dst[d-offset:])
+ //
+ // We align the slices into a and b and show the compiler they are the same size.
+ // This allows the loop to run without bounds checks.
+ a := dst[d : d+length]
+ b := dst[d-offset:]
+ b = b[:len(a)]
+ for i := range a {
+ a[i] = b[i]
+ }
+ d += length
+ }
+
+ if d != len(dst) {
+ return decodeErrCodeCorrupt
+ }
+ return 0
+}
diff --git a/vendor/github.com/klauspost/compress/s2/dict.go b/vendor/github.com/klauspost/compress/s2/dict.go
new file mode 100644
index 00000000000..f125ad09637
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/dict.go
@@ -0,0 +1,350 @@
+// Copyright (c) 2022+ Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2
+
+import (
+ "bytes"
+ "encoding/binary"
+ "sync"
+)
+
+const (
+ // MinDictSize is the minimum dictionary size when repeat has been read.
+ MinDictSize = 16
+
+ // MaxDictSize is the maximum dictionary size when repeat has been read.
+ MaxDictSize = 65536
+
+ // MaxDictSrcOffset is the maximum offset where a dictionary entry can start.
+ MaxDictSrcOffset = 65535
+)
+
+// Dict contains a dictionary that can be used for encoding and decoding s2
+type Dict struct {
+ dict []byte
+ repeat int // Repeat as index of dict
+
+ fast, better, best sync.Once
+ fastTable *[1 << 14]uint16
+
+ betterTableShort *[1 << 14]uint16
+ betterTableLong *[1 << 17]uint16
+
+ bestTableShort *[1 << 16]uint32
+ bestTableLong *[1 << 19]uint32
+}
+
+// NewDict will read a dictionary.
+// It will return nil if the dictionary is invalid.
+func NewDict(dict []byte) *Dict {
+ if len(dict) == 0 {
+ return nil
+ }
+ var d Dict
+ // Repeat is the first value of the dict
+ r, n := binary.Uvarint(dict)
+ if n <= 0 {
+ return nil
+ }
+ dict = dict[n:]
+ d.dict = dict
+ if cap(d.dict) < len(d.dict)+16 {
+ d.dict = append(make([]byte, 0, len(d.dict)+16), d.dict...)
+ }
+ if len(dict) < MinDictSize || len(dict) > MaxDictSize {
+ return nil
+ }
+ d.repeat = int(r)
+ if d.repeat > len(dict) {
+ return nil
+ }
+ return &d
+}
+
+// Bytes will return a serialized version of the dictionary.
+// The output can be sent to NewDict.
+func (d *Dict) Bytes() []byte {
+ dst := make([]byte, binary.MaxVarintLen16+len(d.dict))
+ return append(dst[:binary.PutUvarint(dst, uint64(d.repeat))], d.dict...)
+}
+
+// MakeDict will create a dictionary.
+// 'data' must be at least MinDictSize.
+// If data is longer than MaxDictSize only the last MaxDictSize bytes will be used.
+// If searchStart is set the start repeat value will be set to the last
+// match of this content.
+// If no matches are found, it will attempt to find shorter matches.
+// This content should match the typical start of a block.
+// If at least 4 bytes cannot be matched, repeat is set to start of block.
+func MakeDict(data []byte, searchStart []byte) *Dict {
+ if len(data) == 0 {
+ return nil
+ }
+ if len(data) > MaxDictSize {
+ data = data[len(data)-MaxDictSize:]
+ }
+ var d Dict
+ dict := data
+ d.dict = dict
+ if cap(d.dict) < len(d.dict)+16 {
+ d.dict = append(make([]byte, 0, len(d.dict)+16), d.dict...)
+ }
+ if len(dict) < MinDictSize {
+ return nil
+ }
+
+ // Find the longest match possible, last entry if multiple.
+ for s := len(searchStart); s > 4; s-- {
+ if idx := bytes.LastIndex(data, searchStart[:s]); idx >= 0 && idx <= len(data)-8 {
+ d.repeat = idx
+ break
+ }
+ }
+
+ return &d
+}
+
+// MakeDictManual will create a dictionary.
+// 'data' must be at least MinDictSize and less than or equal to MaxDictSize.
+// A manual first repeat index into data must be provided.
+// It must be less than len(data)-8.
+func MakeDictManual(data []byte, firstIdx uint16) *Dict {
+ if len(data) < MinDictSize || int(firstIdx) >= len(data)-8 || len(data) > MaxDictSize {
+ return nil
+ }
+ var d Dict
+ dict := data
+ d.dict = dict
+ if cap(d.dict) < len(d.dict)+16 {
+ d.dict = append(make([]byte, 0, len(d.dict)+16), d.dict...)
+ }
+
+ d.repeat = int(firstIdx)
+ return &d
+}
+
+// Encode returns the encoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire encoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// The blocks will require the same amount of memory to decode as encoding,
+// and does not make for concurrent decoding.
+// Also note that blocks do not contain CRC information, so corruption may be undetected.
+//
+// If you need to encode larger amounts of data, consider using
+// the streaming interface which gives all of these features.
+func (d *Dict) Encode(dst, src []byte) []byte {
+ if n := MaxEncodedLen(len(src)); n < 0 {
+ panic(ErrTooLarge)
+ } else if cap(dst) < n {
+ dst = make([]byte, n)
+ } else {
+ dst = dst[:n]
+ }
+
+ // The block starts with the varint-encoded length of the decompressed bytes.
+ dstP := binary.PutUvarint(dst, uint64(len(src)))
+
+ if len(src) == 0 {
+ return dst[:dstP]
+ }
+ if len(src) < minNonLiteralBlockSize {
+ dstP += emitLiteral(dst[dstP:], src)
+ return dst[:dstP]
+ }
+ n := encodeBlockDictGo(dst[dstP:], src, d)
+ if n > 0 {
+ dstP += n
+ return dst[:dstP]
+ }
+ // Not compressible
+ dstP += emitLiteral(dst[dstP:], src)
+ return dst[:dstP]
+}
+
+// EncodeBetter returns the encoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire encoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// EncodeBetter compresses better than Encode but typically with a
+// 10-40% speed decrease on both compression and decompression.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// The blocks will require the same amount of memory to decode as encoding,
+// and does not make for concurrent decoding.
+// Also note that blocks do not contain CRC information, so corruption may be undetected.
+//
+// If you need to encode larger amounts of data, consider using
+// the streaming interface which gives all of these features.
+func (d *Dict) EncodeBetter(dst, src []byte) []byte {
+ if n := MaxEncodedLen(len(src)); n < 0 {
+ panic(ErrTooLarge)
+ } else if len(dst) < n {
+ dst = make([]byte, n)
+ }
+
+ // The block starts with the varint-encoded length of the decompressed bytes.
+ dstP := binary.PutUvarint(dst, uint64(len(src)))
+
+ if len(src) == 0 {
+ return dst[:dstP]
+ }
+ if len(src) < minNonLiteralBlockSize {
+ dstP += emitLiteral(dst[dstP:], src)
+ return dst[:dstP]
+ }
+ n := encodeBlockBetterDict(dst[dstP:], src, d)
+ if n > 0 {
+ dstP += n
+ return dst[:dstP]
+ }
+ // Not compressible
+ dstP += emitLiteral(dst[dstP:], src)
+ return dst[:dstP]
+}
+
+// EncodeBest returns the encoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire encoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// EncodeBest compresses as good as reasonably possible but with a
+// big speed decrease.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// The blocks will require the same amount of memory to decode as encoding,
+// and does not make for concurrent decoding.
+// Also note that blocks do not contain CRC information, so corruption may be undetected.
+//
+// If you need to encode larger amounts of data, consider using
+// the streaming interface which gives all of these features.
+func (d *Dict) EncodeBest(dst, src []byte) []byte {
+ if n := MaxEncodedLen(len(src)); n < 0 {
+ panic(ErrTooLarge)
+ } else if len(dst) < n {
+ dst = make([]byte, n)
+ }
+
+ // The block starts with the varint-encoded length of the decompressed bytes.
+ dstP := binary.PutUvarint(dst, uint64(len(src)))
+
+ if len(src) == 0 {
+ return dst[:dstP]
+ }
+ if len(src) < minNonLiteralBlockSize {
+ dstP += emitLiteral(dst[dstP:], src)
+ return dst[:dstP]
+ }
+ n := encodeBlockBest(dst[dstP:], src, d)
+ if n > 0 {
+ dstP += n
+ return dst[:dstP]
+ }
+ // Not compressible
+ dstP += emitLiteral(dst[dstP:], src)
+ return dst[:dstP]
+}
+
+// Decode returns the decoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire decoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+func (d *Dict) Decode(dst, src []byte) ([]byte, error) {
+ dLen, s, err := decodedLen(src)
+ if err != nil {
+ return nil, err
+ }
+ if dLen <= cap(dst) {
+ dst = dst[:dLen]
+ } else {
+ dst = make([]byte, dLen)
+ }
+ if s2DecodeDict(dst, src[s:], d) != 0 {
+ return nil, ErrCorrupt
+ }
+ return dst, nil
+}
+
+func (d *Dict) initFast() {
+ d.fast.Do(func() {
+ const (
+ tableBits = 14
+ maxTableSize = 1 << tableBits
+ )
+
+ var table [maxTableSize]uint16
+ // We stop so any entry of length 8 can always be read.
+ for i := 0; i < len(d.dict)-8-2; i += 3 {
+ x0 := load64(d.dict, i)
+ h0 := hash6(x0, tableBits)
+ h1 := hash6(x0>>8, tableBits)
+ h2 := hash6(x0>>16, tableBits)
+ table[h0] = uint16(i)
+ table[h1] = uint16(i + 1)
+ table[h2] = uint16(i + 2)
+ }
+ d.fastTable = &table
+ })
+}
+
+func (d *Dict) initBetter() {
+ d.better.Do(func() {
+ const (
+ // Long hash matches.
+ lTableBits = 17
+ maxLTableSize = 1 << lTableBits
+
+ // Short hash matches.
+ sTableBits = 14
+ maxSTableSize = 1 << sTableBits
+ )
+
+ var lTable [maxLTableSize]uint16
+ var sTable [maxSTableSize]uint16
+
+ // We stop so any entry of length 8 can always be read.
+ for i := 0; i < len(d.dict)-8; i++ {
+ cv := load64(d.dict, i)
+ lTable[hash7(cv, lTableBits)] = uint16(i)
+ sTable[hash4(cv, sTableBits)] = uint16(i)
+ }
+ d.betterTableShort = &sTable
+ d.betterTableLong = &lTable
+ })
+}
+
+func (d *Dict) initBest() {
+ d.best.Do(func() {
+ const (
+ // Long hash matches.
+ lTableBits = 19
+ maxLTableSize = 1 << lTableBits
+
+ // Short hash matches.
+ sTableBits = 16
+ maxSTableSize = 1 << sTableBits
+ )
+
+ var lTable [maxLTableSize]uint32
+ var sTable [maxSTableSize]uint32
+
+ // We stop so any entry of length 8 can always be read.
+ for i := 0; i < len(d.dict)-8; i++ {
+ cv := load64(d.dict, i)
+ hashL := hash8(cv, lTableBits)
+ hashS := hash4(cv, sTableBits)
+ candidateL := lTable[hashL]
+ candidateS := sTable[hashS]
+ lTable[hashL] = uint32(i) | candidateL<<16
+ sTable[hashS] = uint32(i) | candidateS<<16
+ }
+ d.bestTableShort = &sTable
+ d.bestTableLong = &lTable
+ })
+}
diff --git a/vendor/github.com/klauspost/compress/s2/encode.go b/vendor/github.com/klauspost/compress/s2/encode.go
new file mode 100644
index 00000000000..330e755716f
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/encode.go
@@ -0,0 +1,418 @@
+// Copyright 2011 The Snappy-Go Authors. All rights reserved.
+// Copyright (c) 2019 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2
+
+import (
+ "encoding/binary"
+ "math"
+ "math/bits"
+ "sync"
+
+ "github.com/klauspost/compress/internal/race"
+)
+
+// Encode returns the encoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire encoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// The blocks will require the same amount of memory to decode as encoding,
+// and does not make for concurrent decoding.
+// Also note that blocks do not contain CRC information, so corruption may be undetected.
+//
+// If you need to encode larger amounts of data, consider using
+// the streaming interface which gives all of these features.
+func Encode(dst, src []byte) []byte {
+ if n := MaxEncodedLen(len(src)); n < 0 {
+ panic(ErrTooLarge)
+ } else if cap(dst) < n {
+ dst = make([]byte, n)
+ } else {
+ dst = dst[:n]
+ }
+
+ // The block starts with the varint-encoded length of the decompressed bytes.
+ d := binary.PutUvarint(dst, uint64(len(src)))
+
+ if len(src) == 0 {
+ return dst[:d]
+ }
+ if len(src) < minNonLiteralBlockSize {
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+ }
+ n := encodeBlock(dst[d:], src)
+ if n > 0 {
+ d += n
+ return dst[:d]
+ }
+ // Not compressible
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+}
+
+var estblockPool [2]sync.Pool
+
+// EstimateBlockSize will perform a very fast compression
+// without outputting the result and return the compressed output size.
+// The function returns -1 if no improvement could be achieved.
+// Using actual compression will most often produce better compression than the estimate.
+func EstimateBlockSize(src []byte) (d int) {
+ if len(src) <= inputMargin || int64(len(src)) > 0xffffffff {
+ return -1
+ }
+ if len(src) <= 1024 {
+ const sz, pool = 2048, 0
+ tmp, ok := estblockPool[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer estblockPool[pool].Put(tmp)
+
+ d = calcBlockSizeSmall(src, tmp)
+ } else {
+ const sz, pool = 32768, 1
+ tmp, ok := estblockPool[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer estblockPool[pool].Put(tmp)
+
+ d = calcBlockSize(src, tmp)
+ }
+
+ if d == 0 {
+ return -1
+ }
+ // Size of the varint encoded block size.
+ d += (bits.Len64(uint64(len(src))) + 7) / 7
+
+ if d >= len(src) {
+ return -1
+ }
+ return d
+}
+
+// EncodeBetter returns the encoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire encoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// EncodeBetter compresses better than Encode but typically with a
+// 10-40% speed decrease on both compression and decompression.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// The blocks will require the same amount of memory to decode as encoding,
+// and does not make for concurrent decoding.
+// Also note that blocks do not contain CRC information, so corruption may be undetected.
+//
+// If you need to encode larger amounts of data, consider using
+// the streaming interface which gives all of these features.
+func EncodeBetter(dst, src []byte) []byte {
+ if n := MaxEncodedLen(len(src)); n < 0 {
+ panic(ErrTooLarge)
+ } else if cap(dst) < n {
+ dst = make([]byte, n)
+ } else {
+ dst = dst[:n]
+ }
+
+ // The block starts with the varint-encoded length of the decompressed bytes.
+ d := binary.PutUvarint(dst, uint64(len(src)))
+
+ if len(src) == 0 {
+ return dst[:d]
+ }
+ if len(src) < minNonLiteralBlockSize {
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+ }
+ n := encodeBlockBetter(dst[d:], src)
+ if n > 0 {
+ d += n
+ return dst[:d]
+ }
+ // Not compressible
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+}
+
+// EncodeBest returns the encoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire encoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// EncodeBest compresses as good as reasonably possible but with a
+// big speed decrease.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// The blocks will require the same amount of memory to decode as encoding,
+// and does not make for concurrent decoding.
+// Also note that blocks do not contain CRC information, so corruption may be undetected.
+//
+// If you need to encode larger amounts of data, consider using
+// the streaming interface which gives all of these features.
+func EncodeBest(dst, src []byte) []byte {
+ if n := MaxEncodedLen(len(src)); n < 0 {
+ panic(ErrTooLarge)
+ } else if cap(dst) < n {
+ dst = make([]byte, n)
+ } else {
+ dst = dst[:n]
+ }
+
+ // The block starts with the varint-encoded length of the decompressed bytes.
+ d := binary.PutUvarint(dst, uint64(len(src)))
+
+ if len(src) == 0 {
+ return dst[:d]
+ }
+ if len(src) < minNonLiteralBlockSize {
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+ }
+ n := encodeBlockBest(dst[d:], src, nil)
+ if n > 0 {
+ d += n
+ return dst[:d]
+ }
+ // Not compressible
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+}
+
+// EncodeSnappy returns the encoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire encoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// The output is Snappy compatible and will likely decompress faster.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// The blocks will require the same amount of memory to decode as encoding,
+// and does not make for concurrent decoding.
+// Also note that blocks do not contain CRC information, so corruption may be undetected.
+//
+// If you need to encode larger amounts of data, consider using
+// the streaming interface which gives all of these features.
+func EncodeSnappy(dst, src []byte) []byte {
+ if n := MaxEncodedLen(len(src)); n < 0 {
+ panic(ErrTooLarge)
+ } else if cap(dst) < n {
+ dst = make([]byte, n)
+ } else {
+ dst = dst[:n]
+ }
+
+ // The block starts with the varint-encoded length of the decompressed bytes.
+ d := binary.PutUvarint(dst, uint64(len(src)))
+
+ if len(src) == 0 {
+ return dst[:d]
+ }
+ if len(src) < minNonLiteralBlockSize {
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+ }
+
+ n := encodeBlockSnappy(dst[d:], src)
+ if n > 0 {
+ d += n
+ return dst[:d]
+ }
+ // Not compressible
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+}
+
+// EncodeSnappyBetter returns the encoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire encoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// The output is Snappy compatible and will likely decompress faster.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// The blocks will require the same amount of memory to decode as encoding,
+// and does not make for concurrent decoding.
+// Also note that blocks do not contain CRC information, so corruption may be undetected.
+//
+// If you need to encode larger amounts of data, consider using
+// the streaming interface which gives all of these features.
+func EncodeSnappyBetter(dst, src []byte) []byte {
+ if n := MaxEncodedLen(len(src)); n < 0 {
+ panic(ErrTooLarge)
+ } else if cap(dst) < n {
+ dst = make([]byte, n)
+ } else {
+ dst = dst[:n]
+ }
+
+ // The block starts with the varint-encoded length of the decompressed bytes.
+ d := binary.PutUvarint(dst, uint64(len(src)))
+
+ if len(src) == 0 {
+ return dst[:d]
+ }
+ if len(src) < minNonLiteralBlockSize {
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+ }
+
+ n := encodeBlockBetterSnappy(dst[d:], src)
+ if n > 0 {
+ d += n
+ return dst[:d]
+ }
+ // Not compressible
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+}
+
+// EncodeSnappyBest returns the encoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire encoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// The output is Snappy compatible and will likely decompress faster.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// The blocks will require the same amount of memory to decode as encoding,
+// and does not make for concurrent decoding.
+// Also note that blocks do not contain CRC information, so corruption may be undetected.
+//
+// If you need to encode larger amounts of data, consider using
+// the streaming interface which gives all of these features.
+func EncodeSnappyBest(dst, src []byte) []byte {
+ if n := MaxEncodedLen(len(src)); n < 0 {
+ panic(ErrTooLarge)
+ } else if cap(dst) < n {
+ dst = make([]byte, n)
+ } else {
+ dst = dst[:n]
+ }
+
+ // The block starts with the varint-encoded length of the decompressed bytes.
+ d := binary.PutUvarint(dst, uint64(len(src)))
+
+ if len(src) == 0 {
+ return dst[:d]
+ }
+ if len(src) < minNonLiteralBlockSize {
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+ }
+
+ n := encodeBlockBestSnappy(dst[d:], src)
+ if n > 0 {
+ d += n
+ return dst[:d]
+ }
+ // Not compressible
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+}
+
+// ConcatBlocks will concatenate the supplied blocks and append them to the supplied destination.
+// If the destination is nil or too small, a new will be allocated.
+// The blocks are not validated, so garbage in = garbage out.
+// dst may not overlap block data.
+// Any data in dst is preserved as is, so it will not be considered a block.
+func ConcatBlocks(dst []byte, blocks ...[]byte) ([]byte, error) {
+ totalSize := uint64(0)
+ compSize := 0
+ for _, b := range blocks {
+ l, hdr, err := decodedLen(b)
+ if err != nil {
+ return nil, err
+ }
+ totalSize += uint64(l)
+ compSize += len(b) - hdr
+ }
+ if totalSize == 0 {
+ dst = append(dst, 0)
+ return dst, nil
+ }
+ if totalSize > math.MaxUint32 {
+ return nil, ErrTooLarge
+ }
+ var tmp [binary.MaxVarintLen32]byte
+ hdrSize := binary.PutUvarint(tmp[:], totalSize)
+ wantSize := hdrSize + compSize
+
+ if cap(dst)-len(dst) < wantSize {
+ dst = append(make([]byte, 0, wantSize+len(dst)), dst...)
+ }
+ dst = append(dst, tmp[:hdrSize]...)
+ for _, b := range blocks {
+ _, hdr, err := decodedLen(b)
+ if err != nil {
+ return nil, err
+ }
+ dst = append(dst, b[hdr:]...)
+ }
+ return dst, nil
+}
+
+// inputMargin is the minimum number of extra input bytes to keep, inside
+// encodeBlock's inner loop. On some architectures, this margin lets us
+// implement a fast path for emitLiteral, where the copy of short (<= 16 byte)
+// literals can be implemented as a single load to and store from a 16-byte
+// register. That literal's actual length can be as short as 1 byte, so this
+// can copy up to 15 bytes too much, but that's OK as subsequent iterations of
+// the encoding loop will fix up the copy overrun, and this inputMargin ensures
+// that we don't overrun the dst and src buffers.
+const inputMargin = 8
+
+// minNonLiteralBlockSize is the minimum size of the input to encodeBlock that
+// will be accepted by the encoder.
+const minNonLiteralBlockSize = 32
+
+const intReduction = 2 - (1 << (^uint(0) >> 63)) // 1 (32 bits) or 0 (64 bits)
+
+// MaxBlockSize is the maximum value where MaxEncodedLen will return a valid block size.
+// Blocks this big are highly discouraged, though.
+// Half the size on 32 bit systems.
+const MaxBlockSize = (1<<(32-intReduction) - 1) - binary.MaxVarintLen32 - 5
+
+// MaxEncodedLen returns the maximum length of a snappy block, given its
+// uncompressed length.
+//
+// It will return a negative value if srcLen is too large to encode.
+// 32 bit platforms will have lower thresholds for rejecting big content.
+func MaxEncodedLen(srcLen int) int {
+ n := uint64(srcLen)
+ if intReduction == 1 {
+ // 32 bits
+ if n > math.MaxInt32 {
+ // Also includes negative.
+ return -1
+ }
+ } else if n > 0xffffffff {
+ // 64 bits
+ // Also includes negative.
+ return -1
+ }
+ // Size of the varint encoded block size.
+ n = n + uint64((bits.Len64(n)+7)/7)
+
+ // Add maximum size of encoding block as literals.
+ n += uint64(literalExtraSize(int64(srcLen)))
+ if intReduction == 1 {
+ // 32 bits
+ if n > math.MaxInt32 {
+ return -1
+ }
+ } else if n > 0xffffffff {
+ // 64 bits
+ // Also includes negative.
+ return -1
+ }
+ return int(n)
+}
diff --git a/vendor/github.com/klauspost/compress/s2/encode_all.go b/vendor/github.com/klauspost/compress/s2/encode_all.go
new file mode 100644
index 00000000000..9d12c44f38a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/encode_all.go
@@ -0,0 +1,1477 @@
+// Copyright 2016 The Snappy-Go Authors. All rights reserved.
+// Copyright (c) 2019 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "math/bits"
+
+ "github.com/klauspost/compress/internal/le"
+)
+
+func load32(b []byte, i int) uint32 {
+ return le.Load32(b, i)
+}
+
+func load64(b []byte, i int) uint64 {
+ return le.Load64(b, i)
+}
+
+// hash6 returns the hash of the lowest 6 bytes of u to fit in a hash table with h bits.
+// Preferably h should be a constant and should always be <64.
+func hash6(u uint64, h uint8) uint32 {
+ const prime6bytes = 227718039650203
+ return uint32(((u << (64 - 48)) * prime6bytes) >> ((64 - h) & 63))
+}
+
+func encodeGo(dst, src []byte) []byte {
+ if n := MaxEncodedLen(len(src)); n < 0 {
+ panic(ErrTooLarge)
+ } else if len(dst) < n {
+ dst = make([]byte, n)
+ }
+
+ // The block starts with the varint-encoded length of the decompressed bytes.
+ d := binary.PutUvarint(dst, uint64(len(src)))
+
+ if len(src) == 0 {
+ return dst[:d]
+ }
+ if len(src) < minNonLiteralBlockSize {
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+ }
+ var n int
+ if len(src) < 64<<10 {
+ n = encodeBlockGo64K(dst[d:], src)
+ } else {
+ n = encodeBlockGo(dst[d:], src)
+ }
+ if n > 0 {
+ d += n
+ return dst[:d]
+ }
+ // Not compressible
+ d += emitLiteral(dst[d:], src)
+ return dst[:d]
+}
+
+// encodeBlockGo encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlockGo(dst, src []byte) (d int) {
+ // Initialize the hash table.
+ const (
+ tableBits = 14
+ maxTableSize = 1 << tableBits
+
+ debug = false
+ )
+ var table [maxTableSize]uint32
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - len(src)>>5 - 5
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ cv := load64(src, s)
+
+ // We search for a repeat at -1, but don't output repeats when nextEmit == 0
+ repeat := 1
+
+ for {
+ candidate := 0
+ for {
+ // Next src position to check
+ nextS := s + (s-nextEmit)>>6 + 4
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hash0 := hash6(cv, tableBits)
+ hash1 := hash6(cv>>8, tableBits)
+ candidate = int(table[hash0])
+ candidate2 := int(table[hash1])
+ table[hash0] = uint32(s)
+ table[hash1] = uint32(s + 1)
+ hash2 := hash6(cv>>16, tableBits)
+
+ // Check repeat at offset checkRep.
+ const checkRep = 1
+ if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
+ base := s + checkRep
+ // Extend back
+ for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(base-nextEmit) > dstLimit {
+ return 0
+ }
+
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+
+ // Extend forward
+ candidate := s - repeat + 4 + checkRep
+ s += 4 + checkRep
+ for s <= sLimit {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+ if debug {
+ // Validate match.
+ if s <= candidate {
+ panic("s <= candidate")
+ }
+ a := src[base:s]
+ b := src[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+ if nextEmit > 0 {
+ // same as `add := emitCopy(dst[d:], repeat, s-base)` but skips storing offset.
+ d += emitRepeat(dst[d:], repeat, s-base)
+ } else {
+ // First match, cannot be repeat.
+ d += emitCopy(dst[d:], repeat, s-base)
+ }
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ cv = load64(src, s)
+ continue
+ }
+
+ if uint32(cv) == load32(src, candidate) {
+ break
+ }
+ candidate = int(table[hash2])
+ if uint32(cv>>8) == load32(src, candidate2) {
+ table[hash2] = uint32(s + 2)
+ candidate = candidate2
+ s++
+ break
+ }
+ table[hash2] = uint32(s + 2)
+ if uint32(cv>>16) == load32(src, candidate) {
+ s += 2
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards.
+ // The top bytes will be rechecked to get the full match.
+ for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
+ candidate--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ d += emitLiteral(dst[d:], src[nextEmit:s])
+
+ // Call emitCopy, and then see if another emitCopy could be our next
+ // move. Repeat until we find no match for the input immediately after
+ // what was consumed by the last emitCopy call.
+ //
+ // If we exit this loop normally then we need to call emitLiteral next,
+ // though we don't yet know how big the literal will be. We handle that
+ // by proceeding to the next iteration of the main loop. We also can
+ // exit this loop via goto if we get close to exhausting the input.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+ base := s
+ repeat = base - candidate
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidate += 4
+ for s <= len(src)-8 {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+
+ d += emitCopy(dst[d:], repeat, s-base)
+ if debug {
+ // Validate match.
+ if s <= candidate {
+ panic("s <= candidate")
+ }
+ a := src[base:s]
+ b := src[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+ // Check for an immediate match, otherwise start search at s+1
+ x := load64(src, s-2)
+ m2Hash := hash6(x, tableBits)
+ currHash := hash6(x>>16, tableBits)
+ candidate = int(table[currHash])
+ table[m2Hash] = uint32(s - 2)
+ table[currHash] = uint32(s)
+ if debug && s == candidate {
+ panic("s == candidate")
+ }
+ if uint32(x>>16) != load32(src, candidate) {
+ cv = load64(src, s+1)
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
+
+// encodeBlockGo64K is a specialized version for compressing blocks <= 64KB
+func encodeBlockGo64K(dst, src []byte) (d int) {
+ // Initialize the hash table.
+ const (
+ tableBits = 14
+ maxTableSize = 1 << tableBits
+
+ debug = false
+ )
+
+ var table [maxTableSize]uint16
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - len(src)>>5 - 5
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ cv := load64(src, s)
+
+ // We search for a repeat at -1, but don't output repeats when nextEmit == 0
+ repeat := 1
+
+ for {
+ candidate := 0
+ for {
+ // Next src position to check
+ nextS := s + (s-nextEmit)>>5 + 4
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hash0 := hash6(cv, tableBits)
+ hash1 := hash6(cv>>8, tableBits)
+ candidate = int(table[hash0])
+ candidate2 := int(table[hash1])
+ table[hash0] = uint16(s)
+ table[hash1] = uint16(s + 1)
+ hash2 := hash6(cv>>16, tableBits)
+
+ // Check repeat at offset checkRep.
+ const checkRep = 1
+ if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
+ base := s + checkRep
+ // Extend back
+ for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(base-nextEmit) > dstLimit {
+ return 0
+ }
+
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+
+ // Extend forward
+ candidate := s - repeat + 4 + checkRep
+ s += 4 + checkRep
+ for s <= sLimit {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+ if debug {
+ // Validate match.
+ if s <= candidate {
+ panic("s <= candidate")
+ }
+ a := src[base:s]
+ b := src[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+ if nextEmit > 0 {
+ // same as `add := emitCopy(dst[d:], repeat, s-base)` but skips storing offset.
+ d += emitRepeat(dst[d:], repeat, s-base)
+ } else {
+ // First match, cannot be repeat.
+ d += emitCopy(dst[d:], repeat, s-base)
+ }
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ cv = load64(src, s)
+ continue
+ }
+
+ if uint32(cv) == load32(src, candidate) {
+ break
+ }
+ candidate = int(table[hash2])
+ if uint32(cv>>8) == load32(src, candidate2) {
+ table[hash2] = uint16(s + 2)
+ candidate = candidate2
+ s++
+ break
+ }
+ table[hash2] = uint16(s + 2)
+ if uint32(cv>>16) == load32(src, candidate) {
+ s += 2
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards.
+ // The top bytes will be rechecked to get the full match.
+ for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
+ candidate--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ d += emitLiteral(dst[d:], src[nextEmit:s])
+
+ // Call emitCopy, and then see if another emitCopy could be our next
+ // move. Repeat until we find no match for the input immediately after
+ // what was consumed by the last emitCopy call.
+ //
+ // If we exit this loop normally then we need to call emitLiteral next,
+ // though we don't yet know how big the literal will be. We handle that
+ // by proceeding to the next iteration of the main loop. We also can
+ // exit this loop via goto if we get close to exhausting the input.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+ base := s
+ repeat = base - candidate
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidate += 4
+ for s <= len(src)-8 {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+
+ d += emitCopy(dst[d:], repeat, s-base)
+ if debug {
+ // Validate match.
+ if s <= candidate {
+ panic("s <= candidate")
+ }
+ a := src[base:s]
+ b := src[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+ // Check for an immediate match, otherwise start search at s+1
+ x := load64(src, s-2)
+ m2Hash := hash6(x, tableBits)
+ currHash := hash6(x>>16, tableBits)
+ candidate = int(table[currHash])
+ table[m2Hash] = uint16(s - 2)
+ table[currHash] = uint16(s)
+ if debug && s == candidate {
+ panic("s == candidate")
+ }
+ if uint32(x>>16) != load32(src, candidate) {
+ cv = load64(src, s+1)
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
+
+func encodeBlockSnappyGo(dst, src []byte) (d int) {
+ // Initialize the hash table.
+ const (
+ tableBits = 14
+ maxTableSize = 1 << tableBits
+ )
+ var table [maxTableSize]uint32
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - len(src)>>5 - 5
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ cv := load64(src, s)
+
+ // We search for a repeat at -1, but don't output repeats when nextEmit == 0
+ repeat := 1
+
+ for {
+ candidate := 0
+ for {
+ // Next src position to check
+ nextS := s + (s-nextEmit)>>6 + 4
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hash0 := hash6(cv, tableBits)
+ hash1 := hash6(cv>>8, tableBits)
+ candidate = int(table[hash0])
+ candidate2 := int(table[hash1])
+ table[hash0] = uint32(s)
+ table[hash1] = uint32(s + 1)
+ hash2 := hash6(cv>>16, tableBits)
+
+ // Check repeat at offset checkRep.
+ const checkRep = 1
+ if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
+ base := s + checkRep
+ // Extend back
+ for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+ // Bail if we exceed the maximum size.
+ if d+(base-nextEmit) > dstLimit {
+ return 0
+ }
+
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+
+ // Extend forward
+ candidate := s - repeat + 4 + checkRep
+ s += 4 + checkRep
+ for s <= sLimit {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+
+ d += emitCopyNoRepeat(dst[d:], repeat, s-base)
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ cv = load64(src, s)
+ continue
+ }
+
+ if uint32(cv) == load32(src, candidate) {
+ break
+ }
+ candidate = int(table[hash2])
+ if uint32(cv>>8) == load32(src, candidate2) {
+ table[hash2] = uint32(s + 2)
+ candidate = candidate2
+ s++
+ break
+ }
+ table[hash2] = uint32(s + 2)
+ if uint32(cv>>16) == load32(src, candidate) {
+ s += 2
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards
+ for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
+ candidate--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ d += emitLiteral(dst[d:], src[nextEmit:s])
+
+ // Call emitCopy, and then see if another emitCopy could be our next
+ // move. Repeat until we find no match for the input immediately after
+ // what was consumed by the last emitCopy call.
+ //
+ // If we exit this loop normally then we need to call emitLiteral next,
+ // though we don't yet know how big the literal will be. We handle that
+ // by proceeding to the next iteration of the main loop. We also can
+ // exit this loop via goto if we get close to exhausting the input.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+ base := s
+ repeat = base - candidate
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidate += 4
+ for s <= len(src)-8 {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+
+ d += emitCopyNoRepeat(dst[d:], repeat, s-base)
+ if false {
+ // Validate match.
+ a := src[base:s]
+ b := src[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+ // Check for an immediate match, otherwise start search at s+1
+ x := load64(src, s-2)
+ m2Hash := hash6(x, tableBits)
+ currHash := hash6(x>>16, tableBits)
+ candidate = int(table[currHash])
+ table[m2Hash] = uint32(s - 2)
+ table[currHash] = uint32(s)
+ if uint32(x>>16) != load32(src, candidate) {
+ cv = load64(src, s+1)
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
+
+// encodeBlockSnappyGo64K is a special version of encodeBlockSnappyGo for sizes <64KB
+func encodeBlockSnappyGo64K(dst, src []byte) (d int) {
+ // Initialize the hash table.
+ const (
+ tableBits = 14
+ maxTableSize = 1 << tableBits
+ )
+
+ var table [maxTableSize]uint16
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - len(src)>>5 - 5
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ cv := load64(src, s)
+
+ // We search for a repeat at -1, but don't output repeats when nextEmit == 0
+ repeat := 1
+
+ for {
+ candidate := 0
+ for {
+ // Next src position to check
+ nextS := s + (s-nextEmit)>>5 + 4
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hash0 := hash6(cv, tableBits)
+ hash1 := hash6(cv>>8, tableBits)
+ candidate = int(table[hash0])
+ candidate2 := int(table[hash1])
+ table[hash0] = uint16(s)
+ table[hash1] = uint16(s + 1)
+ hash2 := hash6(cv>>16, tableBits)
+
+ // Check repeat at offset checkRep.
+ const checkRep = 1
+ if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
+ base := s + checkRep
+ // Extend back
+ for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+ // Bail if we exceed the maximum size.
+ if d+(base-nextEmit) > dstLimit {
+ return 0
+ }
+
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+
+ // Extend forward
+ candidate := s - repeat + 4 + checkRep
+ s += 4 + checkRep
+ for s <= sLimit {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+
+ d += emitCopyNoRepeat(dst[d:], repeat, s-base)
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ cv = load64(src, s)
+ continue
+ }
+
+ if uint32(cv) == load32(src, candidate) {
+ break
+ }
+ candidate = int(table[hash2])
+ if uint32(cv>>8) == load32(src, candidate2) {
+ table[hash2] = uint16(s + 2)
+ candidate = candidate2
+ s++
+ break
+ }
+ table[hash2] = uint16(s + 2)
+ if uint32(cv>>16) == load32(src, candidate) {
+ s += 2
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards
+ for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
+ candidate--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ d += emitLiteral(dst[d:], src[nextEmit:s])
+
+ // Call emitCopy, and then see if another emitCopy could be our next
+ // move. Repeat until we find no match for the input immediately after
+ // what was consumed by the last emitCopy call.
+ //
+ // If we exit this loop normally then we need to call emitLiteral next,
+ // though we don't yet know how big the literal will be. We handle that
+ // by proceeding to the next iteration of the main loop. We also can
+ // exit this loop via goto if we get close to exhausting the input.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+ base := s
+ repeat = base - candidate
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidate += 4
+ for s <= len(src)-8 {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+
+ d += emitCopyNoRepeat(dst[d:], repeat, s-base)
+ if false {
+ // Validate match.
+ a := src[base:s]
+ b := src[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+ // Check for an immediate match, otherwise start search at s+1
+ x := load64(src, s-2)
+ m2Hash := hash6(x, tableBits)
+ currHash := hash6(x>>16, tableBits)
+ candidate = int(table[currHash])
+ table[m2Hash] = uint16(s - 2)
+ table[currHash] = uint16(s)
+ if uint32(x>>16) != load32(src, candidate) {
+ cv = load64(src, s+1)
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
+
+// encodeBlockGo encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlockDictGo(dst, src []byte, dict *Dict) (d int) {
+ // Initialize the hash table.
+ const (
+ tableBits = 14
+ maxTableSize = 1 << tableBits
+ maxAhead = 8 // maximum bytes ahead without checking sLimit
+
+ debug = false
+ )
+ dict.initFast()
+
+ var table [maxTableSize]uint32
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := min(len(src)-inputMargin, MaxDictSrcOffset-maxAhead)
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - len(src)>>5 - 5
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form can start with a dict entry (copy or repeat).
+ s := 0
+
+ // Convert dict repeat to offset
+ repeat := len(dict.dict) - dict.repeat
+ cv := load64(src, 0)
+
+ // While in dict
+searchDict:
+ for {
+ // Next src position to check
+ nextS := s + (s-nextEmit)>>6 + 4
+ hash0 := hash6(cv, tableBits)
+ hash1 := hash6(cv>>8, tableBits)
+ if nextS > sLimit {
+ if debug {
+ fmt.Println("slimit reached", s, nextS)
+ }
+ break searchDict
+ }
+ candidateDict := int(dict.fastTable[hash0])
+ candidateDict2 := int(dict.fastTable[hash1])
+ candidate2 := int(table[hash1])
+ candidate := int(table[hash0])
+ table[hash0] = uint32(s)
+ table[hash1] = uint32(s + 1)
+ hash2 := hash6(cv>>16, tableBits)
+
+ // Check repeat at offset checkRep.
+ const checkRep = 1
+
+ if repeat > s {
+ candidate := len(dict.dict) - repeat + s
+ if repeat-s >= 4 && uint32(cv) == load32(dict.dict, candidate) {
+ // Extend back
+ base := s
+ for i := candidate; base > nextEmit && i > 0 && dict.dict[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+ // Bail if we exceed the maximum size.
+ if d+(base-nextEmit) > dstLimit {
+ return 0
+ }
+
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+ if debug && nextEmit != base {
+ fmt.Println("emitted ", base-nextEmit, "literals")
+ }
+ s += 4
+ candidate += 4
+ for candidate < len(dict.dict)-8 && s <= len(src)-8 {
+ if diff := load64(src, s) ^ load64(dict.dict, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+ d += emitRepeat(dst[d:], repeat, s-base)
+ if debug {
+ fmt.Println("emitted dict repeat length", s-base, "offset:", repeat, "s:", s)
+ }
+ nextEmit = s
+ if s >= sLimit {
+ break searchDict
+ }
+ cv = load64(src, s)
+ continue
+ }
+ } else if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
+ base := s + checkRep
+ // Extend back
+ for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+ if debug && nextEmit != base {
+ fmt.Println("emitted ", base-nextEmit, "literals")
+ }
+
+ // Extend forward
+ candidate := s - repeat + 4 + checkRep
+ s += 4 + checkRep
+ for s <= sLimit {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+ if debug {
+ // Validate match.
+ if s <= candidate {
+ panic("s <= candidate")
+ }
+ a := src[base:s]
+ b := src[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+
+ if nextEmit > 0 {
+ // same as `add := emitCopy(dst[d:], repeat, s-base)` but skips storing offset.
+ d += emitRepeat(dst[d:], repeat, s-base)
+ } else {
+ // First match, cannot be repeat.
+ d += emitCopy(dst[d:], repeat, s-base)
+ }
+
+ nextEmit = s
+ if s >= sLimit {
+ break searchDict
+ }
+ if debug {
+ fmt.Println("emitted reg repeat", s-base, "s:", s)
+ }
+ cv = load64(src, s)
+ continue searchDict
+ }
+ if s == 0 {
+ cv = load64(src, nextS)
+ s = nextS
+ continue searchDict
+ }
+ // Start with table. These matches will always be closer.
+ if uint32(cv) == load32(src, candidate) {
+ goto emitMatch
+ }
+ candidate = int(table[hash2])
+ if uint32(cv>>8) == load32(src, candidate2) {
+ table[hash2] = uint32(s + 2)
+ candidate = candidate2
+ s++
+ goto emitMatch
+ }
+
+ // Check dict. Dicts have longer offsets, so we want longer matches.
+ if cv == load64(dict.dict, candidateDict) {
+ table[hash2] = uint32(s + 2)
+ goto emitDict
+ }
+
+ candidateDict = int(dict.fastTable[hash2])
+ // Check if upper 7 bytes match
+ if candidateDict2 >= 1 {
+ if cv^load64(dict.dict, candidateDict2-1) < (1 << 8) {
+ table[hash2] = uint32(s + 2)
+ candidateDict = candidateDict2
+ s++
+ goto emitDict
+ }
+ }
+
+ table[hash2] = uint32(s + 2)
+ if uint32(cv>>16) == load32(src, candidate) {
+ s += 2
+ goto emitMatch
+ }
+ if candidateDict >= 2 {
+ // Check if upper 6 bytes match
+ if cv^load64(dict.dict, candidateDict-2) < (1 << 16) {
+ s += 2
+ goto emitDict
+ }
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ continue searchDict
+
+ emitDict:
+ {
+ if debug {
+ if load32(dict.dict, candidateDict) != load32(src, s) {
+ panic("dict emit mismatch")
+ }
+ }
+ // Extend backwards.
+ // The top bytes will be rechecked to get the full match.
+ for candidateDict > 0 && s > nextEmit && dict.dict[candidateDict-1] == src[s-1] {
+ candidateDict--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ d += emitLiteral(dst[d:], src[nextEmit:s])
+ if debug && nextEmit != s {
+ fmt.Println("emitted ", s-nextEmit, "literals")
+ }
+ {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+ base := s
+ repeat = s + (len(dict.dict)) - candidateDict
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidateDict += 4
+ for s <= len(src)-8 && len(dict.dict)-candidateDict >= 8 {
+ if diff := load64(src, s) ^ load64(dict.dict, candidateDict); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidateDict += 8
+ }
+
+ // Matches longer than 64 are split.
+ if s <= sLimit || s-base < 8 {
+ d += emitCopy(dst[d:], repeat, s-base)
+ } else {
+ // Split to ensure we don't start a copy within next block
+ d += emitCopy(dst[d:], repeat, 4)
+ d += emitRepeat(dst[d:], repeat, s-base-4)
+ }
+ if false {
+ // Validate match.
+ if s <= candidate {
+ panic("s <= candidate")
+ }
+ a := src[base:s]
+ b := dict.dict[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+ if debug {
+ fmt.Println("emitted dict copy, length", s-base, "offset:", repeat, "s:", s)
+ }
+ nextEmit = s
+ if s >= sLimit {
+ break searchDict
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+
+ // Index and continue loop to try new candidate.
+ x := load64(src, s-2)
+ m2Hash := hash6(x, tableBits)
+ currHash := hash6(x>>8, tableBits)
+ table[m2Hash] = uint32(s - 2)
+ table[currHash] = uint32(s - 1)
+ cv = load64(src, s)
+ }
+ continue
+ }
+ emitMatch:
+
+ // Extend backwards.
+ // The top bytes will be rechecked to get the full match.
+ for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
+ candidate--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ d += emitLiteral(dst[d:], src[nextEmit:s])
+ if debug && nextEmit != s {
+ fmt.Println("emitted ", s-nextEmit, "literals")
+ }
+ // Call emitCopy, and then see if another emitCopy could be our next
+ // move. Repeat until we find no match for the input immediately after
+ // what was consumed by the last emitCopy call.
+ //
+ // If we exit this loop normally then we need to call emitLiteral next,
+ // though we don't yet know how big the literal will be. We handle that
+ // by proceeding to the next iteration of the main loop. We also can
+ // exit this loop via goto if we get close to exhausting the input.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+ base := s
+ repeat = base - candidate
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidate += 4
+ for s <= len(src)-8 {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+
+ d += emitCopy(dst[d:], repeat, s-base)
+ if debug {
+ // Validate match.
+ if s <= candidate {
+ panic("s <= candidate")
+ }
+ a := src[base:s]
+ b := src[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+ if debug {
+ fmt.Println("emitted src copy, length", s-base, "offset:", repeat, "s:", s)
+ }
+ nextEmit = s
+ if s >= sLimit {
+ break searchDict
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+ // Check for an immediate match, otherwise start search at s+1
+ x := load64(src, s-2)
+ m2Hash := hash6(x, tableBits)
+ currHash := hash6(x>>16, tableBits)
+ candidate = int(table[currHash])
+ table[m2Hash] = uint32(s - 2)
+ table[currHash] = uint32(s)
+ if debug && s == candidate {
+ panic("s == candidate")
+ }
+ if uint32(x>>16) != load32(src, candidate) {
+ cv = load64(src, s+1)
+ s++
+ break
+ }
+ }
+ }
+
+ // Search without dict:
+ if repeat > s {
+ repeat = 0
+ }
+
+ // No more dict
+ sLimit = len(src) - inputMargin
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ if debug {
+ fmt.Println("non-dict matching at", s, "repeat:", repeat)
+ }
+ cv = load64(src, s)
+ if debug {
+ fmt.Println("now", s, "->", sLimit, "out:", d, "left:", len(src)-s, "nextemit:", nextEmit, "dstLimit:", dstLimit, "s:", s)
+ }
+ for {
+ candidate := 0
+ for {
+ // Next src position to check
+ nextS := s + (s-nextEmit)>>6 + 4
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hash0 := hash6(cv, tableBits)
+ hash1 := hash6(cv>>8, tableBits)
+ candidate = int(table[hash0])
+ candidate2 := int(table[hash1])
+ table[hash0] = uint32(s)
+ table[hash1] = uint32(s + 1)
+ hash2 := hash6(cv>>16, tableBits)
+
+ // Check repeat at offset checkRep.
+ const checkRep = 1
+ if repeat > 0 && uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
+ base := s + checkRep
+ // Extend back
+ for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+ // Bail if we exceed the maximum size.
+ if d+(base-nextEmit) > dstLimit {
+ return 0
+ }
+
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+ if debug && nextEmit != base {
+ fmt.Println("emitted ", base-nextEmit, "literals")
+ }
+ // Extend forward
+ candidate := s - repeat + 4 + checkRep
+ s += 4 + checkRep
+ for s <= sLimit {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+ if debug {
+ // Validate match.
+ if s <= candidate {
+ panic("s <= candidate")
+ }
+ a := src[base:s]
+ b := src[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+ if nextEmit > 0 {
+ // same as `add := emitCopy(dst[d:], repeat, s-base)` but skips storing offset.
+ d += emitRepeat(dst[d:], repeat, s-base)
+ } else {
+ // First match, cannot be repeat.
+ d += emitCopy(dst[d:], repeat, s-base)
+ }
+ if debug {
+ fmt.Println("emitted src repeat length", s-base, "offset:", repeat, "s:", s)
+ }
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ cv = load64(src, s)
+ continue
+ }
+
+ if uint32(cv) == load32(src, candidate) {
+ break
+ }
+ candidate = int(table[hash2])
+ if uint32(cv>>8) == load32(src, candidate2) {
+ table[hash2] = uint32(s + 2)
+ candidate = candidate2
+ s++
+ break
+ }
+ table[hash2] = uint32(s + 2)
+ if uint32(cv>>16) == load32(src, candidate) {
+ s += 2
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards.
+ // The top bytes will be rechecked to get the full match.
+ for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
+ candidate--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ d += emitLiteral(dst[d:], src[nextEmit:s])
+ if debug && nextEmit != s {
+ fmt.Println("emitted ", s-nextEmit, "literals")
+ }
+ // Call emitCopy, and then see if another emitCopy could be our next
+ // move. Repeat until we find no match for the input immediately after
+ // what was consumed by the last emitCopy call.
+ //
+ // If we exit this loop normally then we need to call emitLiteral next,
+ // though we don't yet know how big the literal will be. We handle that
+ // by proceeding to the next iteration of the main loop. We also can
+ // exit this loop via goto if we get close to exhausting the input.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+ base := s
+ repeat = base - candidate
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidate += 4
+ for s <= len(src)-8 {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+
+ d += emitCopy(dst[d:], repeat, s-base)
+ if debug {
+ // Validate match.
+ if s <= candidate {
+ panic("s <= candidate")
+ }
+ a := src[base:s]
+ b := src[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+ if debug {
+ fmt.Println("emitted src copy, length", s-base, "offset:", repeat, "s:", s)
+ }
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+ // Check for an immediate match, otherwise start search at s+1
+ x := load64(src, s-2)
+ m2Hash := hash6(x, tableBits)
+ currHash := hash6(x>>16, tableBits)
+ candidate = int(table[currHash])
+ table[m2Hash] = uint32(s - 2)
+ table[currHash] = uint32(s)
+ if debug && s == candidate {
+ panic("s == candidate")
+ }
+ if uint32(x>>16) != load32(src, candidate) {
+ cv = load64(src, s+1)
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ if debug && nextEmit != s {
+ fmt.Println("emitted ", len(src)-nextEmit, "literals")
+ }
+ }
+ return d
+}
diff --git a/vendor/github.com/klauspost/compress/s2/encode_amd64.go b/vendor/github.com/klauspost/compress/s2/encode_amd64.go
new file mode 100644
index 00000000000..68d72a41d3a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/encode_amd64.go
@@ -0,0 +1,316 @@
+//go:build !appengine && !noasm && gc
+
+package s2
+
+import (
+ "sync"
+
+ "github.com/klauspost/compress/internal/race"
+)
+
+const hasAmd64Asm = true
+
+var encPools [4]sync.Pool
+
+// encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlock(dst, src []byte) (d int) {
+ race.ReadSlice(src)
+ race.WriteSlice(dst)
+
+ const (
+ // Use 12 bit table when less than...
+ limit12B = 16 << 10
+ // Use 10 bit table when less than...
+ limit10B = 4 << 10
+ // Use 8 bit table when less than...
+ limit8B = 512
+ )
+
+ if len(src) >= 4<<20 {
+ const sz, pool = 65536, 0
+ tmp, ok := encPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encPools[pool].Put(tmp)
+ return encodeBlockAsm(dst, src, tmp)
+ }
+ if len(src) >= limit12B {
+ const sz, pool = 65536, 0
+ tmp, ok := encPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encPools[pool].Put(tmp)
+ return encodeBlockAsm4MB(dst, src, tmp)
+ }
+ if len(src) >= limit10B {
+ const sz, pool = 16384, 1
+ tmp, ok := encPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encPools[pool].Put(tmp)
+ return encodeBlockAsm12B(dst, src, tmp)
+ }
+ if len(src) >= limit8B {
+ const sz, pool = 4096, 2
+ tmp, ok := encPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encPools[pool].Put(tmp)
+ return encodeBlockAsm10B(dst, src, tmp)
+ }
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+ const sz, pool = 1024, 3
+ tmp, ok := encPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encPools[pool].Put(tmp)
+ return encodeBlockAsm8B(dst, src, tmp)
+}
+
+var encBetterPools [5]sync.Pool
+
+// encodeBlockBetter encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlockBetter(dst, src []byte) (d int) {
+ race.ReadSlice(src)
+ race.WriteSlice(dst)
+
+ const (
+ // Use 12 bit table when less than...
+ limit12B = 16 << 10
+ // Use 10 bit table when less than...
+ limit10B = 4 << 10
+ // Use 8 bit table when less than...
+ limit8B = 512
+ )
+
+ if len(src) > 4<<20 {
+ const sz, pool = 589824, 0
+ tmp, ok := encBetterPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encBetterPools[pool].Put(tmp)
+ return encodeBetterBlockAsm(dst, src, tmp)
+ }
+ if len(src) >= limit12B {
+ const sz, pool = 589824, 0
+ tmp, ok := encBetterPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encBetterPools[pool].Put(tmp)
+
+ return encodeBetterBlockAsm4MB(dst, src, tmp)
+ }
+ if len(src) >= limit10B {
+ const sz, pool = 81920, 0
+ tmp, ok := encBetterPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encBetterPools[pool].Put(tmp)
+
+ return encodeBetterBlockAsm12B(dst, src, tmp)
+ }
+ if len(src) >= limit8B {
+ const sz, pool = 20480, 1
+ tmp, ok := encBetterPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encBetterPools[pool].Put(tmp)
+ return encodeBetterBlockAsm10B(dst, src, tmp)
+ }
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+
+ const sz, pool = 5120, 2
+ tmp, ok := encBetterPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encBetterPools[pool].Put(tmp)
+ return encodeBetterBlockAsm8B(dst, src, tmp)
+}
+
+// encodeBlockSnappy encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlockSnappy(dst, src []byte) (d int) {
+ race.ReadSlice(src)
+ race.WriteSlice(dst)
+
+ const (
+ // Use 12 bit table when less than...
+ limit12B = 16 << 10
+ // Use 10 bit table when less than...
+ limit10B = 4 << 10
+ // Use 8 bit table when less than...
+ limit8B = 512
+ )
+ if len(src) > 65536 {
+ const sz, pool = 65536, 0
+ tmp, ok := encPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encPools[pool].Put(tmp)
+ return encodeSnappyBlockAsm(dst, src, tmp)
+ }
+ if len(src) >= limit12B {
+ const sz, pool = 65536, 0
+ tmp, ok := encPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encPools[pool].Put(tmp)
+ return encodeSnappyBlockAsm64K(dst, src, tmp)
+ }
+ if len(src) >= limit10B {
+ const sz, pool = 16384, 1
+ tmp, ok := encPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encPools[pool].Put(tmp)
+ return encodeSnappyBlockAsm12B(dst, src, tmp)
+ }
+ if len(src) >= limit8B {
+ const sz, pool = 4096, 2
+ tmp, ok := encPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encPools[pool].Put(tmp)
+ return encodeSnappyBlockAsm10B(dst, src, tmp)
+ }
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+ const sz, pool = 1024, 3
+ tmp, ok := encPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encPools[pool].Put(tmp)
+ return encodeSnappyBlockAsm8B(dst, src, tmp)
+}
+
+// encodeBlockSnappy encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlockBetterSnappy(dst, src []byte) (d int) {
+ race.ReadSlice(src)
+ race.WriteSlice(dst)
+
+ const (
+ // Use 12 bit table when less than...
+ limit12B = 16 << 10
+ // Use 10 bit table when less than...
+ limit10B = 4 << 10
+ // Use 8 bit table when less than...
+ limit8B = 512
+ )
+ if len(src) > 65536 {
+ const sz, pool = 589824, 0
+ tmp, ok := encBetterPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encBetterPools[pool].Put(tmp)
+ return encodeSnappyBetterBlockAsm(dst, src, tmp)
+ }
+
+ if len(src) >= limit12B {
+ const sz, pool = 294912, 4
+ tmp, ok := encBetterPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encBetterPools[pool].Put(tmp)
+
+ return encodeSnappyBetterBlockAsm64K(dst, src, tmp)
+ }
+ if len(src) >= limit10B {
+ const sz, pool = 81920, 0
+ tmp, ok := encBetterPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encBetterPools[pool].Put(tmp)
+
+ return encodeSnappyBetterBlockAsm12B(dst, src, tmp)
+ }
+ if len(src) >= limit8B {
+ const sz, pool = 20480, 1
+ tmp, ok := encBetterPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encBetterPools[pool].Put(tmp)
+ return encodeSnappyBetterBlockAsm10B(dst, src, tmp)
+ }
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+
+ const sz, pool = 5120, 2
+ tmp, ok := encBetterPools[pool].Get().(*[sz]byte)
+ if !ok {
+ tmp = &[sz]byte{}
+ }
+ race.WriteSlice(tmp[:])
+ defer encBetterPools[pool].Put(tmp)
+ return encodeSnappyBetterBlockAsm8B(dst, src, tmp)
+}
diff --git a/vendor/github.com/klauspost/compress/s2/encode_best.go b/vendor/github.com/klauspost/compress/s2/encode_best.go
new file mode 100644
index 00000000000..49f2166ec1a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/encode_best.go
@@ -0,0 +1,797 @@
+// Copyright 2016 The Snappy-Go Authors. All rights reserved.
+// Copyright (c) 2019 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2
+
+import (
+ "fmt"
+ "math"
+ "math/bits"
+)
+
+// encodeBlockBest encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlockBest(dst, src []byte, dict *Dict) (d int) {
+ // Initialize the hash tables.
+ const (
+ // Long hash matches.
+ lTableBits = bestLongTableBits
+ maxLTableSize = bestLongTableSize
+
+ // Short hash matches.
+ sTableBits = bestShortTableBits
+ maxSTableSize = bestShortTableSize
+
+ inputMargin = 8 + 2
+
+ debug = false
+ )
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+ sLimitDict := min(len(src)-inputMargin, MaxDictSrcOffset-inputMargin)
+
+ tbl := getBestTables()
+ lTable := &tbl.lTable
+ sTable := &tbl.sTable
+ defer bestTablePool.Put(tbl)
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - 5
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ repeat := 1
+ if dict != nil {
+ dict.initBest()
+ s = 0
+ repeat = len(dict.dict) - dict.repeat
+ }
+ cv := load64(src, s)
+
+ // We search for a repeat at -1, but don't output repeats when nextEmit == 0
+ const lowbitMask = 0xffffffff
+ getCur := func(x uint64) int {
+ return int(x & lowbitMask)
+ }
+ getPrev := func(x uint64) int {
+ return int(x >> 32)
+ }
+ const maxSkip = 64
+
+ for {
+ type match struct {
+ offset int
+ s int
+ length int
+ score int
+ rep, dict bool
+ }
+ var best match
+ for {
+ // Next src position to check
+ nextS := (s-nextEmit)>>8 + 1
+ if nextS > maxSkip {
+ nextS = s + maxSkip
+ } else {
+ nextS += s
+ }
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ if dict != nil && s >= MaxDictSrcOffset {
+ dict = nil
+ if repeat > s {
+ repeat = math.MinInt32
+ }
+ }
+ hashL := hash8(cv, lTableBits)
+ hashS := hash4(cv, sTableBits)
+ candidateL := lTable[hashL]
+ candidateS := sTable[hashS]
+
+ score := func(m match) int {
+ // Matches that are longer forward are penalized since we must emit it as a literal.
+ score := m.length - m.s
+ if nextEmit == m.s {
+ // If we do not have to emit literals, we save 1 byte
+ score++
+ }
+ offset := m.s - m.offset
+ if m.rep {
+ return score - emitRepeatSize(offset, m.length)
+ }
+ return score - emitCopySize(offset, m.length)
+ }
+
+ matchAt := func(offset, s int, first uint32, rep bool) match {
+ if best.length != 0 && best.s-best.offset == s-offset {
+ // Don't retest if we have the same offset.
+ return match{offset: offset, s: s}
+ }
+ if load32(src, offset) != first {
+ return match{offset: offset, s: s}
+ }
+ m := match{offset: offset, s: s, length: 4 + offset, rep: rep}
+ s += 4
+ for s < len(src) {
+ if len(src)-s < 8 {
+ if src[s] == src[m.length] {
+ m.length++
+ s++
+ continue
+ }
+ break
+ }
+ if diff := load64(src, s) ^ load64(src, m.length); diff != 0 {
+ m.length += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ m.length += 8
+ }
+ m.length -= offset
+ m.score = score(m)
+ if m.score <= -m.s {
+ // Eliminate if no savings, we might find a better one.
+ m.length = 0
+ }
+ return m
+ }
+ matchDict := func(candidate, s int, first uint32, rep bool) match {
+ if s >= MaxDictSrcOffset {
+ return match{offset: candidate, s: s}
+ }
+ // Calculate offset as if in continuous array with s
+ offset := -len(dict.dict) + candidate
+ if best.length != 0 && best.s-best.offset == s-offset && !rep {
+ // Don't retest if we have the same offset.
+ return match{offset: offset, s: s}
+ }
+
+ if load32(dict.dict, candidate) != first {
+ return match{offset: offset, s: s}
+ }
+ m := match{offset: offset, s: s, length: 4 + candidate, rep: rep, dict: true}
+ s += 4
+ if !rep {
+ for s < sLimitDict && m.length < len(dict.dict) {
+ if len(src)-s < 8 || len(dict.dict)-m.length < 8 {
+ if src[s] == dict.dict[m.length] {
+ m.length++
+ s++
+ continue
+ }
+ break
+ }
+ if diff := load64(src, s) ^ load64(dict.dict, m.length); diff != 0 {
+ m.length += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ m.length += 8
+ }
+ } else {
+ for s < len(src) && m.length < len(dict.dict) {
+ if len(src)-s < 8 || len(dict.dict)-m.length < 8 {
+ if src[s] == dict.dict[m.length] {
+ m.length++
+ s++
+ continue
+ }
+ break
+ }
+ if diff := load64(src, s) ^ load64(dict.dict, m.length); diff != 0 {
+ m.length += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ m.length += 8
+ }
+ }
+ m.length -= candidate
+ m.score = score(m)
+ if m.score <= -m.s {
+ // Eliminate if no savings, we might find a better one.
+ m.length = 0
+ }
+ return m
+ }
+
+ bestOf := func(a, b match) match {
+ if b.length == 0 {
+ return a
+ }
+ if a.length == 0 {
+ return b
+ }
+ as := a.score + b.s
+ bs := b.score + a.s
+ if as >= bs {
+ return a
+ }
+ return b
+ }
+
+ if s > 0 {
+ best = bestOf(matchAt(getCur(candidateL), s, uint32(cv), false), matchAt(getPrev(candidateL), s, uint32(cv), false))
+ best = bestOf(best, matchAt(getCur(candidateS), s, uint32(cv), false))
+ best = bestOf(best, matchAt(getPrev(candidateS), s, uint32(cv), false))
+ }
+ if dict != nil {
+ candidateL := dict.bestTableLong[hashL]
+ candidateS := dict.bestTableShort[hashS]
+ best = bestOf(best, matchDict(int(candidateL&0xffff), s, uint32(cv), false))
+ best = bestOf(best, matchDict(int(candidateL>>16), s, uint32(cv), false))
+ best = bestOf(best, matchDict(int(candidateS&0xffff), s, uint32(cv), false))
+ best = bestOf(best, matchDict(int(candidateS>>16), s, uint32(cv), false))
+ }
+ {
+ if (dict == nil || repeat <= s) && repeat > 0 {
+ best = bestOf(best, matchAt(s-repeat+1, s+1, uint32(cv>>8), true))
+ } else if s-repeat < -4 && dict != nil {
+ candidate := len(dict.dict) - (repeat - s)
+ best = bestOf(best, matchDict(candidate, s, uint32(cv), true))
+ candidate++
+ best = bestOf(best, matchDict(candidate, s+1, uint32(cv>>8), true))
+ }
+
+ if best.length > 0 {
+ hashS := hash4(cv>>8, sTableBits)
+ // s+1
+ nextShort := sTable[hashS]
+ s := s + 1
+ cv := load64(src, s)
+ hashL := hash8(cv, lTableBits)
+ nextLong := lTable[hashL]
+ best = bestOf(best, matchAt(getCur(nextShort), s, uint32(cv), false))
+ best = bestOf(best, matchAt(getPrev(nextShort), s, uint32(cv), false))
+ best = bestOf(best, matchAt(getCur(nextLong), s, uint32(cv), false))
+ best = bestOf(best, matchAt(getPrev(nextLong), s, uint32(cv), false))
+
+ // Dict at + 1
+ if dict != nil {
+ candidateL := dict.bestTableLong[hashL]
+ candidateS := dict.bestTableShort[hashS]
+
+ best = bestOf(best, matchDict(int(candidateL&0xffff), s, uint32(cv), false))
+ best = bestOf(best, matchDict(int(candidateS&0xffff), s, uint32(cv), false))
+ }
+
+ // s+2
+ if true {
+ hashS := hash4(cv>>8, sTableBits)
+
+ nextShort = sTable[hashS]
+ s++
+ cv = load64(src, s)
+ hashL := hash8(cv, lTableBits)
+ nextLong = lTable[hashL]
+
+ if (dict == nil || repeat <= s) && repeat > 0 {
+ // Repeat at + 2
+ best = bestOf(best, matchAt(s-repeat, s, uint32(cv), true))
+ } else if repeat-s > 4 && dict != nil {
+ candidate := len(dict.dict) - (repeat - s)
+ best = bestOf(best, matchDict(candidate, s, uint32(cv), true))
+ }
+ best = bestOf(best, matchAt(getCur(nextShort), s, uint32(cv), false))
+ best = bestOf(best, matchAt(getPrev(nextShort), s, uint32(cv), false))
+ best = bestOf(best, matchAt(getCur(nextLong), s, uint32(cv), false))
+ best = bestOf(best, matchAt(getPrev(nextLong), s, uint32(cv), false))
+
+ // Dict at +2
+ // Very small gain
+ if dict != nil {
+ candidateL := dict.bestTableLong[hashL]
+ candidateS := dict.bestTableShort[hashS]
+
+ best = bestOf(best, matchDict(int(candidateL&0xffff), s, uint32(cv), false))
+ best = bestOf(best, matchDict(int(candidateS&0xffff), s, uint32(cv), false))
+ }
+ }
+ // Search for a match at best match end, see if that is better.
+ // Allow some bytes at the beginning to mismatch.
+ // Sweet spot is around 1-2 bytes, but depends on input.
+ // The skipped bytes are tested in Extend backwards,
+ // and still picked up as part of the match if they do.
+ const skipBeginning = 2
+ const skipEnd = 1
+ if sAt := best.s + best.length - skipEnd; sAt < sLimit {
+
+ sBack := best.s + skipBeginning - skipEnd
+ backL := best.length - skipBeginning
+ // Load initial values
+ cv = load64(src, sBack)
+
+ // Grab candidates...
+ next := lTable[hash8(load64(src, sAt), lTableBits)]
+
+ if checkAt := getCur(next) - backL; checkAt > 0 {
+ best = bestOf(best, matchAt(checkAt, sBack, uint32(cv), false))
+ }
+ if checkAt := getPrev(next) - backL; checkAt > 0 {
+ best = bestOf(best, matchAt(checkAt, sBack, uint32(cv), false))
+ }
+ // Disabled: Extremely small gain
+ if false {
+ next = sTable[hash4(load64(src, sAt), sTableBits)]
+ if checkAt := getCur(next) - backL; checkAt > 0 {
+ best = bestOf(best, matchAt(checkAt, sBack, uint32(cv), false))
+ }
+ if checkAt := getPrev(next) - backL; checkAt > 0 {
+ best = bestOf(best, matchAt(checkAt, sBack, uint32(cv), false))
+ }
+ }
+ }
+ }
+ }
+
+ // Update table
+ lTable[hashL] = uint64(s) | candidateL<<32
+ sTable[hashS] = uint64(s) | candidateS<<32
+
+ if best.length > 0 {
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards, not needed for repeats...
+ s = best.s
+ if !best.rep && !best.dict {
+ for best.offset > 0 && s > nextEmit && src[best.offset-1] == src[s-1] {
+ best.offset--
+ best.length++
+ s--
+ }
+ }
+ if false && best.offset >= s {
+ panic(fmt.Errorf("t %d >= s %d", best.offset, s))
+ }
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ base := s
+ offset := s - best.offset
+ s += best.length
+
+ if offset > 65535 && s-base <= 5 && !best.rep {
+ // Bail if the match is equal or worse to the encoding.
+ s = best.s + 1
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ cv = load64(src, s)
+ continue
+ }
+ if debug && nextEmit != base {
+ fmt.Println("EMIT", base-nextEmit, "literals. base-after:", base)
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+ if best.rep {
+ if nextEmit > 0 || best.dict {
+ if debug {
+ fmt.Println("REPEAT, length", best.length, "offset:", offset, "s-after:", s, "dict:", best.dict, "best:", best)
+ }
+ // same as `add := emitCopy(dst[d:], repeat, s-base)` but skips storing offset.
+ d += emitRepeat(dst[d:], offset, best.length)
+ } else {
+ // First match without dict cannot be a repeat.
+ if debug {
+ fmt.Println("COPY, length", best.length, "offset:", offset, "s-after:", s, "dict:", best.dict, "best:", best)
+ }
+ d += emitCopy(dst[d:], offset, best.length)
+ }
+ } else {
+ if debug {
+ fmt.Println("COPY, length", best.length, "offset:", offset, "s-after:", s, "dict:", best.dict, "best:", best)
+ }
+ d += emitCopy(dst[d:], offset, best.length)
+ }
+ repeat = offset
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+ // Fill tables...
+ for i := best.s + 1; i < s; i++ {
+ cv0 := load64(src, i)
+ long0 := hash8(cv0, lTableBits)
+ short0 := hash4(cv0, sTableBits)
+ lTable[long0] = uint64(i) | lTable[long0]<<32
+ sTable[short0] = uint64(i) | sTable[short0]<<32
+ }
+ cv = load64(src, s)
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ if debug && nextEmit != s {
+ fmt.Println("emitted ", len(src)-nextEmit, "literals")
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
+
+// encodeBlockBestSnappy encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlockBestSnappy(dst, src []byte) (d int) {
+ // Initialize the hash tables.
+ const (
+ // Long hash matches.
+ lTableBits = bestLongTableBits
+ maxLTableSize = bestLongTableSize
+
+ // Short hash matches.
+ sTableBits = bestShortTableBits
+ maxSTableSize = bestShortTableSize
+
+ inputMargin = 8 + 2
+ )
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+
+ tbl := getBestTables()
+ lTable := &tbl.lTable
+ sTable := &tbl.sTable
+ defer bestTablePool.Put(tbl)
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - 5
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ cv := load64(src, s)
+
+ // We search for a repeat at -1, but don't output repeats when nextEmit == 0
+ repeat := 1
+ const lowbitMask = 0xffffffff
+ getCur := func(x uint64) int {
+ return int(x & lowbitMask)
+ }
+ getPrev := func(x uint64) int {
+ return int(x >> 32)
+ }
+ const maxSkip = 64
+
+ for {
+ type match struct {
+ offset int
+ s int
+ length int
+ score int
+ }
+ var best match
+ for {
+ // Next src position to check
+ nextS := (s-nextEmit)>>8 + 1
+ if nextS > maxSkip {
+ nextS = s + maxSkip
+ } else {
+ nextS += s
+ }
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hashL := hash8(cv, lTableBits)
+ hashS := hash4(cv, sTableBits)
+ candidateL := lTable[hashL]
+ candidateS := sTable[hashS]
+
+ score := func(m match) int {
+ // Matches that are longer forward are penalized since we must emit it as a literal.
+ score := m.length - m.s
+ if nextEmit == m.s {
+ // If we do not have to emit literals, we save 1 byte
+ score++
+ }
+ offset := m.s - m.offset
+
+ return score - emitCopyNoRepeatSize(offset, m.length)
+ }
+
+ matchAt := func(offset, s int, first uint32) match {
+ if best.length != 0 && best.s-best.offset == s-offset {
+ // Don't retest if we have the same offset.
+ return match{offset: offset, s: s}
+ }
+ if load32(src, offset) != first {
+ return match{offset: offset, s: s}
+ }
+ m := match{offset: offset, s: s, length: 4 + offset}
+ s += 4
+ for s <= sLimit {
+ if diff := load64(src, s) ^ load64(src, m.length); diff != 0 {
+ m.length += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ m.length += 8
+ }
+ m.length -= offset
+ m.score = score(m)
+ if m.score <= -m.s {
+ // Eliminate if no savings, we might find a better one.
+ m.length = 0
+ }
+ return m
+ }
+
+ bestOf := func(a, b match) match {
+ if b.length == 0 {
+ return a
+ }
+ if a.length == 0 {
+ return b
+ }
+ as := a.score + b.s
+ bs := b.score + a.s
+ if as >= bs {
+ return a
+ }
+ return b
+ }
+
+ best = bestOf(matchAt(getCur(candidateL), s, uint32(cv)), matchAt(getPrev(candidateL), s, uint32(cv)))
+ best = bestOf(best, matchAt(getCur(candidateS), s, uint32(cv)))
+ best = bestOf(best, matchAt(getPrev(candidateS), s, uint32(cv)))
+
+ {
+ best = bestOf(best, matchAt(s-repeat+1, s+1, uint32(cv>>8)))
+ if best.length > 0 {
+ // s+1
+ nextShort := sTable[hash4(cv>>8, sTableBits)]
+ s := s + 1
+ cv := load64(src, s)
+ nextLong := lTable[hash8(cv, lTableBits)]
+ best = bestOf(best, matchAt(getCur(nextShort), s, uint32(cv)))
+ best = bestOf(best, matchAt(getPrev(nextShort), s, uint32(cv)))
+ best = bestOf(best, matchAt(getCur(nextLong), s, uint32(cv)))
+ best = bestOf(best, matchAt(getPrev(nextLong), s, uint32(cv)))
+ // Repeat at + 2
+ best = bestOf(best, matchAt(s-repeat+1, s+1, uint32(cv>>8)))
+
+ // s+2
+ if true {
+ nextShort = sTable[hash4(cv>>8, sTableBits)]
+ s++
+ cv = load64(src, s)
+ nextLong = lTable[hash8(cv, lTableBits)]
+ best = bestOf(best, matchAt(getCur(nextShort), s, uint32(cv)))
+ best = bestOf(best, matchAt(getPrev(nextShort), s, uint32(cv)))
+ best = bestOf(best, matchAt(getCur(nextLong), s, uint32(cv)))
+ best = bestOf(best, matchAt(getPrev(nextLong), s, uint32(cv)))
+ }
+ // Search for a match at best match end, see if that is better.
+ if sAt := best.s + best.length; sAt < sLimit {
+ sBack := best.s
+ backL := best.length
+ // Load initial values
+ cv = load64(src, sBack)
+ // Search for mismatch
+ next := lTable[hash8(load64(src, sAt), lTableBits)]
+ //next := sTable[hash4(load64(src, sAt), sTableBits)]
+
+ if checkAt := getCur(next) - backL; checkAt > 0 {
+ best = bestOf(best, matchAt(checkAt, sBack, uint32(cv)))
+ }
+ if checkAt := getPrev(next) - backL; checkAt > 0 {
+ best = bestOf(best, matchAt(checkAt, sBack, uint32(cv)))
+ }
+ }
+ }
+ }
+
+ // Update table
+ lTable[hashL] = uint64(s) | candidateL<<32
+ sTable[hashS] = uint64(s) | candidateS<<32
+
+ if best.length > 0 {
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards, not needed for repeats...
+ s = best.s
+ if true {
+ for best.offset > 0 && s > nextEmit && src[best.offset-1] == src[s-1] {
+ best.offset--
+ best.length++
+ s--
+ }
+ }
+ if false && best.offset >= s {
+ panic(fmt.Errorf("t %d >= s %d", best.offset, s))
+ }
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ base := s
+ offset := s - best.offset
+
+ s += best.length
+
+ if offset > 65535 && s-base <= 5 {
+ // Bail if the match is equal or worse to the encoding.
+ s = best.s + 1
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ cv = load64(src, s)
+ continue
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+ d += emitCopyNoRepeat(dst[d:], offset, best.length)
+ repeat = offset
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+ // Fill tables...
+ for i := best.s + 1; i < s; i++ {
+ cv0 := load64(src, i)
+ long0 := hash8(cv0, lTableBits)
+ short0 := hash4(cv0, sTableBits)
+ lTable[long0] = uint64(i) | lTable[long0]<<32
+ sTable[short0] = uint64(i) | sTable[short0]<<32
+ }
+ cv = load64(src, s)
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
+
+// emitCopySize returns the size to encode the offset+length
+//
+// It assumes that:
+//
+// 1 <= offset && offset <= math.MaxUint32
+// 4 <= length && length <= 1 << 24
+func emitCopySize(offset, length int) int {
+ if offset >= 65536 {
+ i := 0
+ if length > 64 {
+ length -= 64
+ if length >= 4 {
+ // Emit remaining as repeats
+ return 5 + emitRepeatSize(offset, length)
+ }
+ i = 5
+ }
+ if length == 0 {
+ return i
+ }
+ return i + 5
+ }
+
+ // Offset no more than 2 bytes.
+ if length > 64 {
+ if offset < 2048 {
+ // Emit 8 bytes, then rest as repeats...
+ return 2 + emitRepeatSize(offset, length-8)
+ }
+ // Emit remaining as repeats, at least 4 bytes remain.
+ return 3 + emitRepeatSize(offset, length-60)
+ }
+ if length >= 12 || offset >= 2048 {
+ return 3
+ }
+ // Emit the remaining copy, encoded as 2 bytes.
+ return 2
+}
+
+// emitCopyNoRepeatSize returns the size to encode the offset+length
+//
+// It assumes that:
+//
+// 1 <= offset && offset <= math.MaxUint32
+// 4 <= length && length <= 1 << 24
+func emitCopyNoRepeatSize(offset, length int) int {
+ if offset >= 65536 {
+ return 5 + 5*(length/64)
+ }
+
+ // Offset no more than 2 bytes.
+ if length > 64 {
+ // Emit remaining as repeats, at least 4 bytes remain.
+ return 3 + 3*(length/60)
+ }
+ if length >= 12 || offset >= 2048 {
+ return 3
+ }
+ // Emit the remaining copy, encoded as 2 bytes.
+ return 2
+}
+
+// emitRepeatSize returns the number of bytes required to encode a repeat.
+// Length must be at least 4 and < 1<<24
+func emitRepeatSize(offset, length int) int {
+ // Repeat offset, make length cheaper
+ if length <= 4+4 || (length < 8+4 && offset < 2048) {
+ return 2
+ }
+ if length < (1<<8)+4+4 {
+ return 3
+ }
+ if length < (1<<16)+(1<<8)+4 {
+ return 4
+ }
+ const maxRepeat = (1 << 24) - 1
+ length -= (1 << 16) - 4
+ left := 0
+ if length > maxRepeat {
+ left = length - maxRepeat + 4
+ }
+ if left > 0 {
+ return 5 + emitRepeatSize(offset, left)
+ }
+ return 5
+}
diff --git a/vendor/github.com/klauspost/compress/s2/encode_better.go b/vendor/github.com/klauspost/compress/s2/encode_better.go
new file mode 100644
index 00000000000..adbc57c4d27
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/encode_better.go
@@ -0,0 +1,1513 @@
+// Copyright 2016 The Snappy-Go Authors. All rights reserved.
+// Copyright (c) 2019 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2
+
+import (
+ "bytes"
+ "fmt"
+ "math/bits"
+)
+
+// hash4 returns the hash of the lowest 4 bytes of u to fit in a hash table with h bits.
+// Preferably h should be a constant and should always be <32.
+func hash4(u uint64, h uint8) uint32 {
+ const prime4bytes = 2654435761
+ return (uint32(u) * prime4bytes) >> ((32 - h) & 31)
+}
+
+// hash5 returns the hash of the lowest 5 bytes of u to fit in a hash table with h bits.
+// Preferably h should be a constant and should always be <64.
+func hash5(u uint64, h uint8) uint32 {
+ const prime5bytes = 889523592379
+ return uint32(((u << (64 - 40)) * prime5bytes) >> ((64 - h) & 63))
+}
+
+// hash7 returns the hash of the lowest 7 bytes of u to fit in a hash table with h bits.
+// Preferably h should be a constant and should always be <64.
+func hash7(u uint64, h uint8) uint32 {
+ const prime7bytes = 58295818150454627
+ return uint32(((u << (64 - 56)) * prime7bytes) >> ((64 - h) & 63))
+}
+
+// hash8 returns the hash of u to fit in a hash table with h bits.
+// Preferably h should be a constant and should always be <64.
+func hash8(u uint64, h uint8) uint32 {
+ const prime8bytes = 0xcf1bbcdcb7a56463
+ return uint32((u * prime8bytes) >> ((64 - h) & 63))
+}
+
+// encodeBlockBetter encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlockBetterGo(dst, src []byte) (d int) {
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+
+ // Initialize the hash tables.
+ const (
+ // Long hash matches.
+ lTableBits = betterLongTableBits
+ maxLTableSize = betterLongTableSize
+
+ // Short hash matches.
+ sTableBits = betterShortTableBits
+ maxSTableSize = betterShortTableSize
+ )
+
+ tbl := getBetterTables()
+ lTable := &tbl.lTable
+ sTable := &tbl.sTable
+ defer betterTablePool.Put(tbl)
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - len(src)>>5 - 6
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ cv := load64(src, s)
+
+ // We initialize repeat to 0, so we never match on first attempt
+ repeat := 0
+
+ for {
+ candidateL := 0
+ nextS := 0
+ for {
+ // Next src position to check
+ nextS = s + (s-nextEmit)>>7 + 1
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hashL := hash7(cv, lTableBits)
+ hashS := hash4(cv, sTableBits)
+ candidateL = int(lTable[hashL])
+ candidateS := int(sTable[hashS])
+ lTable[hashL] = uint32(s)
+ sTable[hashS] = uint32(s)
+
+ valLong := load64(src, candidateL)
+ valShort := load64(src, candidateS)
+
+ // If long matches at least 8 bytes, use that.
+ if cv == valLong {
+ break
+ }
+ if cv == valShort {
+ candidateL = candidateS
+ break
+ }
+
+ // Check repeat at offset checkRep.
+ const checkRep = 1
+ // Minimum length of a repeat. Tested with various values.
+ // While 4-5 offers improvements in some, 6 reduces
+ // regressions significantly.
+ const wantRepeatBytes = 6
+ const repeatMask = ((1 << (wantRepeatBytes * 8)) - 1) << (8 * checkRep)
+ if false && repeat > 0 && cv&repeatMask == load64(src, s-repeat)&repeatMask {
+ base := s + checkRep
+ // Extend back
+ for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+
+ // Extend forward
+ candidate := s - repeat + wantRepeatBytes + checkRep
+ s += wantRepeatBytes + checkRep
+ for s < len(src) {
+ if len(src)-s < 8 {
+ if src[s] == src[candidate] {
+ s++
+ candidate++
+ continue
+ }
+ break
+ }
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+ // same as `add := emitCopy(dst[d:], repeat, s-base)` but skips storing offset.
+ d += emitRepeat(dst[d:], repeat, s-base)
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ // Index in-between
+ index0 := base + 1
+ index1 := s - 2
+
+ for index0 < index1 {
+ cv0 := load64(src, index0)
+ cv1 := load64(src, index1)
+ lTable[hash7(cv0, lTableBits)] = uint32(index0)
+ sTable[hash4(cv0>>8, sTableBits)] = uint32(index0 + 1)
+
+ lTable[hash7(cv1, lTableBits)] = uint32(index1)
+ sTable[hash4(cv1>>8, sTableBits)] = uint32(index1 + 1)
+ index0 += 2
+ index1 -= 2
+ }
+
+ cv = load64(src, s)
+ continue
+ }
+
+ // Long likely matches 7, so take that.
+ if uint32(cv) == uint32(valLong) {
+ break
+ }
+
+ // Check our short candidate
+ if uint32(cv) == uint32(valShort) {
+ // Try a long candidate at s+1
+ hashL = hash7(cv>>8, lTableBits)
+ candidateL = int(lTable[hashL])
+ lTable[hashL] = uint32(s + 1)
+ if uint32(cv>>8) == load32(src, candidateL) {
+ s++
+ break
+ }
+ // Use our short candidate.
+ candidateL = candidateS
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards
+ for candidateL > 0 && s > nextEmit && src[candidateL-1] == src[s-1] {
+ candidateL--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ base := s
+ offset := base - candidateL
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidateL += 4
+ for s < len(src) {
+ if len(src)-s < 8 {
+ if src[s] == src[candidateL] {
+ s++
+ candidateL++
+ continue
+ }
+ break
+ }
+ if diff := load64(src, s) ^ load64(src, candidateL); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidateL += 8
+ }
+
+ if offset > 65535 && s-base <= 5 && repeat != offset {
+ // Bail if the match is equal or worse to the encoding.
+ s = nextS + 1
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ cv = load64(src, s)
+ continue
+ }
+
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+ if repeat == offset {
+ d += emitRepeat(dst[d:], offset, s-base)
+ } else {
+ d += emitCopy(dst[d:], offset, s-base)
+ repeat = offset
+ }
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+
+ // Index short & long
+ index0 := base + 1
+ index1 := s - 2
+
+ cv0 := load64(src, index0)
+ cv1 := load64(src, index1)
+ lTable[hash7(cv0, lTableBits)] = uint32(index0)
+ sTable[hash4(cv0>>8, sTableBits)] = uint32(index0 + 1)
+
+ // lTable could be postponed, but very minor difference.
+ lTable[hash7(cv1, lTableBits)] = uint32(index1)
+ sTable[hash4(cv1>>8, sTableBits)] = uint32(index1 + 1)
+ index0 += 1
+ index1 -= 1
+ cv = load64(src, s)
+
+ // Index large values sparsely in between.
+ // We do two starting from different offsets for speed.
+ index2 := (index0 + index1 + 1) >> 1
+ for index2 < index1 {
+ lTable[hash7(load64(src, index0), lTableBits)] = uint32(index0)
+ lTable[hash7(load64(src, index2), lTableBits)] = uint32(index2)
+ index0 += 2
+ index2 += 2
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
+
+// encodeBlockBetterSnappyGo encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlockBetterSnappyGo(dst, src []byte) (d int) {
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+
+ // Initialize the hash tables.
+ const (
+ // Long hash matches.
+ lTableBits = betterSnappyLongTableBits
+ maxLTableSize = betterSnappyLongTableSize
+
+ // Short hash matches.
+ sTableBits = betterShortTableBits
+ maxSTableSize = betterShortTableSize
+ )
+
+ tbl := getBetterSnappyTables()
+ lTable := &tbl.lTable
+ sTable := &tbl.sTable
+ defer betterSnappyTablePool.Put(tbl)
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - len(src)>>5 - 6
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ cv := load64(src, s)
+
+ // We initialize repeat to 0, so we never match on first attempt
+ repeat := 0
+ const maxSkip = 100
+
+ for {
+ candidateL := 0
+ nextS := 0
+ for {
+ // Next src position to check
+ nextS = min(s+(s-nextEmit)>>7+1, s+maxSkip)
+
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hashL := hash7(cv, lTableBits)
+ hashS := hash4(cv, sTableBits)
+ candidateL = int(lTable[hashL])
+ candidateS := int(sTable[hashS])
+ lTable[hashL] = uint32(s)
+ sTable[hashS] = uint32(s)
+
+ if uint32(cv) == load32(src, candidateL) {
+ break
+ }
+
+ // Check our short candidate
+ if uint32(cv) == load32(src, candidateS) {
+ // Try a long candidate at s+1
+ hashL = hash7(cv>>8, lTableBits)
+ candidateL = int(lTable[hashL])
+ lTable[hashL] = uint32(s + 1)
+ if uint32(cv>>8) == load32(src, candidateL) {
+ s++
+ break
+ }
+ // Use our short candidate.
+ candidateL = candidateS
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards
+ for candidateL > 0 && s > nextEmit && src[candidateL-1] == src[s-1] {
+ candidateL--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ base := s
+ offset := base - candidateL
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidateL += 4
+ for s < len(src) {
+ if len(src)-s < 8 {
+ if src[s] == src[candidateL] {
+ s++
+ candidateL++
+ continue
+ }
+ break
+ }
+ if diff := load64(src, s) ^ load64(src, candidateL); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidateL += 8
+ }
+
+ if offset > 65535 && s-base <= 5 && repeat != offset {
+ // Bail if the match is equal or worse to the encoding.
+ s = nextS + 1
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ cv = load64(src, s)
+ continue
+ }
+
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+ d += emitCopyNoRepeat(dst[d:], offset, s-base)
+ repeat = offset
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+
+ // Index short & long
+ index0 := base + 1
+ index1 := s - 2
+
+ cv0 := load64(src, index0)
+ cv1 := load64(src, index1)
+ lTable[hash7(cv0, lTableBits)] = uint32(index0)
+ sTable[hash4(cv0>>8, sTableBits)] = uint32(index0 + 1)
+
+ lTable[hash7(cv1, lTableBits)] = uint32(index1)
+ sTable[hash4(cv1>>8, sTableBits)] = uint32(index1 + 1)
+ index0 += 1
+ index1 -= 1
+ cv = load64(src, s)
+
+ // Index large values sparsely in between.
+ // We do two starting from different offsets for speed.
+ index2 := (index0 + index1 + 1) >> 1
+ for index2 < index1 {
+ lTable[hash7(load64(src, index0), lTableBits)] = uint32(index0)
+ lTable[hash7(load64(src, index2), lTableBits)] = uint32(index2)
+ index0 += 2
+ index2 += 2
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
+
+func encodeBlockBetterGo64K(dst, src []byte) (d int) {
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+ // Initialize the hash tables.
+ // Use smaller tables for smaller blocks
+ const (
+ // Long hash matches.
+ lTableBits = 16
+ maxLTableSize = 1 << lTableBits
+
+ // Short hash matches.
+ sTableBits = 13
+ maxSTableSize = 1 << sTableBits
+ )
+
+ var lTable [maxLTableSize]uint16
+ var sTable [maxSTableSize]uint16
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - len(src)>>5 - 6
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ cv := load64(src, s)
+
+ // We initialize repeat to 0, so we never match on first attempt
+ repeat := 0
+
+ for {
+ candidateL := 0
+ nextS := 0
+ for {
+ // Next src position to check
+ nextS = s + (s-nextEmit)>>6 + 1
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hashL := hash7(cv, lTableBits)
+ hashS := hash4(cv, sTableBits)
+ candidateL = int(lTable[hashL])
+ candidateS := int(sTable[hashS])
+ lTable[hashL] = uint16(s)
+ sTable[hashS] = uint16(s)
+
+ valLong := load64(src, candidateL)
+ valShort := load64(src, candidateS)
+
+ // If long matches at least 8 bytes, use that.
+ if cv == valLong {
+ break
+ }
+ if cv == valShort {
+ candidateL = candidateS
+ break
+ }
+
+ // Check repeat at offset checkRep.
+ const checkRep = 1
+ // Minimum length of a repeat. Tested with various values.
+ // While 4-5 offers improvements in some, 6 reduces
+ // regressions significantly.
+ const wantRepeatBytes = 6
+ const repeatMask = ((1 << (wantRepeatBytes * 8)) - 1) << (8 * checkRep)
+ if false && repeat > 0 && cv&repeatMask == load64(src, s-repeat)&repeatMask {
+ base := s + checkRep
+ // Extend back
+ for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+
+ // Extend forward
+ candidate := s - repeat + wantRepeatBytes + checkRep
+ s += wantRepeatBytes + checkRep
+ for s < len(src) {
+ if len(src)-s < 8 {
+ if src[s] == src[candidate] {
+ s++
+ candidate++
+ continue
+ }
+ break
+ }
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+ // same as `add := emitCopy(dst[d:], repeat, s-base)` but skips storing offset.
+ d += emitRepeat(dst[d:], repeat, s-base)
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ // Index in-between
+ index0 := base + 1
+ index1 := s - 2
+
+ for index0 < index1 {
+ cv0 := load64(src, index0)
+ cv1 := load64(src, index1)
+ lTable[hash7(cv0, lTableBits)] = uint16(index0)
+ sTable[hash4(cv0>>8, sTableBits)] = uint16(index0 + 1)
+
+ lTable[hash7(cv1, lTableBits)] = uint16(index1)
+ sTable[hash4(cv1>>8, sTableBits)] = uint16(index1 + 1)
+ index0 += 2
+ index1 -= 2
+ }
+
+ cv = load64(src, s)
+ continue
+ }
+
+ // Long likely matches 7, so take that.
+ if uint32(cv) == uint32(valLong) {
+ break
+ }
+
+ // Check our short candidate
+ if uint32(cv) == uint32(valShort) {
+ // Try a long candidate at s+1
+ hashL = hash7(cv>>8, lTableBits)
+ candidateL = int(lTable[hashL])
+ lTable[hashL] = uint16(s + 1)
+ if uint32(cv>>8) == load32(src, candidateL) {
+ s++
+ break
+ }
+ // Use our short candidate.
+ candidateL = candidateS
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards
+ for candidateL > 0 && s > nextEmit && src[candidateL-1] == src[s-1] {
+ candidateL--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ base := s
+ offset := base - candidateL
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidateL += 4
+ for s < len(src) {
+ if len(src)-s < 8 {
+ if src[s] == src[candidateL] {
+ s++
+ candidateL++
+ continue
+ }
+ break
+ }
+ if diff := load64(src, s) ^ load64(src, candidateL); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidateL += 8
+ }
+
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+ if repeat == offset {
+ d += emitRepeat(dst[d:], offset, s-base)
+ } else {
+ d += emitCopy(dst[d:], offset, s-base)
+ repeat = offset
+ }
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+
+ // Index short & long
+ index0 := base + 1
+ index1 := s - 2
+
+ cv0 := load64(src, index0)
+ cv1 := load64(src, index1)
+ lTable[hash7(cv0, lTableBits)] = uint16(index0)
+ sTable[hash4(cv0>>8, sTableBits)] = uint16(index0 + 1)
+
+ // lTable could be postponed, but very minor difference.
+ lTable[hash7(cv1, lTableBits)] = uint16(index1)
+ sTable[hash4(cv1>>8, sTableBits)] = uint16(index1 + 1)
+ index0 += 1
+ index1 -= 1
+ cv = load64(src, s)
+
+ // Index large values sparsely in between.
+ // We do two starting from different offsets for speed.
+ index2 := (index0 + index1 + 1) >> 1
+ for index2 < index1 {
+ lTable[hash7(load64(src, index0), lTableBits)] = uint16(index0)
+ lTable[hash7(load64(src, index2), lTableBits)] = uint16(index2)
+ index0 += 2
+ index2 += 2
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
+
+// encodeBlockBetterSnappyGo encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlockBetterSnappyGo64K(dst, src []byte) (d int) {
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+
+ // Initialize the hash tables.
+ // Use smaller tables for smaller blocks
+ const (
+ // Long hash matches.
+ lTableBits = 15
+ maxLTableSize = 1 << lTableBits
+
+ // Short hash matches.
+ sTableBits = 13
+ maxSTableSize = 1 << sTableBits
+ )
+
+ var lTable [maxLTableSize]uint16
+ var sTable [maxSTableSize]uint16
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - len(src)>>5 - 6
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ cv := load64(src, s)
+
+ const maxSkip = 100
+
+ for {
+ candidateL := 0
+ nextS := 0
+ for {
+ // Next src position to check
+ nextS = min(s+(s-nextEmit)>>6+1, s+maxSkip)
+
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hashL := hash7(cv, lTableBits)
+ hashS := hash4(cv, sTableBits)
+ candidateL = int(lTable[hashL])
+ candidateS := int(sTable[hashS])
+ lTable[hashL] = uint16(s)
+ sTable[hashS] = uint16(s)
+
+ if uint32(cv) == load32(src, candidateL) {
+ break
+ }
+
+ // Check our short candidate
+ if uint32(cv) == load32(src, candidateS) {
+ // Try a long candidate at s+1
+ hashL = hash7(cv>>8, lTableBits)
+ candidateL = int(lTable[hashL])
+ lTable[hashL] = uint16(s + 1)
+ if uint32(cv>>8) == load32(src, candidateL) {
+ s++
+ break
+ }
+ // Use our short candidate.
+ candidateL = candidateS
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards
+ for candidateL > 0 && s > nextEmit && src[candidateL-1] == src[s-1] {
+ candidateL--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ base := s
+ offset := base - candidateL
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidateL += 4
+ for s < len(src) {
+ if len(src)-s < 8 {
+ if src[s] == src[candidateL] {
+ s++
+ candidateL++
+ continue
+ }
+ break
+ }
+ if diff := load64(src, s) ^ load64(src, candidateL); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidateL += 8
+ }
+
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+ d += emitCopyNoRepeat(dst[d:], offset, s-base)
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+
+ // Index short & long
+ index0 := base + 1
+ index1 := s - 2
+
+ cv0 := load64(src, index0)
+ cv1 := load64(src, index1)
+ lTable[hash7(cv0, lTableBits)] = uint16(index0)
+ sTable[hash4(cv0>>8, sTableBits)] = uint16(index0 + 1)
+
+ lTable[hash7(cv1, lTableBits)] = uint16(index1)
+ sTable[hash4(cv1>>8, sTableBits)] = uint16(index1 + 1)
+ index0 += 1
+ index1 -= 1
+ cv = load64(src, s)
+
+ // Index large values sparsely in between.
+ // We do two starting from different offsets for speed.
+ index2 := (index0 + index1 + 1) >> 1
+ for index2 < index1 {
+ lTable[hash7(load64(src, index0), lTableBits)] = uint16(index0)
+ lTable[hash7(load64(src, index2), lTableBits)] = uint16(index2)
+ index0 += 2
+ index2 += 2
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
+
+// encodeBlockBetterDict encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlockBetterDict(dst, src []byte, dict *Dict) (d int) {
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ // Initialize the hash tables.
+ const (
+ // Long hash matches.
+ lTableBits = betterLongTableBits
+ maxLTableSize = betterLongTableSize
+
+ // Short hash matches.
+ sTableBits = betterShortTableBits
+ maxSTableSize = betterShortTableSize
+
+ maxAhead = 8 // maximum bytes ahead without checking sLimit
+
+ debug = false
+ )
+
+ sLimit := min(len(src)-inputMargin, MaxDictSrcOffset-maxAhead)
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+
+ dict.initBetter()
+
+ tbl := getBetterTables()
+ lTable := &tbl.lTable
+ sTable := &tbl.sTable
+ defer betterTablePool.Put(tbl)
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - len(src)>>5 - 6
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 0
+ cv := load64(src, s)
+
+ // We initialize repeat to 0, so we never match on first attempt
+ repeat := len(dict.dict) - dict.repeat
+
+ // While in dict
+searchDict:
+ for {
+ candidateL := 0
+ nextS := 0
+ for {
+ // Next src position to check
+ nextS = s + (s-nextEmit)>>7 + 1
+ if nextS > sLimit {
+ break searchDict
+ }
+ hashL := hash7(cv, lTableBits)
+ hashS := hash4(cv, sTableBits)
+ candidateL = int(lTable[hashL])
+ candidateS := int(sTable[hashS])
+ dictL := int(dict.betterTableLong[hashL])
+ dictS := int(dict.betterTableShort[hashS])
+ lTable[hashL] = uint32(s)
+ sTable[hashS] = uint32(s)
+
+ valLong := load64(src, candidateL)
+ valShort := load64(src, candidateS)
+
+ // If long matches at least 8 bytes, use that.
+ if s != 0 {
+ if cv == valLong {
+ goto emitMatch
+ }
+ if cv == valShort {
+ candidateL = candidateS
+ goto emitMatch
+ }
+ }
+
+ // Check dict repeat.
+ if repeat >= s+4 {
+ candidate := len(dict.dict) - repeat + s
+ if candidate > 0 && uint32(cv) == load32(dict.dict, candidate) {
+ // Extend back
+ base := s
+ for i := candidate; base > nextEmit && i > 0 && dict.dict[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+ if debug && nextEmit != base {
+ fmt.Println("emitted ", base-nextEmit, "literals")
+ }
+ s += 4
+ candidate += 4
+ for candidate < len(dict.dict)-8 && s <= len(src)-8 {
+ if diff := load64(src, s) ^ load64(dict.dict, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+ d += emitRepeat(dst[d:], repeat, s-base)
+ if debug {
+ fmt.Println("emitted dict repeat length", s-base, "offset:", repeat, "s:", s)
+ }
+ nextEmit = s
+ if s >= sLimit {
+ break searchDict
+ }
+ // Index in-between
+ index0 := base + 1
+ index1 := s - 2
+
+ cv = load64(src, s)
+ for index0 < index1 {
+ cv0 := load64(src, index0)
+ cv1 := load64(src, index1)
+ lTable[hash7(cv0, lTableBits)] = uint32(index0)
+ sTable[hash4(cv0>>8, sTableBits)] = uint32(index0 + 1)
+
+ lTable[hash7(cv1, lTableBits)] = uint32(index1)
+ sTable[hash4(cv1>>8, sTableBits)] = uint32(index1 + 1)
+ index0 += 2
+ index1 -= 2
+ }
+ continue
+ }
+ }
+ // Don't try to find match at s==0
+ if s == 0 {
+ cv = load64(src, nextS)
+ s = nextS
+ continue
+ }
+
+ // Long likely matches 7, so take that.
+ if uint32(cv) == uint32(valLong) {
+ goto emitMatch
+ }
+
+ // Long dict...
+ if uint32(cv) == load32(dict.dict, dictL) {
+ candidateL = dictL
+ goto emitDict
+ }
+
+ // Check our short candidate
+ if uint32(cv) == uint32(valShort) {
+ // Try a long candidate at s+1
+ hashL = hash7(cv>>8, lTableBits)
+ candidateL = int(lTable[hashL])
+ lTable[hashL] = uint32(s + 1)
+ if uint32(cv>>8) == load32(src, candidateL) {
+ s++
+ goto emitMatch
+ }
+ // Use our short candidate.
+ candidateL = candidateS
+ goto emitMatch
+ }
+ if uint32(cv) == load32(dict.dict, dictS) {
+ // Try a long candidate at s+1
+ hashL = hash7(cv>>8, lTableBits)
+ candidateL = int(lTable[hashL])
+ lTable[hashL] = uint32(s + 1)
+ if uint32(cv>>8) == load32(src, candidateL) {
+ s++
+ goto emitMatch
+ }
+ candidateL = dictS
+ goto emitDict
+ }
+ cv = load64(src, nextS)
+ s = nextS
+ }
+ emitDict:
+ {
+ if debug {
+ if load32(dict.dict, candidateL) != load32(src, s) {
+ panic("dict emit mismatch")
+ }
+ }
+ // Extend backwards.
+ // The top bytes will be rechecked to get the full match.
+ for candidateL > 0 && s > nextEmit && dict.dict[candidateL-1] == src[s-1] {
+ candidateL--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ d += emitLiteral(dst[d:], src[nextEmit:s])
+ if debug && nextEmit != s {
+ fmt.Println("emitted ", s-nextEmit, "literals")
+ }
+ {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+ base := s
+ offset := s + (len(dict.dict)) - candidateL
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidateL += 4
+ for s <= len(src)-8 && len(dict.dict)-candidateL >= 8 {
+ if diff := load64(src, s) ^ load64(dict.dict, candidateL); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidateL += 8
+ }
+
+ if repeat == offset {
+ if debug {
+ fmt.Println("emitted dict repeat, length", s-base, "offset:", offset, "s:", s, "dict offset:", candidateL)
+ }
+ d += emitRepeat(dst[d:], offset, s-base)
+ } else {
+ if debug {
+ fmt.Println("emitted dict copy, length", s-base, "offset:", offset, "s:", s, "dict offset:", candidateL)
+ }
+ // Matches longer than 64 are split.
+ if s <= sLimit || s-base < 8 {
+ d += emitCopy(dst[d:], offset, s-base)
+ } else {
+ // Split to ensure we don't start a copy within next block.
+ d += emitCopy(dst[d:], offset, 4)
+ d += emitRepeat(dst[d:], offset, s-base-4)
+ }
+ repeat = offset
+ }
+ if false {
+ // Validate match.
+ if s <= candidateL {
+ panic("s <= candidate")
+ }
+ a := src[base:s]
+ b := dict.dict[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+
+ nextEmit = s
+ if s >= sLimit {
+ break searchDict
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+
+ // Index short & long
+ index0 := base + 1
+ index1 := s - 2
+
+ cv0 := load64(src, index0)
+ cv1 := load64(src, index1)
+ lTable[hash7(cv0, lTableBits)] = uint32(index0)
+ sTable[hash4(cv0>>8, sTableBits)] = uint32(index0 + 1)
+
+ lTable[hash7(cv1, lTableBits)] = uint32(index1)
+ sTable[hash4(cv1>>8, sTableBits)] = uint32(index1 + 1)
+ index0 += 1
+ index1 -= 1
+ cv = load64(src, s)
+
+ // index every second long in between.
+ for index0 < index1 {
+ lTable[hash7(load64(src, index0), lTableBits)] = uint32(index0)
+ lTable[hash7(load64(src, index1), lTableBits)] = uint32(index1)
+ index0 += 2
+ index1 -= 2
+ }
+ }
+ continue
+ }
+ emitMatch:
+
+ // Extend backwards
+ for candidateL > 0 && s > nextEmit && src[candidateL-1] == src[s-1] {
+ candidateL--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ base := s
+ offset := base - candidateL
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidateL += 4
+ for s < len(src) {
+ if len(src)-s < 8 {
+ if src[s] == src[candidateL] {
+ s++
+ candidateL++
+ continue
+ }
+ break
+ }
+ if diff := load64(src, s) ^ load64(src, candidateL); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidateL += 8
+ }
+
+ if offset > 65535 && s-base <= 5 && repeat != offset {
+ // Bail if the match is equal or worse to the encoding.
+ s = nextS + 1
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ cv = load64(src, s)
+ continue
+ }
+
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+ if debug && nextEmit != s {
+ fmt.Println("emitted ", s-nextEmit, "literals")
+ }
+ if repeat == offset {
+ if debug {
+ fmt.Println("emitted match repeat, length", s-base, "offset:", offset, "s:", s)
+ }
+ d += emitRepeat(dst[d:], offset, s-base)
+ } else {
+ if debug {
+ fmt.Println("emitted match copy, length", s-base, "offset:", offset, "s:", s)
+ }
+ d += emitCopy(dst[d:], offset, s-base)
+ repeat = offset
+ }
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+
+ // Index short & long
+ index0 := base + 1
+ index1 := s - 2
+
+ cv0 := load64(src, index0)
+ cv1 := load64(src, index1)
+ lTable[hash7(cv0, lTableBits)] = uint32(index0)
+ sTable[hash4(cv0>>8, sTableBits)] = uint32(index0 + 1)
+
+ lTable[hash7(cv1, lTableBits)] = uint32(index1)
+ sTable[hash4(cv1>>8, sTableBits)] = uint32(index1 + 1)
+ index0 += 1
+ index1 -= 1
+ cv = load64(src, s)
+
+ // Index large values sparsely in between.
+ // We do two starting from different offsets for speed.
+ index2 := (index0 + index1 + 1) >> 1
+ for index2 < index1 {
+ lTable[hash7(load64(src, index0), lTableBits)] = uint32(index0)
+ lTable[hash7(load64(src, index2), lTableBits)] = uint32(index2)
+ index0 += 2
+ index2 += 2
+ }
+ }
+
+ // Search without dict:
+ if repeat > s {
+ repeat = 0
+ }
+
+ // No more dict
+ sLimit = len(src) - inputMargin
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ cv = load64(src, s)
+ if debug {
+ fmt.Println("now", s, "->", sLimit, "out:", d, "left:", len(src)-s, "nextemit:", nextEmit, "dstLimit:", dstLimit, "s:", s)
+ }
+ for {
+ candidateL := 0
+ nextS := 0
+ for {
+ // Next src position to check
+ nextS = s + (s-nextEmit)>>7 + 1
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hashL := hash7(cv, lTableBits)
+ hashS := hash4(cv, sTableBits)
+ candidateL = int(lTable[hashL])
+ candidateS := int(sTable[hashS])
+ lTable[hashL] = uint32(s)
+ sTable[hashS] = uint32(s)
+
+ valLong := load64(src, candidateL)
+ valShort := load64(src, candidateS)
+
+ // If long matches at least 8 bytes, use that.
+ if cv == valLong {
+ break
+ }
+ if cv == valShort {
+ candidateL = candidateS
+ break
+ }
+
+ // Check repeat at offset checkRep.
+ const checkRep = 1
+ // Minimum length of a repeat. Tested with various values.
+ // While 4-5 offers improvements in some, 6 reduces
+ // regressions significantly.
+ const wantRepeatBytes = 6
+ const repeatMask = ((1 << (wantRepeatBytes * 8)) - 1) << (8 * checkRep)
+ if false && repeat > 0 && cv&repeatMask == load64(src, s-repeat)&repeatMask {
+ base := s + checkRep
+ // Extend back
+ for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+
+ // Extend forward
+ candidate := s - repeat + wantRepeatBytes + checkRep
+ s += wantRepeatBytes + checkRep
+ for s < len(src) {
+ if len(src)-s < 8 {
+ if src[s] == src[candidate] {
+ s++
+ candidate++
+ continue
+ }
+ break
+ }
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+ // same as `add := emitCopy(dst[d:], repeat, s-base)` but skips storing offset.
+ d += emitRepeat(dst[d:], repeat, s-base)
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ // Index in-between
+ index0 := base + 1
+ index1 := s - 2
+
+ for index0 < index1 {
+ cv0 := load64(src, index0)
+ cv1 := load64(src, index1)
+ lTable[hash7(cv0, lTableBits)] = uint32(index0)
+ sTable[hash4(cv0>>8, sTableBits)] = uint32(index0 + 1)
+
+ lTable[hash7(cv1, lTableBits)] = uint32(index1)
+ sTable[hash4(cv1>>8, sTableBits)] = uint32(index1 + 1)
+ index0 += 2
+ index1 -= 2
+ }
+
+ cv = load64(src, s)
+ continue
+ }
+
+ // Long likely matches 7, so take that.
+ if uint32(cv) == uint32(valLong) {
+ break
+ }
+
+ // Check our short candidate
+ if uint32(cv) == uint32(valShort) {
+ // Try a long candidate at s+1
+ hashL = hash7(cv>>8, lTableBits)
+ candidateL = int(lTable[hashL])
+ lTable[hashL] = uint32(s + 1)
+ if uint32(cv>>8) == load32(src, candidateL) {
+ s++
+ break
+ }
+ // Use our short candidate.
+ candidateL = candidateS
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards
+ for candidateL > 0 && s > nextEmit && src[candidateL-1] == src[s-1] {
+ candidateL--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ base := s
+ offset := base - candidateL
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidateL += 4
+ for s < len(src) {
+ if len(src)-s < 8 {
+ if src[s] == src[candidateL] {
+ s++
+ candidateL++
+ continue
+ }
+ break
+ }
+ if diff := load64(src, s) ^ load64(src, candidateL); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidateL += 8
+ }
+
+ if offset > 65535 && s-base <= 5 && repeat != offset {
+ // Bail if the match is equal or worse to the encoding.
+ s = nextS + 1
+ if s >= sLimit {
+ goto emitRemainder
+ }
+ cv = load64(src, s)
+ continue
+ }
+
+ d += emitLiteral(dst[d:], src[nextEmit:base])
+ if repeat == offset {
+ d += emitRepeat(dst[d:], offset, s-base)
+ } else {
+ d += emitCopy(dst[d:], offset, s-base)
+ repeat = offset
+ }
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+
+ // Index short & long
+ index0 := base + 1
+ index1 := s - 2
+
+ cv0 := load64(src, index0)
+ cv1 := load64(src, index1)
+ lTable[hash7(cv0, lTableBits)] = uint32(index0)
+ sTable[hash4(cv0>>8, sTableBits)] = uint32(index0 + 1)
+
+ lTable[hash7(cv1, lTableBits)] = uint32(index1)
+ sTable[hash4(cv1>>8, sTableBits)] = uint32(index1 + 1)
+ index0 += 1
+ index1 -= 1
+ cv = load64(src, s)
+
+ // Index large values sparsely in between.
+ // We do two starting from different offsets for speed.
+ index2 := (index0 + index1 + 1) >> 1
+ for index2 < index1 {
+ lTable[hash7(load64(src, index0), lTableBits)] = uint32(index0)
+ lTable[hash7(load64(src, index2), lTableBits)] = uint32(index2)
+ index0 += 2
+ index2 += 2
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
diff --git a/vendor/github.com/klauspost/compress/s2/encode_go.go b/vendor/github.com/klauspost/compress/s2/encode_go.go
new file mode 100644
index 00000000000..5597f3ef2ec
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/encode_go.go
@@ -0,0 +1,740 @@
+//go:build !amd64 || appengine || !gc || noasm
+
+package s2
+
+import (
+ "bytes"
+ "math/bits"
+)
+
+const hasAmd64Asm = false
+
+// encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src))
+func encodeBlock(dst, src []byte) (d int) {
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+ if len(src) <= 64<<10 {
+ return encodeBlockGo64K(dst, src)
+ }
+ return encodeBlockGo(dst, src)
+}
+
+// encodeBlockBetter encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src))
+func encodeBlockBetter(dst, src []byte) (d int) {
+ if len(src) <= 64<<10 {
+ return encodeBlockBetterGo64K(dst, src)
+ }
+ return encodeBlockBetterGo(dst, src)
+}
+
+// encodeBlockBetter encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src))
+func encodeBlockBetterSnappy(dst, src []byte) (d int) {
+ if len(src) <= 64<<10 {
+ return encodeBlockBetterSnappyGo64K(dst, src)
+ }
+ return encodeBlockBetterSnappyGo(dst, src)
+}
+
+// encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src))
+func encodeBlockSnappy(dst, src []byte) (d int) {
+ if len(src) < minNonLiteralBlockSize {
+ return 0
+ }
+ if len(src) <= 64<<10 {
+ return encodeBlockSnappyGo64K(dst, src)
+ }
+ return encodeBlockSnappyGo(dst, src)
+}
+
+// emitLiteral writes a literal chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes
+// 0 <= len(lit) && len(lit) <= math.MaxUint32
+func emitLiteral(dst, lit []byte) int {
+ if len(lit) == 0 {
+ return 0
+ }
+ const num = 63<<2 | tagLiteral
+ i, n := 0, uint(len(lit)-1)
+ switch {
+ case n < 60:
+ dst[0] = uint8(n)<<2 | tagLiteral
+ i = 1
+ case n < 1<<8:
+ dst[1] = uint8(n)
+ dst[0] = 60<<2 | tagLiteral
+ i = 2
+ case n < 1<<16:
+ dst[2] = uint8(n >> 8)
+ dst[1] = uint8(n)
+ dst[0] = 61<<2 | tagLiteral
+ i = 3
+ case n < 1<<24:
+ dst[3] = uint8(n >> 16)
+ dst[2] = uint8(n >> 8)
+ dst[1] = uint8(n)
+ dst[0] = 62<<2 | tagLiteral
+ i = 4
+ default:
+ dst[4] = uint8(n >> 24)
+ dst[3] = uint8(n >> 16)
+ dst[2] = uint8(n >> 8)
+ dst[1] = uint8(n)
+ dst[0] = 63<<2 | tagLiteral
+ i = 5
+ }
+ return i + copy(dst[i:], lit)
+}
+
+// emitRepeat writes a repeat chunk and returns the number of bytes written.
+// Length must be at least 4 and < 1<<24
+func emitRepeat(dst []byte, offset, length int) int {
+ // Repeat offset, make length cheaper
+ length -= 4
+ if length <= 4 {
+ dst[0] = uint8(length)<<2 | tagCopy1
+ dst[1] = 0
+ return 2
+ }
+ if length < 8 && offset < 2048 {
+ // Encode WITH offset
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(length)<<2 | tagCopy1
+ return 2
+ }
+ if length < (1<<8)+4 {
+ length -= 4
+ dst[2] = uint8(length)
+ dst[1] = 0
+ dst[0] = 5<<2 | tagCopy1
+ return 3
+ }
+ if length < (1<<16)+(1<<8) {
+ length -= 1 << 8
+ dst[3] = uint8(length >> 8)
+ dst[2] = uint8(length >> 0)
+ dst[1] = 0
+ dst[0] = 6<<2 | tagCopy1
+ return 4
+ }
+ const maxRepeat = (1 << 24) - 1
+ length -= 1 << 16
+ left := 0
+ if length > maxRepeat {
+ left = length - maxRepeat + 4
+ length = maxRepeat - 4
+ }
+ dst[4] = uint8(length >> 16)
+ dst[3] = uint8(length >> 8)
+ dst[2] = uint8(length >> 0)
+ dst[1] = 0
+ dst[0] = 7<<2 | tagCopy1
+ if left > 0 {
+ return 5 + emitRepeat(dst[5:], offset, left)
+ }
+ return 5
+}
+
+// emitCopy writes a copy chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes
+// 1 <= offset && offset <= math.MaxUint32
+// 4 <= length && length <= 1 << 24
+func emitCopy(dst []byte, offset, length int) int {
+ if offset >= 65536 {
+ i := 0
+ if length > 64 {
+ // Emit a length 64 copy, encoded as 5 bytes.
+ dst[4] = uint8(offset >> 24)
+ dst[3] = uint8(offset >> 16)
+ dst[2] = uint8(offset >> 8)
+ dst[1] = uint8(offset)
+ dst[0] = 63<<2 | tagCopy4
+ length -= 64
+ if length >= 4 {
+ // Emit remaining as repeats
+ return 5 + emitRepeat(dst[5:], offset, length)
+ }
+ i = 5
+ }
+ if length == 0 {
+ return i
+ }
+ // Emit a copy, offset encoded as 4 bytes.
+ dst[i+0] = uint8(length-1)<<2 | tagCopy4
+ dst[i+1] = uint8(offset)
+ dst[i+2] = uint8(offset >> 8)
+ dst[i+3] = uint8(offset >> 16)
+ dst[i+4] = uint8(offset >> 24)
+ return i + 5
+ }
+
+ // Offset no more than 2 bytes.
+ if length > 64 {
+ off := 3
+ if offset < 2048 {
+ // emit 8 bytes as tagCopy1, rest as repeats.
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(8-4)<<2 | tagCopy1
+ length -= 8
+ off = 2
+ } else {
+ // Emit a length 60 copy, encoded as 3 bytes.
+ // Emit remaining as repeat value (minimum 4 bytes).
+ dst[2] = uint8(offset >> 8)
+ dst[1] = uint8(offset)
+ dst[0] = 59<<2 | tagCopy2
+ length -= 60
+ }
+ // Emit remaining as repeats, at least 4 bytes remain.
+ return off + emitRepeat(dst[off:], offset, length)
+ }
+ if length >= 12 || offset >= 2048 {
+ // Emit the remaining copy, encoded as 3 bytes.
+ dst[2] = uint8(offset >> 8)
+ dst[1] = uint8(offset)
+ dst[0] = uint8(length-1)<<2 | tagCopy2
+ return 3
+ }
+ // Emit the remaining copy, encoded as 2 bytes.
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
+ return 2
+}
+
+// emitCopyNoRepeat writes a copy chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes
+// 1 <= offset && offset <= math.MaxUint32
+// 4 <= length && length <= 1 << 24
+func emitCopyNoRepeat(dst []byte, offset, length int) int {
+ if offset >= 65536 {
+ i := 0
+ if length > 64 {
+ // Emit a length 64 copy, encoded as 5 bytes.
+ dst[4] = uint8(offset >> 24)
+ dst[3] = uint8(offset >> 16)
+ dst[2] = uint8(offset >> 8)
+ dst[1] = uint8(offset)
+ dst[0] = 63<<2 | tagCopy4
+ length -= 64
+ if length >= 4 {
+ // Emit remaining as repeats
+ return 5 + emitCopyNoRepeat(dst[5:], offset, length)
+ }
+ i = 5
+ }
+ if length == 0 {
+ return i
+ }
+ // Emit a copy, offset encoded as 4 bytes.
+ dst[i+0] = uint8(length-1)<<2 | tagCopy4
+ dst[i+1] = uint8(offset)
+ dst[i+2] = uint8(offset >> 8)
+ dst[i+3] = uint8(offset >> 16)
+ dst[i+4] = uint8(offset >> 24)
+ return i + 5
+ }
+
+ // Offset no more than 2 bytes.
+ if length > 64 {
+ // Emit a length 60 copy, encoded as 3 bytes.
+ // Emit remaining as repeat value (minimum 4 bytes).
+ dst[2] = uint8(offset >> 8)
+ dst[1] = uint8(offset)
+ dst[0] = 59<<2 | tagCopy2
+ length -= 60
+ // Emit remaining as repeats, at least 4 bytes remain.
+ return 3 + emitCopyNoRepeat(dst[3:], offset, length)
+ }
+ if length >= 12 || offset >= 2048 {
+ // Emit the remaining copy, encoded as 3 bytes.
+ dst[2] = uint8(offset >> 8)
+ dst[1] = uint8(offset)
+ dst[0] = uint8(length-1)<<2 | tagCopy2
+ return 3
+ }
+ // Emit the remaining copy, encoded as 2 bytes.
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
+ return 2
+}
+
+// matchLen returns how many bytes match in a and b
+//
+// It assumes that:
+//
+// len(a) <= len(b)
+func matchLen(a []byte, b []byte) int {
+ b = b[:len(a)]
+ var checked int
+ if len(a) > 4 {
+ // Try 4 bytes first
+ if diff := load32(a, 0) ^ load32(b, 0); diff != 0 {
+ return bits.TrailingZeros32(diff) >> 3
+ }
+ // Switch to 8 byte matching.
+ checked = 4
+ a = a[4:]
+ b = b[4:]
+ for len(a) >= 8 {
+ b = b[:len(a)]
+ if diff := load64(a, 0) ^ load64(b, 0); diff != 0 {
+ return checked + (bits.TrailingZeros64(diff) >> 3)
+ }
+ checked += 8
+ a = a[8:]
+ b = b[8:]
+ }
+ }
+ b = b[:len(a)]
+ for i := range a {
+ if a[i] != b[i] {
+ return int(i) + checked
+ }
+ }
+ return len(a) + checked
+}
+
+// input must be > inputMargin
+func calcBlockSize(src []byte, _ *[32768]byte) (d int) {
+ // Initialize the hash table.
+ const (
+ tableBits = 13
+ maxTableSize = 1 << tableBits
+ )
+
+ var table [maxTableSize]uint32
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - len(src)>>5 - 5
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ cv := load64(src, s)
+
+ // We search for a repeat at -1, but don't output repeats when nextEmit == 0
+ repeat := 1
+
+ for {
+ candidate := 0
+ for {
+ // Next src position to check
+ nextS := s + (s-nextEmit)>>6 + 4
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hash0 := hash6(cv, tableBits)
+ hash1 := hash6(cv>>8, tableBits)
+ candidate = int(table[hash0])
+ candidate2 := int(table[hash1])
+ table[hash0] = uint32(s)
+ table[hash1] = uint32(s + 1)
+ hash2 := hash6(cv>>16, tableBits)
+
+ // Check repeat at offset checkRep.
+ const checkRep = 1
+ if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
+ base := s + checkRep
+ // Extend back
+ for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+ d += emitLiteralSize(src[nextEmit:base])
+
+ // Extend forward
+ candidate := s - repeat + 4 + checkRep
+ s += 4 + checkRep
+ for s <= sLimit {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+
+ d += emitCopyNoRepeatSize(repeat, s-base)
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ cv = load64(src, s)
+ continue
+ }
+
+ if uint32(cv) == load32(src, candidate) {
+ break
+ }
+ candidate = int(table[hash2])
+ if uint32(cv>>8) == load32(src, candidate2) {
+ table[hash2] = uint32(s + 2)
+ candidate = candidate2
+ s++
+ break
+ }
+ table[hash2] = uint32(s + 2)
+ if uint32(cv>>16) == load32(src, candidate) {
+ s += 2
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards
+ for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
+ candidate--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ d += emitLiteralSize(src[nextEmit:s])
+
+ // Call emitCopy, and then see if another emitCopy could be our next
+ // move. Repeat until we find no match for the input immediately after
+ // what was consumed by the last emitCopy call.
+ //
+ // If we exit this loop normally then we need to call emitLiteral next,
+ // though we don't yet know how big the literal will be. We handle that
+ // by proceeding to the next iteration of the main loop. We also can
+ // exit this loop via goto if we get close to exhausting the input.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+ base := s
+ repeat = base - candidate
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidate += 4
+ for s <= len(src)-8 {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+
+ d += emitCopyNoRepeatSize(repeat, s-base)
+ if false {
+ // Validate match.
+ a := src[base:s]
+ b := src[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+ // Check for an immediate match, otherwise start search at s+1
+ x := load64(src, s-2)
+ m2Hash := hash6(x, tableBits)
+ currHash := hash6(x>>16, tableBits)
+ candidate = int(table[currHash])
+ table[m2Hash] = uint32(s - 2)
+ table[currHash] = uint32(s)
+ if uint32(x>>16) != load32(src, candidate) {
+ cv = load64(src, s+1)
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteralSize(src[nextEmit:])
+ }
+ return d
+}
+
+// length must be > inputMargin.
+func calcBlockSizeSmall(src []byte, _ *[2048]byte) (d int) {
+ // Initialize the hash table.
+ const (
+ tableBits = 9
+ maxTableSize = 1 << tableBits
+ )
+
+ var table [maxTableSize]uint32
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := len(src) - inputMargin
+
+ // Bail if we can't compress to at least this.
+ dstLimit := len(src) - len(src)>>5 - 5
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ cv := load64(src, s)
+
+ // We search for a repeat at -1, but don't output repeats when nextEmit == 0
+ repeat := 1
+
+ for {
+ candidate := 0
+ for {
+ // Next src position to check
+ nextS := s + (s-nextEmit)>>6 + 4
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ hash0 := hash6(cv, tableBits)
+ hash1 := hash6(cv>>8, tableBits)
+ candidate = int(table[hash0])
+ candidate2 := int(table[hash1])
+ table[hash0] = uint32(s)
+ table[hash1] = uint32(s + 1)
+ hash2 := hash6(cv>>16, tableBits)
+
+ // Check repeat at offset checkRep.
+ const checkRep = 1
+ if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
+ base := s + checkRep
+ // Extend back
+ for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
+ i--
+ base--
+ }
+ d += emitLiteralSize(src[nextEmit:base])
+
+ // Extend forward
+ candidate := s - repeat + 4 + checkRep
+ s += 4 + checkRep
+ for s <= sLimit {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+
+ d += emitCopyNoRepeatSize(repeat, s-base)
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ cv = load64(src, s)
+ continue
+ }
+
+ if uint32(cv) == load32(src, candidate) {
+ break
+ }
+ candidate = int(table[hash2])
+ if uint32(cv>>8) == load32(src, candidate2) {
+ table[hash2] = uint32(s + 2)
+ candidate = candidate2
+ s++
+ break
+ }
+ table[hash2] = uint32(s + 2)
+ if uint32(cv>>16) == load32(src, candidate) {
+ s += 2
+ break
+ }
+
+ cv = load64(src, nextS)
+ s = nextS
+ }
+
+ // Extend backwards
+ for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
+ candidate--
+ s--
+ }
+
+ // Bail if we exceed the maximum size.
+ if d+(s-nextEmit) > dstLimit {
+ return 0
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ d += emitLiteralSize(src[nextEmit:s])
+
+ // Call emitCopy, and then see if another emitCopy could be our next
+ // move. Repeat until we find no match for the input immediately after
+ // what was consumed by the last emitCopy call.
+ //
+ // If we exit this loop normally then we need to call emitLiteral next,
+ // though we don't yet know how big the literal will be. We handle that
+ // by proceeding to the next iteration of the main loop. We also can
+ // exit this loop via goto if we get close to exhausting the input.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+ base := s
+ repeat = base - candidate
+
+ // Extend the 4-byte match as long as possible.
+ s += 4
+ candidate += 4
+ for s <= len(src)-8 {
+ if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
+ s += bits.TrailingZeros64(diff) >> 3
+ break
+ }
+ s += 8
+ candidate += 8
+ }
+
+ d += emitCopyNoRepeatSize(repeat, s-base)
+ if false {
+ // Validate match.
+ a := src[base:s]
+ b := src[base-repeat : base-repeat+(s-base)]
+ if !bytes.Equal(a, b) {
+ panic("mismatch")
+ }
+ }
+
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if d > dstLimit {
+ // Do we have space for more, if not bail.
+ return 0
+ }
+ // Check for an immediate match, otherwise start search at s+1
+ x := load64(src, s-2)
+ m2Hash := hash6(x, tableBits)
+ currHash := hash6(x>>16, tableBits)
+ candidate = int(table[currHash])
+ table[m2Hash] = uint32(s - 2)
+ table[currHash] = uint32(s)
+ if uint32(x>>16) != load32(src, candidate) {
+ cv = load64(src, s+1)
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ // Bail if we exceed the maximum size.
+ if d+len(src)-nextEmit > dstLimit {
+ return 0
+ }
+ d += emitLiteralSize(src[nextEmit:])
+ }
+ return d
+}
+
+// emitLiteral writes a literal chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes
+// 0 <= len(lit) && len(lit) <= math.MaxUint32
+func emitLiteralSize(lit []byte) int {
+ if len(lit) == 0 {
+ return 0
+ }
+ switch {
+ case len(lit) <= 60:
+ return len(lit) + 1
+ case len(lit) <= 1<<8:
+ return len(lit) + 2
+ case len(lit) <= 1<<16:
+ return len(lit) + 3
+ case len(lit) <= 1<<24:
+ return len(lit) + 4
+ default:
+ return len(lit) + 5
+ }
+}
+
+func cvtLZ4BlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
+ panic("cvtLZ4BlockAsm should be unreachable")
+}
+
+func cvtLZ4BlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
+ panic("cvtLZ4BlockSnappyAsm should be unreachable")
+}
+
+func cvtLZ4sBlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
+ panic("cvtLZ4sBlockAsm should be unreachable")
+}
+
+func cvtLZ4sBlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
+ panic("cvtLZ4sBlockSnappyAsm should be unreachable")
+}
diff --git a/vendor/github.com/klauspost/compress/s2/encodeblock_amd64.go b/vendor/github.com/klauspost/compress/s2/encodeblock_amd64.go
new file mode 100644
index 00000000000..f43aa815435
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/encodeblock_amd64.go
@@ -0,0 +1,228 @@
+// Code generated by command: go run gen.go -out ../encodeblock_amd64.s -stubs ../encodeblock_amd64.go -pkg=s2. DO NOT EDIT.
+
+//go:build !appengine && !noasm && gc && !noasm
+
+package s2
+
+func _dummy_()
+
+// encodeBlockAsm encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 4294967295 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeBlockAsm(dst []byte, src []byte, tmp *[65536]byte) int
+
+// encodeBlockAsm4MB encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 4194304 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeBlockAsm4MB(dst []byte, src []byte, tmp *[65536]byte) int
+
+// encodeBlockAsm12B encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 16383 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeBlockAsm12B(dst []byte, src []byte, tmp *[16384]byte) int
+
+// encodeBlockAsm10B encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 4095 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeBlockAsm10B(dst []byte, src []byte, tmp *[4096]byte) int
+
+// encodeBlockAsm8B encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 511 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeBlockAsm8B(dst []byte, src []byte, tmp *[1024]byte) int
+
+// encodeBetterBlockAsm encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 4294967295 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeBetterBlockAsm(dst []byte, src []byte, tmp *[589824]byte) int
+
+// encodeBetterBlockAsm4MB encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 4194304 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeBetterBlockAsm4MB(dst []byte, src []byte, tmp *[589824]byte) int
+
+// encodeBetterBlockAsm12B encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 16383 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeBetterBlockAsm12B(dst []byte, src []byte, tmp *[81920]byte) int
+
+// encodeBetterBlockAsm10B encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 4095 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeBetterBlockAsm10B(dst []byte, src []byte, tmp *[20480]byte) int
+
+// encodeBetterBlockAsm8B encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 511 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeBetterBlockAsm8B(dst []byte, src []byte, tmp *[5120]byte) int
+
+// encodeSnappyBlockAsm encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 4294967295 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeSnappyBlockAsm(dst []byte, src []byte, tmp *[65536]byte) int
+
+// encodeSnappyBlockAsm64K encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 65535 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeSnappyBlockAsm64K(dst []byte, src []byte, tmp *[65536]byte) int
+
+// encodeSnappyBlockAsm12B encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 16383 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeSnappyBlockAsm12B(dst []byte, src []byte, tmp *[16384]byte) int
+
+// encodeSnappyBlockAsm10B encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 4095 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeSnappyBlockAsm10B(dst []byte, src []byte, tmp *[4096]byte) int
+
+// encodeSnappyBlockAsm8B encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 511 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeSnappyBlockAsm8B(dst []byte, src []byte, tmp *[1024]byte) int
+
+// encodeSnappyBetterBlockAsm encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 4294967295 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeSnappyBetterBlockAsm(dst []byte, src []byte, tmp *[589824]byte) int
+
+// encodeSnappyBetterBlockAsm64K encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 65535 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeSnappyBetterBlockAsm64K(dst []byte, src []byte, tmp *[294912]byte) int
+
+// encodeSnappyBetterBlockAsm12B encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 16383 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeSnappyBetterBlockAsm12B(dst []byte, src []byte, tmp *[81920]byte) int
+
+// encodeSnappyBetterBlockAsm10B encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 4095 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeSnappyBetterBlockAsm10B(dst []byte, src []byte, tmp *[20480]byte) int
+
+// encodeSnappyBetterBlockAsm8B encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 511 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func encodeSnappyBetterBlockAsm8B(dst []byte, src []byte, tmp *[5120]byte) int
+
+// calcBlockSize encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 4294967295 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func calcBlockSize(src []byte, tmp *[32768]byte) int
+
+// calcBlockSizeSmall encodes a non-empty src to a guaranteed-large-enough dst.
+// Maximum input 1024 bytes.
+// It assumes that the varint-encoded length of the decompressed bytes has already been written.
+//
+//go:noescape
+func calcBlockSizeSmall(src []byte, tmp *[2048]byte) int
+
+// emitLiteral writes a literal chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes with margin of 0 bytes
+// 0 <= len(lit) && len(lit) <= math.MaxUint32
+//
+//go:noescape
+func emitLiteral(dst []byte, lit []byte) int
+
+// emitRepeat writes a repeat chunk and returns the number of bytes written.
+// Length must be at least 4 and < 1<<32
+//
+//go:noescape
+func emitRepeat(dst []byte, offset int, length int) int
+
+// emitCopy writes a copy chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes
+// 1 <= offset && offset <= math.MaxUint32
+// 4 <= length && length <= 1 << 24
+//
+//go:noescape
+func emitCopy(dst []byte, offset int, length int) int
+
+// emitCopyNoRepeat writes a copy chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes
+// 1 <= offset && offset <= math.MaxUint32
+// 4 <= length && length <= 1 << 24
+//
+//go:noescape
+func emitCopyNoRepeat(dst []byte, offset int, length int) int
+
+// matchLen returns how many bytes match in a and b
+//
+// It assumes that:
+//
+// len(a) <= len(b)
+//
+//go:noescape
+func matchLen(a []byte, b []byte) int
+
+// cvtLZ4Block converts an LZ4 block to S2
+//
+//go:noescape
+func cvtLZ4BlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
+
+// cvtLZ4sBlock converts an LZ4s block to S2
+//
+//go:noescape
+func cvtLZ4sBlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
+
+// cvtLZ4Block converts an LZ4 block to Snappy
+//
+//go:noescape
+func cvtLZ4BlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
+
+// cvtLZ4sBlock converts an LZ4s block to Snappy
+//
+//go:noescape
+func cvtLZ4sBlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
diff --git a/vendor/github.com/klauspost/compress/s2/encodeblock_amd64.s b/vendor/github.com/klauspost/compress/s2/encodeblock_amd64.s
new file mode 100644
index 00000000000..df9be687be7
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/encodeblock_amd64.s
@@ -0,0 +1,21303 @@
+// Code generated by command: go run gen.go -out ../encodeblock_amd64.s -stubs ../encodeblock_amd64.go -pkg=s2. DO NOT EDIT.
+
+//go:build !appengine && !noasm && gc && !noasm
+
+#include "textflag.h"
+
+// func _dummy_()
+TEXT ·_dummy_(SB), $0
+#ifdef GOAMD64_v4
+#ifndef GOAMD64_v3
+#define GOAMD64_v3
+#endif
+#endif
+ RET
+
+// func encodeBlockAsm(dst []byte, src []byte, tmp *[65536]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeBlockAsm(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000200, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeBlockAsm:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeBlockAsm
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL DX, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeBlockAsm:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x06, SI
+ LEAL 4(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeBlockAsm
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHRQ $0x08, R11
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x32, R10
+ SHLQ $0x10, R11
+ IMULQ R9, R11
+ SHRQ $0x32, R11
+ MOVL (AX)(R10*4), SI
+ MOVL (AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ LEAL 1(DX), R10
+ MOVL R10, (AX)(R11*4)
+ MOVQ DI, R10
+ SHRQ $0x10, R10
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x32, R10
+ MOVL DX, R9
+ SUBL 16(SP), R9
+ MOVL 1(BX)(R9*1), R11
+ MOVQ DI, R9
+ SHRQ $0x08, R9
+ CMPL R9, R11
+ JNE no_repeat_found_encodeBlockAsm
+ LEAL 1(DX), DI
+ MOVL 12(SP), R8
+ MOVL DI, SI
+ SUBL 16(SP), SI
+ JZ repeat_extend_back_end_encodeBlockAsm
+
+repeat_extend_back_loop_encodeBlockAsm:
+ CMPL DI, R8
+ JBE repeat_extend_back_end_encodeBlockAsm
+ MOVB -1(BX)(SI*1), R9
+ MOVB -1(BX)(DI*1), R10
+ CMPB R9, R10
+ JNE repeat_extend_back_end_encodeBlockAsm
+ LEAL -1(DI), DI
+ DECL SI
+ JNZ repeat_extend_back_loop_encodeBlockAsm
+
+repeat_extend_back_end_encodeBlockAsm:
+ MOVL DI, SI
+ SUBL 12(SP), SI
+ LEAQ 5(CX)(SI*1), SI
+ CMPQ SI, (SP)
+ JB repeat_dst_size_check_encodeBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+repeat_dst_size_check_encodeBlockAsm:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_repeat_emit_encodeBlockAsm
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_repeat_emit_encodeBlockAsm
+ CMPL SI, $0x00000100
+ JB two_bytes_repeat_emit_encodeBlockAsm
+ CMPL SI, $0x00010000
+ JB three_bytes_repeat_emit_encodeBlockAsm
+ CMPL SI, $0x01000000
+ JB four_bytes_repeat_emit_encodeBlockAsm
+ MOVB $0xfc, (CX)
+ MOVL SI, 1(CX)
+ ADDQ $0x05, CX
+ JMP memmove_long_repeat_emit_encodeBlockAsm
+
+four_bytes_repeat_emit_encodeBlockAsm:
+ MOVL SI, R11
+ SHRL $0x10, R11
+ MOVB $0xf8, (CX)
+ MOVW SI, 1(CX)
+ MOVB R11, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_repeat_emit_encodeBlockAsm
+
+three_bytes_repeat_emit_encodeBlockAsm:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_repeat_emit_encodeBlockAsm
+
+two_bytes_repeat_emit_encodeBlockAsm:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_repeat_emit_encodeBlockAsm
+ JMP memmove_long_repeat_emit_encodeBlockAsm
+
+one_byte_repeat_emit_encodeBlockAsm:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_repeat_emit_encodeBlockAsm:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm_memmove_move_17through32
+ JMP emit_lit_memmove_repeat_emit_encodeBlockAsm_memmove_move_33through64
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm_memmove_move_8:
+ MOVQ (R10), R11
+ MOVQ R11, (CX)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_repeat_emit_encodeBlockAsm:
+ MOVQ SI, CX
+ JMP emit_literal_done_repeat_emit_encodeBlockAsm
+
+memmove_long_repeat_emit_encodeBlockAsm:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R12
+ SHRQ $0x05, R12
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R13
+ SUBQ R11, R13
+ DECQ R12
+ JA emit_lit_memmove_long_repeat_emit_encodeBlockAsmlarge_forward_sse_loop_32
+ LEAQ -32(R10)(R13*1), R11
+ LEAQ -32(CX)(R13*1), R14
+
+emit_lit_memmove_long_repeat_emit_encodeBlockAsmlarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R14)
+ MOVOA X5, 16(R14)
+ ADDQ $0x20, R14
+ ADDQ $0x20, R11
+ ADDQ $0x20, R13
+ DECQ R12
+ JNA emit_lit_memmove_long_repeat_emit_encodeBlockAsmlarge_big_loop_back
+
+emit_lit_memmove_long_repeat_emit_encodeBlockAsmlarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R13*1), X4
+ MOVOU -16(R10)(R13*1), X5
+ MOVOA X4, -32(CX)(R13*1)
+ MOVOA X5, -16(CX)(R13*1)
+ ADDQ $0x20, R13
+ CMPQ R9, R13
+ JAE emit_lit_memmove_long_repeat_emit_encodeBlockAsmlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_repeat_emit_encodeBlockAsm:
+ ADDL $0x05, DX
+ MOVL DX, SI
+ SUBL 16(SP), SI
+ MOVQ src_len+32(FP), R9
+ SUBL DX, R9
+ LEAQ (BX)(DX*1), R10
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_repeat_extend_encodeBlockAsm:
+ CMPL R9, $0x10
+ JB matchlen_match8_repeat_extend_encodeBlockAsm
+ MOVQ (R10)(R12*1), R11
+ MOVQ 8(R10)(R12*1), R13
+ XORQ (SI)(R12*1), R11
+ JNZ matchlen_bsf_8_repeat_extend_encodeBlockAsm
+ XORQ 8(SI)(R12*1), R13
+ JNZ matchlen_bsf_16repeat_extend_encodeBlockAsm
+ LEAL -16(R9), R9
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_repeat_extend_encodeBlockAsm
+
+matchlen_bsf_16repeat_extend_encodeBlockAsm:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP repeat_extend_forward_end_encodeBlockAsm
+
+matchlen_match8_repeat_extend_encodeBlockAsm:
+ CMPL R9, $0x08
+ JB matchlen_match4_repeat_extend_encodeBlockAsm
+ MOVQ (R10)(R12*1), R11
+ XORQ (SI)(R12*1), R11
+ JNZ matchlen_bsf_8_repeat_extend_encodeBlockAsm
+ LEAL -8(R9), R9
+ LEAL 8(R12), R12
+ JMP matchlen_match4_repeat_extend_encodeBlockAsm
+
+matchlen_bsf_8_repeat_extend_encodeBlockAsm:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP repeat_extend_forward_end_encodeBlockAsm
+
+matchlen_match4_repeat_extend_encodeBlockAsm:
+ CMPL R9, $0x04
+ JB matchlen_match2_repeat_extend_encodeBlockAsm
+ MOVL (R10)(R12*1), R11
+ CMPL (SI)(R12*1), R11
+ JNE matchlen_match2_repeat_extend_encodeBlockAsm
+ LEAL -4(R9), R9
+ LEAL 4(R12), R12
+
+matchlen_match2_repeat_extend_encodeBlockAsm:
+ CMPL R9, $0x01
+ JE matchlen_match1_repeat_extend_encodeBlockAsm
+ JB repeat_extend_forward_end_encodeBlockAsm
+ MOVW (R10)(R12*1), R11
+ CMPW (SI)(R12*1), R11
+ JNE matchlen_match1_repeat_extend_encodeBlockAsm
+ LEAL 2(R12), R12
+ SUBL $0x02, R9
+ JZ repeat_extend_forward_end_encodeBlockAsm
+
+matchlen_match1_repeat_extend_encodeBlockAsm:
+ MOVB (R10)(R12*1), R11
+ CMPB (SI)(R12*1), R11
+ JNE repeat_extend_forward_end_encodeBlockAsm
+ LEAL 1(R12), R12
+
+repeat_extend_forward_end_encodeBlockAsm:
+ ADDL R12, DX
+ MOVL DX, SI
+ SUBL DI, SI
+ MOVL 16(SP), DI
+ TESTL R8, R8
+ JZ repeat_as_copy_encodeBlockAsm
+
+ // emitRepeat
+emit_repeat_again_match_repeat_encodeBlockAsm:
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_match_repeat_encodeBlockAsm
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_match_repeat_encodeBlockAsm
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_match_repeat_encodeBlockAsm
+
+cant_repeat_two_offset_match_repeat_encodeBlockAsm:
+ CMPL SI, $0x00000104
+ JB repeat_three_match_repeat_encodeBlockAsm
+ CMPL SI, $0x00010100
+ JB repeat_four_match_repeat_encodeBlockAsm
+ CMPL SI, $0x0100ffff
+ JB repeat_five_match_repeat_encodeBlockAsm
+ LEAL -16842747(SI), SI
+ MOVL $0xfffb001d, (CX)
+ MOVB $0xff, 4(CX)
+ ADDQ $0x05, CX
+ JMP emit_repeat_again_match_repeat_encodeBlockAsm
+
+repeat_five_match_repeat_encodeBlockAsm:
+ LEAL -65536(SI), SI
+ MOVL SI, DI
+ MOVW $0x001d, (CX)
+ MOVW SI, 2(CX)
+ SARL $0x10, DI
+ MOVB DI, 4(CX)
+ ADDQ $0x05, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_four_match_repeat_encodeBlockAsm:
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_three_match_repeat_encodeBlockAsm:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_two_match_repeat_encodeBlockAsm:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_two_offset_match_repeat_encodeBlockAsm:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_as_copy_encodeBlockAsm:
+ // emitCopy
+ CMPL DI, $0x00010000
+ JB two_byte_offset_repeat_as_copy_encodeBlockAsm
+ CMPL SI, $0x40
+ JBE four_bytes_remain_repeat_as_copy_encodeBlockAsm
+ MOVB $0xff, (CX)
+ MOVL DI, 1(CX)
+ LEAL -64(SI), SI
+ ADDQ $0x05, CX
+ CMPL SI, $0x04
+ JB four_bytes_remain_repeat_as_copy_encodeBlockAsm
+
+ // emitRepeat
+emit_repeat_again_repeat_as_copy_encodeBlockAsm_emit_copy:
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_repeat_as_copy_encodeBlockAsm_emit_copy
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy
+
+cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy:
+ CMPL SI, $0x00000104
+ JB repeat_three_repeat_as_copy_encodeBlockAsm_emit_copy
+ CMPL SI, $0x00010100
+ JB repeat_four_repeat_as_copy_encodeBlockAsm_emit_copy
+ CMPL SI, $0x0100ffff
+ JB repeat_five_repeat_as_copy_encodeBlockAsm_emit_copy
+ LEAL -16842747(SI), SI
+ MOVL $0xfffb001d, (CX)
+ MOVB $0xff, 4(CX)
+ ADDQ $0x05, CX
+ JMP emit_repeat_again_repeat_as_copy_encodeBlockAsm_emit_copy
+
+repeat_five_repeat_as_copy_encodeBlockAsm_emit_copy:
+ LEAL -65536(SI), SI
+ MOVL SI, DI
+ MOVW $0x001d, (CX)
+ MOVW SI, 2(CX)
+ SARL $0x10, DI
+ MOVB DI, 4(CX)
+ ADDQ $0x05, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_four_repeat_as_copy_encodeBlockAsm_emit_copy:
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_three_repeat_as_copy_encodeBlockAsm_emit_copy:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_two_repeat_as_copy_encodeBlockAsm_emit_copy:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+four_bytes_remain_repeat_as_copy_encodeBlockAsm:
+ TESTL SI, SI
+ JZ repeat_end_emit_encodeBlockAsm
+ XORL R8, R8
+ LEAL -1(R8)(SI*4), SI
+ MOVB SI, (CX)
+ MOVL DI, 1(CX)
+ ADDQ $0x05, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+two_byte_offset_repeat_as_copy_encodeBlockAsm:
+ CMPL SI, $0x40
+ JBE two_byte_offset_short_repeat_as_copy_encodeBlockAsm
+ CMPL DI, $0x00000800
+ JAE long_offset_short_repeat_as_copy_encodeBlockAsm
+ MOVL $0x00000001, R8
+ LEAL 16(R8), R8
+ MOVB DI, 1(CX)
+ MOVL DI, R9
+ SHRL $0x08, R9
+ SHLL $0x05, R9
+ ORL R9, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, SI
+
+ // emitRepeat
+ LEAL -4(SI), SI
+ JMP cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b
+
+emit_repeat_again_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b:
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b
+
+cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b:
+ CMPL SI, $0x00000104
+ JB repeat_three_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b
+ CMPL SI, $0x00010100
+ JB repeat_four_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b
+ CMPL SI, $0x0100ffff
+ JB repeat_five_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b
+ LEAL -16842747(SI), SI
+ MOVL $0xfffb001d, (CX)
+ MOVB $0xff, 4(CX)
+ ADDQ $0x05, CX
+ JMP emit_repeat_again_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b
+
+repeat_five_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b:
+ LEAL -65536(SI), SI
+ MOVL SI, DI
+ MOVW $0x001d, (CX)
+ MOVW SI, 2(CX)
+ SARL $0x10, DI
+ MOVB DI, 4(CX)
+ ADDQ $0x05, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_four_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b:
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_three_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_two_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy_short_2b:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+long_offset_short_repeat_as_copy_encodeBlockAsm:
+ MOVB $0xee, (CX)
+ MOVW DI, 1(CX)
+ LEAL -60(SI), SI
+ ADDQ $0x03, CX
+
+ // emitRepeat
+emit_repeat_again_repeat_as_copy_encodeBlockAsm_emit_copy_short:
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_repeat_as_copy_encodeBlockAsm_emit_copy_short
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy_short
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy_short
+
+cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy_short:
+ CMPL SI, $0x00000104
+ JB repeat_three_repeat_as_copy_encodeBlockAsm_emit_copy_short
+ CMPL SI, $0x00010100
+ JB repeat_four_repeat_as_copy_encodeBlockAsm_emit_copy_short
+ CMPL SI, $0x0100ffff
+ JB repeat_five_repeat_as_copy_encodeBlockAsm_emit_copy_short
+ LEAL -16842747(SI), SI
+ MOVL $0xfffb001d, (CX)
+ MOVB $0xff, 4(CX)
+ ADDQ $0x05, CX
+ JMP emit_repeat_again_repeat_as_copy_encodeBlockAsm_emit_copy_short
+
+repeat_five_repeat_as_copy_encodeBlockAsm_emit_copy_short:
+ LEAL -65536(SI), SI
+ MOVL SI, DI
+ MOVW $0x001d, (CX)
+ MOVW SI, 2(CX)
+ SARL $0x10, DI
+ MOVB DI, 4(CX)
+ ADDQ $0x05, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_four_repeat_as_copy_encodeBlockAsm_emit_copy_short:
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_three_repeat_as_copy_encodeBlockAsm_emit_copy_short:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_two_repeat_as_copy_encodeBlockAsm_emit_copy_short:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+repeat_two_offset_repeat_as_copy_encodeBlockAsm_emit_copy_short:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+two_byte_offset_short_repeat_as_copy_encodeBlockAsm:
+ MOVL SI, R8
+ SHLL $0x02, R8
+ CMPL SI, $0x0c
+ JAE emit_copy_three_repeat_as_copy_encodeBlockAsm
+ CMPL DI, $0x00000800
+ JAE emit_copy_three_repeat_as_copy_encodeBlockAsm
+ LEAL -15(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm
+
+emit_copy_three_repeat_as_copy_encodeBlockAsm:
+ LEAL -2(R8), R8
+ MOVB R8, (CX)
+ MOVW DI, 1(CX)
+ ADDQ $0x03, CX
+
+repeat_end_emit_encodeBlockAsm:
+ MOVL DX, 12(SP)
+ JMP search_loop_encodeBlockAsm
+
+no_repeat_found_encodeBlockAsm:
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeBlockAsm
+ SHRQ $0x08, DI
+ MOVL (AX)(R10*4), SI
+ LEAL 2(DX), R9
+ CMPL (BX)(R8*1), DI
+ JEQ candidate2_match_encodeBlockAsm
+ MOVL R9, (AX)(R10*4)
+ SHRQ $0x08, DI
+ CMPL (BX)(SI*1), DI
+ JEQ candidate3_match_encodeBlockAsm
+ MOVL 20(SP), DX
+ JMP search_loop_encodeBlockAsm
+
+candidate3_match_encodeBlockAsm:
+ ADDL $0x02, DX
+ JMP candidate_match_encodeBlockAsm
+
+candidate2_match_encodeBlockAsm:
+ MOVL R9, (AX)(R10*4)
+ INCL DX
+ MOVL R8, SI
+
+candidate_match_encodeBlockAsm:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeBlockAsm
+
+match_extend_back_loop_encodeBlockAsm:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeBlockAsm
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeBlockAsm
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeBlockAsm
+ JMP match_extend_back_loop_encodeBlockAsm
+
+match_extend_back_end_encodeBlockAsm:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 5(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeBlockAsm:
+ MOVL DX, DI
+ MOVL 12(SP), R8
+ CMPL R8, DI
+ JEQ emit_literal_done_match_emit_encodeBlockAsm
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(R8*1), DI
+ SUBL R8, R9
+ LEAL -1(R9), R8
+ CMPL R8, $0x3c
+ JB one_byte_match_emit_encodeBlockAsm
+ CMPL R8, $0x00000100
+ JB two_bytes_match_emit_encodeBlockAsm
+ CMPL R8, $0x00010000
+ JB three_bytes_match_emit_encodeBlockAsm
+ CMPL R8, $0x01000000
+ JB four_bytes_match_emit_encodeBlockAsm
+ MOVB $0xfc, (CX)
+ MOVL R8, 1(CX)
+ ADDQ $0x05, CX
+ JMP memmove_long_match_emit_encodeBlockAsm
+
+four_bytes_match_emit_encodeBlockAsm:
+ MOVL R8, R10
+ SHRL $0x10, R10
+ MOVB $0xf8, (CX)
+ MOVW R8, 1(CX)
+ MOVB R10, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_match_emit_encodeBlockAsm
+
+three_bytes_match_emit_encodeBlockAsm:
+ MOVB $0xf4, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeBlockAsm
+
+two_bytes_match_emit_encodeBlockAsm:
+ MOVB $0xf0, (CX)
+ MOVB R8, 1(CX)
+ ADDQ $0x02, CX
+ CMPL R8, $0x40
+ JB memmove_match_emit_encodeBlockAsm
+ JMP memmove_long_match_emit_encodeBlockAsm
+
+one_byte_match_emit_encodeBlockAsm:
+ SHLB $0x02, R8
+ MOVB R8, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeBlockAsm:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeBlockAsm_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeBlockAsm_memmove_move_8:
+ MOVQ (DI), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm
+
+emit_lit_memmove_match_emit_encodeBlockAsm_memmove_move_8through16:
+ MOVQ (DI), R10
+ MOVQ -8(DI)(R9*1), DI
+ MOVQ R10, (CX)
+ MOVQ DI, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm
+
+emit_lit_memmove_match_emit_encodeBlockAsm_memmove_move_17through32:
+ MOVOU (DI), X0
+ MOVOU -16(DI)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm
+
+emit_lit_memmove_match_emit_encodeBlockAsm_memmove_move_33through64:
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeBlockAsm:
+ MOVQ R8, CX
+ JMP emit_literal_done_match_emit_encodeBlockAsm
+
+memmove_long_match_emit_encodeBlockAsm:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveLong
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVQ R9, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_match_emit_encodeBlockAsmlarge_forward_sse_loop_32
+ LEAQ -32(DI)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_match_emit_encodeBlockAsmlarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_match_emit_encodeBlockAsmlarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeBlockAsmlarge_forward_sse_loop_32:
+ MOVOU -32(DI)(R12*1), X4
+ MOVOU -16(DI)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R9, R12
+ JAE emit_lit_memmove_long_match_emit_encodeBlockAsmlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ R8, CX
+
+emit_literal_done_match_emit_encodeBlockAsm:
+match_nolit_loop_encodeBlockAsm:
+ MOVL DX, DI
+ SUBL SI, DI
+ MOVL DI, 16(SP)
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), DI
+ SUBL DX, DI
+ LEAQ (BX)(DX*1), R8
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R10, R10
+
+matchlen_loopback_16_match_nolit_encodeBlockAsm:
+ CMPL DI, $0x10
+ JB matchlen_match8_match_nolit_encodeBlockAsm
+ MOVQ (R8)(R10*1), R9
+ MOVQ 8(R8)(R10*1), R11
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeBlockAsm
+ XORQ 8(SI)(R10*1), R11
+ JNZ matchlen_bsf_16match_nolit_encodeBlockAsm
+ LEAL -16(DI), DI
+ LEAL 16(R10), R10
+ JMP matchlen_loopback_16_match_nolit_encodeBlockAsm
+
+matchlen_bsf_16match_nolit_encodeBlockAsm:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL 8(R10)(R11*1), R10
+ JMP match_nolit_end_encodeBlockAsm
+
+matchlen_match8_match_nolit_encodeBlockAsm:
+ CMPL DI, $0x08
+ JB matchlen_match4_match_nolit_encodeBlockAsm
+ MOVQ (R8)(R10*1), R9
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeBlockAsm
+ LEAL -8(DI), DI
+ LEAL 8(R10), R10
+ JMP matchlen_match4_match_nolit_encodeBlockAsm
+
+matchlen_bsf_8_match_nolit_encodeBlockAsm:
+#ifdef GOAMD64_v3
+ TZCNTQ R9, R9
+
+#else
+ BSFQ R9, R9
+
+#endif
+ SARQ $0x03, R9
+ LEAL (R10)(R9*1), R10
+ JMP match_nolit_end_encodeBlockAsm
+
+matchlen_match4_match_nolit_encodeBlockAsm:
+ CMPL DI, $0x04
+ JB matchlen_match2_match_nolit_encodeBlockAsm
+ MOVL (R8)(R10*1), R9
+ CMPL (SI)(R10*1), R9
+ JNE matchlen_match2_match_nolit_encodeBlockAsm
+ LEAL -4(DI), DI
+ LEAL 4(R10), R10
+
+matchlen_match2_match_nolit_encodeBlockAsm:
+ CMPL DI, $0x01
+ JE matchlen_match1_match_nolit_encodeBlockAsm
+ JB match_nolit_end_encodeBlockAsm
+ MOVW (R8)(R10*1), R9
+ CMPW (SI)(R10*1), R9
+ JNE matchlen_match1_match_nolit_encodeBlockAsm
+ LEAL 2(R10), R10
+ SUBL $0x02, DI
+ JZ match_nolit_end_encodeBlockAsm
+
+matchlen_match1_match_nolit_encodeBlockAsm:
+ MOVB (R8)(R10*1), R9
+ CMPB (SI)(R10*1), R9
+ JNE match_nolit_end_encodeBlockAsm
+ LEAL 1(R10), R10
+
+match_nolit_end_encodeBlockAsm:
+ ADDL R10, DX
+ MOVL 16(SP), SI
+ ADDL $0x04, R10
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL SI, $0x00010000
+ JB two_byte_offset_match_nolit_encodeBlockAsm
+ CMPL R10, $0x40
+ JBE four_bytes_remain_match_nolit_encodeBlockAsm
+ MOVB $0xff, (CX)
+ MOVL SI, 1(CX)
+ LEAL -64(R10), R10
+ ADDQ $0x05, CX
+ CMPL R10, $0x04
+ JB four_bytes_remain_match_nolit_encodeBlockAsm
+
+ // emitRepeat
+emit_repeat_again_match_nolit_encodeBlockAsm_emit_copy:
+ MOVL R10, DI
+ LEAL -4(R10), R10
+ CMPL DI, $0x08
+ JBE repeat_two_match_nolit_encodeBlockAsm_emit_copy
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy
+ CMPL SI, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy
+
+cant_repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy:
+ CMPL R10, $0x00000104
+ JB repeat_three_match_nolit_encodeBlockAsm_emit_copy
+ CMPL R10, $0x00010100
+ JB repeat_four_match_nolit_encodeBlockAsm_emit_copy
+ CMPL R10, $0x0100ffff
+ JB repeat_five_match_nolit_encodeBlockAsm_emit_copy
+ LEAL -16842747(R10), R10
+ MOVL $0xfffb001d, (CX)
+ MOVB $0xff, 4(CX)
+ ADDQ $0x05, CX
+ JMP emit_repeat_again_match_nolit_encodeBlockAsm_emit_copy
+
+repeat_five_match_nolit_encodeBlockAsm_emit_copy:
+ LEAL -65536(R10), R10
+ MOVL R10, SI
+ MOVW $0x001d, (CX)
+ MOVW R10, 2(CX)
+ SARL $0x10, SI
+ MOVB SI, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+repeat_four_match_nolit_encodeBlockAsm_emit_copy:
+ LEAL -256(R10), R10
+ MOVW $0x0019, (CX)
+ MOVW R10, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+repeat_three_match_nolit_encodeBlockAsm_emit_copy:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (CX)
+ MOVB R10, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+repeat_two_match_nolit_encodeBlockAsm_emit_copy:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy:
+ XORQ DI, DI
+ LEAL 1(DI)(R10*4), R10
+ MOVB SI, 1(CX)
+ SARL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, R10
+ MOVB R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+four_bytes_remain_match_nolit_encodeBlockAsm:
+ TESTL R10, R10
+ JZ match_nolit_emitcopy_end_encodeBlockAsm
+ XORL DI, DI
+ LEAL -1(DI)(R10*4), R10
+ MOVB R10, (CX)
+ MOVL SI, 1(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+two_byte_offset_match_nolit_encodeBlockAsm:
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeBlockAsm
+ CMPL SI, $0x00000800
+ JAE long_offset_short_match_nolit_encodeBlockAsm
+ MOVL $0x00000001, DI
+ LEAL 16(DI), DI
+ MOVB SI, 1(CX)
+ MOVL SI, R8
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, R10
+
+ // emitRepeat
+ LEAL -4(R10), R10
+ JMP cant_repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy_short_2b
+
+emit_repeat_again_match_nolit_encodeBlockAsm_emit_copy_short_2b:
+ MOVL R10, DI
+ LEAL -4(R10), R10
+ CMPL DI, $0x08
+ JBE repeat_two_match_nolit_encodeBlockAsm_emit_copy_short_2b
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy_short_2b
+ CMPL SI, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy_short_2b
+
+cant_repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy_short_2b:
+ CMPL R10, $0x00000104
+ JB repeat_three_match_nolit_encodeBlockAsm_emit_copy_short_2b
+ CMPL R10, $0x00010100
+ JB repeat_four_match_nolit_encodeBlockAsm_emit_copy_short_2b
+ CMPL R10, $0x0100ffff
+ JB repeat_five_match_nolit_encodeBlockAsm_emit_copy_short_2b
+ LEAL -16842747(R10), R10
+ MOVL $0xfffb001d, (CX)
+ MOVB $0xff, 4(CX)
+ ADDQ $0x05, CX
+ JMP emit_repeat_again_match_nolit_encodeBlockAsm_emit_copy_short_2b
+
+repeat_five_match_nolit_encodeBlockAsm_emit_copy_short_2b:
+ LEAL -65536(R10), R10
+ MOVL R10, SI
+ MOVW $0x001d, (CX)
+ MOVW R10, 2(CX)
+ SARL $0x10, SI
+ MOVB SI, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+repeat_four_match_nolit_encodeBlockAsm_emit_copy_short_2b:
+ LEAL -256(R10), R10
+ MOVW $0x0019, (CX)
+ MOVW R10, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+repeat_three_match_nolit_encodeBlockAsm_emit_copy_short_2b:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (CX)
+ MOVB R10, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+repeat_two_match_nolit_encodeBlockAsm_emit_copy_short_2b:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy_short_2b:
+ XORQ DI, DI
+ LEAL 1(DI)(R10*4), R10
+ MOVB SI, 1(CX)
+ SARL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, R10
+ MOVB R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+long_offset_short_match_nolit_encodeBlockAsm:
+ MOVB $0xee, (CX)
+ MOVW SI, 1(CX)
+ LEAL -60(R10), R10
+ ADDQ $0x03, CX
+
+ // emitRepeat
+emit_repeat_again_match_nolit_encodeBlockAsm_emit_copy_short:
+ MOVL R10, DI
+ LEAL -4(R10), R10
+ CMPL DI, $0x08
+ JBE repeat_two_match_nolit_encodeBlockAsm_emit_copy_short
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy_short
+ CMPL SI, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy_short
+
+cant_repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy_short:
+ CMPL R10, $0x00000104
+ JB repeat_three_match_nolit_encodeBlockAsm_emit_copy_short
+ CMPL R10, $0x00010100
+ JB repeat_four_match_nolit_encodeBlockAsm_emit_copy_short
+ CMPL R10, $0x0100ffff
+ JB repeat_five_match_nolit_encodeBlockAsm_emit_copy_short
+ LEAL -16842747(R10), R10
+ MOVL $0xfffb001d, (CX)
+ MOVB $0xff, 4(CX)
+ ADDQ $0x05, CX
+ JMP emit_repeat_again_match_nolit_encodeBlockAsm_emit_copy_short
+
+repeat_five_match_nolit_encodeBlockAsm_emit_copy_short:
+ LEAL -65536(R10), R10
+ MOVL R10, SI
+ MOVW $0x001d, (CX)
+ MOVW R10, 2(CX)
+ SARL $0x10, SI
+ MOVB SI, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+repeat_four_match_nolit_encodeBlockAsm_emit_copy_short:
+ LEAL -256(R10), R10
+ MOVW $0x0019, (CX)
+ MOVW R10, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+repeat_three_match_nolit_encodeBlockAsm_emit_copy_short:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (CX)
+ MOVB R10, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+repeat_two_match_nolit_encodeBlockAsm_emit_copy_short:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+repeat_two_offset_match_nolit_encodeBlockAsm_emit_copy_short:
+ XORQ DI, DI
+ LEAL 1(DI)(R10*4), R10
+ MOVB SI, 1(CX)
+ SARL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, R10
+ MOVB R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+two_byte_offset_short_match_nolit_encodeBlockAsm:
+ MOVL R10, DI
+ SHLL $0x02, DI
+ CMPL R10, $0x0c
+ JAE emit_copy_three_match_nolit_encodeBlockAsm
+ CMPL SI, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeBlockAsm
+ LEAL -15(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm
+
+emit_copy_three_match_nolit_encodeBlockAsm:
+ LEAL -2(DI), DI
+ MOVB DI, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeBlockAsm:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeBlockAsm
+ MOVQ -2(BX)(DX*1), DI
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeBlockAsm:
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ DI, R8
+ SHRQ $0x10, DI
+ MOVQ DI, SI
+ SHLQ $0x10, R8
+ IMULQ R9, R8
+ SHRQ $0x32, R8
+ SHLQ $0x10, SI
+ IMULQ R9, SI
+ SHRQ $0x32, SI
+ LEAL -2(DX), R9
+ LEAQ (AX)(SI*4), R10
+ MOVL (R10), SI
+ MOVL R9, (AX)(R8*4)
+ MOVL DX, (R10)
+ CMPL (BX)(SI*1), DI
+ JEQ match_nolit_loop_encodeBlockAsm
+ INCL DX
+ JMP search_loop_encodeBlockAsm
+
+emit_remainder_encodeBlockAsm:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 5(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeBlockAsm:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeBlockAsm
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeBlockAsm
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeBlockAsm
+ CMPL DX, $0x00010000
+ JB three_bytes_emit_remainder_encodeBlockAsm
+ CMPL DX, $0x01000000
+ JB four_bytes_emit_remainder_encodeBlockAsm
+ MOVB $0xfc, (CX)
+ MOVL DX, 1(CX)
+ ADDQ $0x05, CX
+ JMP memmove_long_emit_remainder_encodeBlockAsm
+
+four_bytes_emit_remainder_encodeBlockAsm:
+ MOVL DX, BX
+ SHRL $0x10, BX
+ MOVB $0xf8, (CX)
+ MOVW DX, 1(CX)
+ MOVB BL, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_emit_remainder_encodeBlockAsm
+
+three_bytes_emit_remainder_encodeBlockAsm:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeBlockAsm
+
+two_bytes_emit_remainder_encodeBlockAsm:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeBlockAsm
+ JMP memmove_long_emit_remainder_encodeBlockAsm
+
+one_byte_emit_remainder_encodeBlockAsm:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeBlockAsm:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeBlockAsm_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeBlockAsm_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeBlockAsm_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeBlockAsm_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeBlockAsm_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeBlockAsm_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeBlockAsm:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeBlockAsm
+
+memmove_long_emit_remainder_encodeBlockAsm:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeBlockAsmlarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeBlockAsmlarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeBlockAsmlarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeBlockAsmlarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeBlockAsmlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeBlockAsm:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeBlockAsm4MB(dst []byte, src []byte, tmp *[65536]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeBlockAsm4MB(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000200, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeBlockAsm4MB:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeBlockAsm4MB
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL DX, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeBlockAsm4MB:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x06, SI
+ LEAL 4(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeBlockAsm4MB
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHRQ $0x08, R11
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x32, R10
+ SHLQ $0x10, R11
+ IMULQ R9, R11
+ SHRQ $0x32, R11
+ MOVL (AX)(R10*4), SI
+ MOVL (AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ LEAL 1(DX), R10
+ MOVL R10, (AX)(R11*4)
+ MOVQ DI, R10
+ SHRQ $0x10, R10
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x32, R10
+ MOVL DX, R9
+ SUBL 16(SP), R9
+ MOVL 1(BX)(R9*1), R11
+ MOVQ DI, R9
+ SHRQ $0x08, R9
+ CMPL R9, R11
+ JNE no_repeat_found_encodeBlockAsm4MB
+ LEAL 1(DX), DI
+ MOVL 12(SP), R8
+ MOVL DI, SI
+ SUBL 16(SP), SI
+ JZ repeat_extend_back_end_encodeBlockAsm4MB
+
+repeat_extend_back_loop_encodeBlockAsm4MB:
+ CMPL DI, R8
+ JBE repeat_extend_back_end_encodeBlockAsm4MB
+ MOVB -1(BX)(SI*1), R9
+ MOVB -1(BX)(DI*1), R10
+ CMPB R9, R10
+ JNE repeat_extend_back_end_encodeBlockAsm4MB
+ LEAL -1(DI), DI
+ DECL SI
+ JNZ repeat_extend_back_loop_encodeBlockAsm4MB
+
+repeat_extend_back_end_encodeBlockAsm4MB:
+ MOVL DI, SI
+ SUBL 12(SP), SI
+ LEAQ 4(CX)(SI*1), SI
+ CMPQ SI, (SP)
+ JB repeat_dst_size_check_encodeBlockAsm4MB
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+repeat_dst_size_check_encodeBlockAsm4MB:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_repeat_emit_encodeBlockAsm4MB
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_repeat_emit_encodeBlockAsm4MB
+ CMPL SI, $0x00000100
+ JB two_bytes_repeat_emit_encodeBlockAsm4MB
+ CMPL SI, $0x00010000
+ JB three_bytes_repeat_emit_encodeBlockAsm4MB
+ MOVL SI, R11
+ SHRL $0x10, R11
+ MOVB $0xf8, (CX)
+ MOVW SI, 1(CX)
+ MOVB R11, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_repeat_emit_encodeBlockAsm4MB
+
+three_bytes_repeat_emit_encodeBlockAsm4MB:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_repeat_emit_encodeBlockAsm4MB
+
+two_bytes_repeat_emit_encodeBlockAsm4MB:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_repeat_emit_encodeBlockAsm4MB
+ JMP memmove_long_repeat_emit_encodeBlockAsm4MB
+
+one_byte_repeat_emit_encodeBlockAsm4MB:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_repeat_emit_encodeBlockAsm4MB:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm4MB_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm4MB_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm4MB_memmove_move_17through32
+ JMP emit_lit_memmove_repeat_emit_encodeBlockAsm4MB_memmove_move_33through64
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm4MB_memmove_move_8:
+ MOVQ (R10), R11
+ MOVQ R11, (CX)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm4MB
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm4MB_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm4MB
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm4MB_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm4MB
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm4MB_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_repeat_emit_encodeBlockAsm4MB:
+ MOVQ SI, CX
+ JMP emit_literal_done_repeat_emit_encodeBlockAsm4MB
+
+memmove_long_repeat_emit_encodeBlockAsm4MB:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R12
+ SHRQ $0x05, R12
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R13
+ SUBQ R11, R13
+ DECQ R12
+ JA emit_lit_memmove_long_repeat_emit_encodeBlockAsm4MBlarge_forward_sse_loop_32
+ LEAQ -32(R10)(R13*1), R11
+ LEAQ -32(CX)(R13*1), R14
+
+emit_lit_memmove_long_repeat_emit_encodeBlockAsm4MBlarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R14)
+ MOVOA X5, 16(R14)
+ ADDQ $0x20, R14
+ ADDQ $0x20, R11
+ ADDQ $0x20, R13
+ DECQ R12
+ JNA emit_lit_memmove_long_repeat_emit_encodeBlockAsm4MBlarge_big_loop_back
+
+emit_lit_memmove_long_repeat_emit_encodeBlockAsm4MBlarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R13*1), X4
+ MOVOU -16(R10)(R13*1), X5
+ MOVOA X4, -32(CX)(R13*1)
+ MOVOA X5, -16(CX)(R13*1)
+ ADDQ $0x20, R13
+ CMPQ R9, R13
+ JAE emit_lit_memmove_long_repeat_emit_encodeBlockAsm4MBlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_repeat_emit_encodeBlockAsm4MB:
+ ADDL $0x05, DX
+ MOVL DX, SI
+ SUBL 16(SP), SI
+ MOVQ src_len+32(FP), R9
+ SUBL DX, R9
+ LEAQ (BX)(DX*1), R10
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_repeat_extend_encodeBlockAsm4MB:
+ CMPL R9, $0x10
+ JB matchlen_match8_repeat_extend_encodeBlockAsm4MB
+ MOVQ (R10)(R12*1), R11
+ MOVQ 8(R10)(R12*1), R13
+ XORQ (SI)(R12*1), R11
+ JNZ matchlen_bsf_8_repeat_extend_encodeBlockAsm4MB
+ XORQ 8(SI)(R12*1), R13
+ JNZ matchlen_bsf_16repeat_extend_encodeBlockAsm4MB
+ LEAL -16(R9), R9
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_repeat_extend_encodeBlockAsm4MB
+
+matchlen_bsf_16repeat_extend_encodeBlockAsm4MB:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP repeat_extend_forward_end_encodeBlockAsm4MB
+
+matchlen_match8_repeat_extend_encodeBlockAsm4MB:
+ CMPL R9, $0x08
+ JB matchlen_match4_repeat_extend_encodeBlockAsm4MB
+ MOVQ (R10)(R12*1), R11
+ XORQ (SI)(R12*1), R11
+ JNZ matchlen_bsf_8_repeat_extend_encodeBlockAsm4MB
+ LEAL -8(R9), R9
+ LEAL 8(R12), R12
+ JMP matchlen_match4_repeat_extend_encodeBlockAsm4MB
+
+matchlen_bsf_8_repeat_extend_encodeBlockAsm4MB:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP repeat_extend_forward_end_encodeBlockAsm4MB
+
+matchlen_match4_repeat_extend_encodeBlockAsm4MB:
+ CMPL R9, $0x04
+ JB matchlen_match2_repeat_extend_encodeBlockAsm4MB
+ MOVL (R10)(R12*1), R11
+ CMPL (SI)(R12*1), R11
+ JNE matchlen_match2_repeat_extend_encodeBlockAsm4MB
+ LEAL -4(R9), R9
+ LEAL 4(R12), R12
+
+matchlen_match2_repeat_extend_encodeBlockAsm4MB:
+ CMPL R9, $0x01
+ JE matchlen_match1_repeat_extend_encodeBlockAsm4MB
+ JB repeat_extend_forward_end_encodeBlockAsm4MB
+ MOVW (R10)(R12*1), R11
+ CMPW (SI)(R12*1), R11
+ JNE matchlen_match1_repeat_extend_encodeBlockAsm4MB
+ LEAL 2(R12), R12
+ SUBL $0x02, R9
+ JZ repeat_extend_forward_end_encodeBlockAsm4MB
+
+matchlen_match1_repeat_extend_encodeBlockAsm4MB:
+ MOVB (R10)(R12*1), R11
+ CMPB (SI)(R12*1), R11
+ JNE repeat_extend_forward_end_encodeBlockAsm4MB
+ LEAL 1(R12), R12
+
+repeat_extend_forward_end_encodeBlockAsm4MB:
+ ADDL R12, DX
+ MOVL DX, SI
+ SUBL DI, SI
+ MOVL 16(SP), DI
+ TESTL R8, R8
+ JZ repeat_as_copy_encodeBlockAsm4MB
+
+ // emitRepeat
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_match_repeat_encodeBlockAsm4MB
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_match_repeat_encodeBlockAsm4MB
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_match_repeat_encodeBlockAsm4MB
+
+cant_repeat_two_offset_match_repeat_encodeBlockAsm4MB:
+ CMPL SI, $0x00000104
+ JB repeat_three_match_repeat_encodeBlockAsm4MB
+ CMPL SI, $0x00010100
+ JB repeat_four_match_repeat_encodeBlockAsm4MB
+ LEAL -65536(SI), SI
+ MOVL SI, DI
+ MOVW $0x001d, (CX)
+ MOVW SI, 2(CX)
+ SARL $0x10, DI
+ MOVB DI, 4(CX)
+ ADDQ $0x05, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_four_match_repeat_encodeBlockAsm4MB:
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_three_match_repeat_encodeBlockAsm4MB:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_two_match_repeat_encodeBlockAsm4MB:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_two_offset_match_repeat_encodeBlockAsm4MB:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_as_copy_encodeBlockAsm4MB:
+ // emitCopy
+ CMPL DI, $0x00010000
+ JB two_byte_offset_repeat_as_copy_encodeBlockAsm4MB
+ CMPL SI, $0x40
+ JBE four_bytes_remain_repeat_as_copy_encodeBlockAsm4MB
+ MOVB $0xff, (CX)
+ MOVL DI, 1(CX)
+ LEAL -64(SI), SI
+ ADDQ $0x05, CX
+ CMPL SI, $0x04
+ JB four_bytes_remain_repeat_as_copy_encodeBlockAsm4MB
+
+ // emitRepeat
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_repeat_as_copy_encodeBlockAsm4MB_emit_copy
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy
+
+cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy:
+ CMPL SI, $0x00000104
+ JB repeat_three_repeat_as_copy_encodeBlockAsm4MB_emit_copy
+ CMPL SI, $0x00010100
+ JB repeat_four_repeat_as_copy_encodeBlockAsm4MB_emit_copy
+ LEAL -65536(SI), SI
+ MOVL SI, DI
+ MOVW $0x001d, (CX)
+ MOVW SI, 2(CX)
+ SARL $0x10, DI
+ MOVB DI, 4(CX)
+ ADDQ $0x05, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_four_repeat_as_copy_encodeBlockAsm4MB_emit_copy:
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_three_repeat_as_copy_encodeBlockAsm4MB_emit_copy:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_two_repeat_as_copy_encodeBlockAsm4MB_emit_copy:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+four_bytes_remain_repeat_as_copy_encodeBlockAsm4MB:
+ TESTL SI, SI
+ JZ repeat_end_emit_encodeBlockAsm4MB
+ XORL R8, R8
+ LEAL -1(R8)(SI*4), SI
+ MOVB SI, (CX)
+ MOVL DI, 1(CX)
+ ADDQ $0x05, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+two_byte_offset_repeat_as_copy_encodeBlockAsm4MB:
+ CMPL SI, $0x40
+ JBE two_byte_offset_short_repeat_as_copy_encodeBlockAsm4MB
+ CMPL DI, $0x00000800
+ JAE long_offset_short_repeat_as_copy_encodeBlockAsm4MB
+ MOVL $0x00000001, R8
+ LEAL 16(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, SI
+
+ // emitRepeat
+ LEAL -4(SI), SI
+ JMP cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short_2b
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short_2b
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short_2b
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short_2b
+
+cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short_2b:
+ CMPL SI, $0x00000104
+ JB repeat_three_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short_2b
+ CMPL SI, $0x00010100
+ JB repeat_four_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short_2b
+ LEAL -65536(SI), SI
+ MOVL SI, DI
+ MOVW $0x001d, (CX)
+ MOVW SI, 2(CX)
+ SARL $0x10, DI
+ MOVB DI, 4(CX)
+ ADDQ $0x05, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_four_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short_2b:
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_three_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short_2b:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_two_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short_2b:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short_2b:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+long_offset_short_repeat_as_copy_encodeBlockAsm4MB:
+ MOVB $0xee, (CX)
+ MOVW DI, 1(CX)
+ LEAL -60(SI), SI
+ ADDQ $0x03, CX
+
+ // emitRepeat
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short
+
+cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short:
+ CMPL SI, $0x00000104
+ JB repeat_three_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short
+ CMPL SI, $0x00010100
+ JB repeat_four_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short
+ LEAL -65536(SI), SI
+ MOVL SI, DI
+ MOVW $0x001d, (CX)
+ MOVW SI, 2(CX)
+ SARL $0x10, DI
+ MOVB DI, 4(CX)
+ ADDQ $0x05, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_four_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short:
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_three_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_two_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+repeat_two_offset_repeat_as_copy_encodeBlockAsm4MB_emit_copy_short:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+two_byte_offset_short_repeat_as_copy_encodeBlockAsm4MB:
+ MOVL SI, R8
+ SHLL $0x02, R8
+ CMPL SI, $0x0c
+ JAE emit_copy_three_repeat_as_copy_encodeBlockAsm4MB
+ CMPL DI, $0x00000800
+ JAE emit_copy_three_repeat_as_copy_encodeBlockAsm4MB
+ LEAL -15(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm4MB
+
+emit_copy_three_repeat_as_copy_encodeBlockAsm4MB:
+ LEAL -2(R8), R8
+ MOVB R8, (CX)
+ MOVW DI, 1(CX)
+ ADDQ $0x03, CX
+
+repeat_end_emit_encodeBlockAsm4MB:
+ MOVL DX, 12(SP)
+ JMP search_loop_encodeBlockAsm4MB
+
+no_repeat_found_encodeBlockAsm4MB:
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeBlockAsm4MB
+ SHRQ $0x08, DI
+ MOVL (AX)(R10*4), SI
+ LEAL 2(DX), R9
+ CMPL (BX)(R8*1), DI
+ JEQ candidate2_match_encodeBlockAsm4MB
+ MOVL R9, (AX)(R10*4)
+ SHRQ $0x08, DI
+ CMPL (BX)(SI*1), DI
+ JEQ candidate3_match_encodeBlockAsm4MB
+ MOVL 20(SP), DX
+ JMP search_loop_encodeBlockAsm4MB
+
+candidate3_match_encodeBlockAsm4MB:
+ ADDL $0x02, DX
+ JMP candidate_match_encodeBlockAsm4MB
+
+candidate2_match_encodeBlockAsm4MB:
+ MOVL R9, (AX)(R10*4)
+ INCL DX
+ MOVL R8, SI
+
+candidate_match_encodeBlockAsm4MB:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeBlockAsm4MB
+
+match_extend_back_loop_encodeBlockAsm4MB:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeBlockAsm4MB
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeBlockAsm4MB
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeBlockAsm4MB
+ JMP match_extend_back_loop_encodeBlockAsm4MB
+
+match_extend_back_end_encodeBlockAsm4MB:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 4(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeBlockAsm4MB
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeBlockAsm4MB:
+ MOVL DX, DI
+ MOVL 12(SP), R8
+ CMPL R8, DI
+ JEQ emit_literal_done_match_emit_encodeBlockAsm4MB
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(R8*1), DI
+ SUBL R8, R9
+ LEAL -1(R9), R8
+ CMPL R8, $0x3c
+ JB one_byte_match_emit_encodeBlockAsm4MB
+ CMPL R8, $0x00000100
+ JB two_bytes_match_emit_encodeBlockAsm4MB
+ CMPL R8, $0x00010000
+ JB three_bytes_match_emit_encodeBlockAsm4MB
+ MOVL R8, R10
+ SHRL $0x10, R10
+ MOVB $0xf8, (CX)
+ MOVW R8, 1(CX)
+ MOVB R10, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_match_emit_encodeBlockAsm4MB
+
+three_bytes_match_emit_encodeBlockAsm4MB:
+ MOVB $0xf4, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeBlockAsm4MB
+
+two_bytes_match_emit_encodeBlockAsm4MB:
+ MOVB $0xf0, (CX)
+ MOVB R8, 1(CX)
+ ADDQ $0x02, CX
+ CMPL R8, $0x40
+ JB memmove_match_emit_encodeBlockAsm4MB
+ JMP memmove_long_match_emit_encodeBlockAsm4MB
+
+one_byte_match_emit_encodeBlockAsm4MB:
+ SHLB $0x02, R8
+ MOVB R8, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeBlockAsm4MB:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm4MB_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm4MB_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm4MB_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeBlockAsm4MB_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeBlockAsm4MB_memmove_move_8:
+ MOVQ (DI), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm4MB
+
+emit_lit_memmove_match_emit_encodeBlockAsm4MB_memmove_move_8through16:
+ MOVQ (DI), R10
+ MOVQ -8(DI)(R9*1), DI
+ MOVQ R10, (CX)
+ MOVQ DI, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm4MB
+
+emit_lit_memmove_match_emit_encodeBlockAsm4MB_memmove_move_17through32:
+ MOVOU (DI), X0
+ MOVOU -16(DI)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm4MB
+
+emit_lit_memmove_match_emit_encodeBlockAsm4MB_memmove_move_33through64:
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeBlockAsm4MB:
+ MOVQ R8, CX
+ JMP emit_literal_done_match_emit_encodeBlockAsm4MB
+
+memmove_long_match_emit_encodeBlockAsm4MB:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveLong
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVQ R9, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_match_emit_encodeBlockAsm4MBlarge_forward_sse_loop_32
+ LEAQ -32(DI)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_match_emit_encodeBlockAsm4MBlarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_match_emit_encodeBlockAsm4MBlarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeBlockAsm4MBlarge_forward_sse_loop_32:
+ MOVOU -32(DI)(R12*1), X4
+ MOVOU -16(DI)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R9, R12
+ JAE emit_lit_memmove_long_match_emit_encodeBlockAsm4MBlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ R8, CX
+
+emit_literal_done_match_emit_encodeBlockAsm4MB:
+match_nolit_loop_encodeBlockAsm4MB:
+ MOVL DX, DI
+ SUBL SI, DI
+ MOVL DI, 16(SP)
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), DI
+ SUBL DX, DI
+ LEAQ (BX)(DX*1), R8
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R10, R10
+
+matchlen_loopback_16_match_nolit_encodeBlockAsm4MB:
+ CMPL DI, $0x10
+ JB matchlen_match8_match_nolit_encodeBlockAsm4MB
+ MOVQ (R8)(R10*1), R9
+ MOVQ 8(R8)(R10*1), R11
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeBlockAsm4MB
+ XORQ 8(SI)(R10*1), R11
+ JNZ matchlen_bsf_16match_nolit_encodeBlockAsm4MB
+ LEAL -16(DI), DI
+ LEAL 16(R10), R10
+ JMP matchlen_loopback_16_match_nolit_encodeBlockAsm4MB
+
+matchlen_bsf_16match_nolit_encodeBlockAsm4MB:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL 8(R10)(R11*1), R10
+ JMP match_nolit_end_encodeBlockAsm4MB
+
+matchlen_match8_match_nolit_encodeBlockAsm4MB:
+ CMPL DI, $0x08
+ JB matchlen_match4_match_nolit_encodeBlockAsm4MB
+ MOVQ (R8)(R10*1), R9
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeBlockAsm4MB
+ LEAL -8(DI), DI
+ LEAL 8(R10), R10
+ JMP matchlen_match4_match_nolit_encodeBlockAsm4MB
+
+matchlen_bsf_8_match_nolit_encodeBlockAsm4MB:
+#ifdef GOAMD64_v3
+ TZCNTQ R9, R9
+
+#else
+ BSFQ R9, R9
+
+#endif
+ SARQ $0x03, R9
+ LEAL (R10)(R9*1), R10
+ JMP match_nolit_end_encodeBlockAsm4MB
+
+matchlen_match4_match_nolit_encodeBlockAsm4MB:
+ CMPL DI, $0x04
+ JB matchlen_match2_match_nolit_encodeBlockAsm4MB
+ MOVL (R8)(R10*1), R9
+ CMPL (SI)(R10*1), R9
+ JNE matchlen_match2_match_nolit_encodeBlockAsm4MB
+ LEAL -4(DI), DI
+ LEAL 4(R10), R10
+
+matchlen_match2_match_nolit_encodeBlockAsm4MB:
+ CMPL DI, $0x01
+ JE matchlen_match1_match_nolit_encodeBlockAsm4MB
+ JB match_nolit_end_encodeBlockAsm4MB
+ MOVW (R8)(R10*1), R9
+ CMPW (SI)(R10*1), R9
+ JNE matchlen_match1_match_nolit_encodeBlockAsm4MB
+ LEAL 2(R10), R10
+ SUBL $0x02, DI
+ JZ match_nolit_end_encodeBlockAsm4MB
+
+matchlen_match1_match_nolit_encodeBlockAsm4MB:
+ MOVB (R8)(R10*1), R9
+ CMPB (SI)(R10*1), R9
+ JNE match_nolit_end_encodeBlockAsm4MB
+ LEAL 1(R10), R10
+
+match_nolit_end_encodeBlockAsm4MB:
+ ADDL R10, DX
+ MOVL 16(SP), SI
+ ADDL $0x04, R10
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL SI, $0x00010000
+ JB two_byte_offset_match_nolit_encodeBlockAsm4MB
+ CMPL R10, $0x40
+ JBE four_bytes_remain_match_nolit_encodeBlockAsm4MB
+ MOVB $0xff, (CX)
+ MOVL SI, 1(CX)
+ LEAL -64(R10), R10
+ ADDQ $0x05, CX
+ CMPL R10, $0x04
+ JB four_bytes_remain_match_nolit_encodeBlockAsm4MB
+
+ // emitRepeat
+ MOVL R10, DI
+ LEAL -4(R10), R10
+ CMPL DI, $0x08
+ JBE repeat_two_match_nolit_encodeBlockAsm4MB_emit_copy
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy
+ CMPL SI, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy
+
+cant_repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy:
+ CMPL R10, $0x00000104
+ JB repeat_three_match_nolit_encodeBlockAsm4MB_emit_copy
+ CMPL R10, $0x00010100
+ JB repeat_four_match_nolit_encodeBlockAsm4MB_emit_copy
+ LEAL -65536(R10), R10
+ MOVL R10, SI
+ MOVW $0x001d, (CX)
+ MOVW R10, 2(CX)
+ SARL $0x10, SI
+ MOVB SI, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+repeat_four_match_nolit_encodeBlockAsm4MB_emit_copy:
+ LEAL -256(R10), R10
+ MOVW $0x0019, (CX)
+ MOVW R10, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+repeat_three_match_nolit_encodeBlockAsm4MB_emit_copy:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (CX)
+ MOVB R10, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+repeat_two_match_nolit_encodeBlockAsm4MB_emit_copy:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy:
+ XORQ DI, DI
+ LEAL 1(DI)(R10*4), R10
+ MOVB SI, 1(CX)
+ SARL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, R10
+ MOVB R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+four_bytes_remain_match_nolit_encodeBlockAsm4MB:
+ TESTL R10, R10
+ JZ match_nolit_emitcopy_end_encodeBlockAsm4MB
+ XORL DI, DI
+ LEAL -1(DI)(R10*4), R10
+ MOVB R10, (CX)
+ MOVL SI, 1(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+two_byte_offset_match_nolit_encodeBlockAsm4MB:
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeBlockAsm4MB
+ CMPL SI, $0x00000800
+ JAE long_offset_short_match_nolit_encodeBlockAsm4MB
+ MOVL $0x00000001, DI
+ LEAL 16(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, R10
+
+ // emitRepeat
+ LEAL -4(R10), R10
+ JMP cant_repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy_short_2b
+ MOVL R10, DI
+ LEAL -4(R10), R10
+ CMPL DI, $0x08
+ JBE repeat_two_match_nolit_encodeBlockAsm4MB_emit_copy_short_2b
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy_short_2b
+ CMPL SI, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy_short_2b
+
+cant_repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy_short_2b:
+ CMPL R10, $0x00000104
+ JB repeat_three_match_nolit_encodeBlockAsm4MB_emit_copy_short_2b
+ CMPL R10, $0x00010100
+ JB repeat_four_match_nolit_encodeBlockAsm4MB_emit_copy_short_2b
+ LEAL -65536(R10), R10
+ MOVL R10, SI
+ MOVW $0x001d, (CX)
+ MOVW R10, 2(CX)
+ SARL $0x10, SI
+ MOVB SI, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+repeat_four_match_nolit_encodeBlockAsm4MB_emit_copy_short_2b:
+ LEAL -256(R10), R10
+ MOVW $0x0019, (CX)
+ MOVW R10, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+repeat_three_match_nolit_encodeBlockAsm4MB_emit_copy_short_2b:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (CX)
+ MOVB R10, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+repeat_two_match_nolit_encodeBlockAsm4MB_emit_copy_short_2b:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy_short_2b:
+ XORQ DI, DI
+ LEAL 1(DI)(R10*4), R10
+ MOVB SI, 1(CX)
+ SARL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, R10
+ MOVB R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+long_offset_short_match_nolit_encodeBlockAsm4MB:
+ MOVB $0xee, (CX)
+ MOVW SI, 1(CX)
+ LEAL -60(R10), R10
+ ADDQ $0x03, CX
+
+ // emitRepeat
+ MOVL R10, DI
+ LEAL -4(R10), R10
+ CMPL DI, $0x08
+ JBE repeat_two_match_nolit_encodeBlockAsm4MB_emit_copy_short
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy_short
+ CMPL SI, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy_short
+
+cant_repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy_short:
+ CMPL R10, $0x00000104
+ JB repeat_three_match_nolit_encodeBlockAsm4MB_emit_copy_short
+ CMPL R10, $0x00010100
+ JB repeat_four_match_nolit_encodeBlockAsm4MB_emit_copy_short
+ LEAL -65536(R10), R10
+ MOVL R10, SI
+ MOVW $0x001d, (CX)
+ MOVW R10, 2(CX)
+ SARL $0x10, SI
+ MOVB SI, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+repeat_four_match_nolit_encodeBlockAsm4MB_emit_copy_short:
+ LEAL -256(R10), R10
+ MOVW $0x0019, (CX)
+ MOVW R10, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+repeat_three_match_nolit_encodeBlockAsm4MB_emit_copy_short:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (CX)
+ MOVB R10, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+repeat_two_match_nolit_encodeBlockAsm4MB_emit_copy_short:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+repeat_two_offset_match_nolit_encodeBlockAsm4MB_emit_copy_short:
+ XORQ DI, DI
+ LEAL 1(DI)(R10*4), R10
+ MOVB SI, 1(CX)
+ SARL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, R10
+ MOVB R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+two_byte_offset_short_match_nolit_encodeBlockAsm4MB:
+ MOVL R10, DI
+ SHLL $0x02, DI
+ CMPL R10, $0x0c
+ JAE emit_copy_three_match_nolit_encodeBlockAsm4MB
+ CMPL SI, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeBlockAsm4MB
+ LEAL -15(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm4MB
+
+emit_copy_three_match_nolit_encodeBlockAsm4MB:
+ LEAL -2(DI), DI
+ MOVB DI, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeBlockAsm4MB:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeBlockAsm4MB
+ MOVQ -2(BX)(DX*1), DI
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeBlockAsm4MB
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeBlockAsm4MB:
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ DI, R8
+ SHRQ $0x10, DI
+ MOVQ DI, SI
+ SHLQ $0x10, R8
+ IMULQ R9, R8
+ SHRQ $0x32, R8
+ SHLQ $0x10, SI
+ IMULQ R9, SI
+ SHRQ $0x32, SI
+ LEAL -2(DX), R9
+ LEAQ (AX)(SI*4), R10
+ MOVL (R10), SI
+ MOVL R9, (AX)(R8*4)
+ MOVL DX, (R10)
+ CMPL (BX)(SI*1), DI
+ JEQ match_nolit_loop_encodeBlockAsm4MB
+ INCL DX
+ JMP search_loop_encodeBlockAsm4MB
+
+emit_remainder_encodeBlockAsm4MB:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 4(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeBlockAsm4MB
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeBlockAsm4MB:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeBlockAsm4MB
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeBlockAsm4MB
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeBlockAsm4MB
+ CMPL DX, $0x00010000
+ JB three_bytes_emit_remainder_encodeBlockAsm4MB
+ MOVL DX, BX
+ SHRL $0x10, BX
+ MOVB $0xf8, (CX)
+ MOVW DX, 1(CX)
+ MOVB BL, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_emit_remainder_encodeBlockAsm4MB
+
+three_bytes_emit_remainder_encodeBlockAsm4MB:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeBlockAsm4MB
+
+two_bytes_emit_remainder_encodeBlockAsm4MB:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeBlockAsm4MB
+ JMP memmove_long_emit_remainder_encodeBlockAsm4MB
+
+one_byte_emit_remainder_encodeBlockAsm4MB:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeBlockAsm4MB:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeBlockAsm4MB_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeBlockAsm4MB_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeBlockAsm4MB_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeBlockAsm4MB_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeBlockAsm4MB_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeBlockAsm4MB_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm4MB_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm4MB
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm4MB_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm4MB
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm4MB_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm4MB
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm4MB_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm4MB
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm4MB_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm4MB
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm4MB_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeBlockAsm4MB:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeBlockAsm4MB
+
+memmove_long_emit_remainder_encodeBlockAsm4MB:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeBlockAsm4MBlarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeBlockAsm4MBlarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeBlockAsm4MBlarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeBlockAsm4MBlarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeBlockAsm4MBlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeBlockAsm4MB:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeBlockAsm12B(dst []byte, src []byte, tmp *[16384]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeBlockAsm12B(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000080, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeBlockAsm12B:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeBlockAsm12B
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL DX, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeBlockAsm12B:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x05, SI
+ LEAL 4(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeBlockAsm12B
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x000000cf1bbcdcbb, R9
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHRQ $0x08, R11
+ SHLQ $0x18, R10
+ IMULQ R9, R10
+ SHRQ $0x34, R10
+ SHLQ $0x18, R11
+ IMULQ R9, R11
+ SHRQ $0x34, R11
+ MOVL (AX)(R10*4), SI
+ MOVL (AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ LEAL 1(DX), R10
+ MOVL R10, (AX)(R11*4)
+ MOVQ DI, R10
+ SHRQ $0x10, R10
+ SHLQ $0x18, R10
+ IMULQ R9, R10
+ SHRQ $0x34, R10
+ MOVL DX, R9
+ SUBL 16(SP), R9
+ MOVL 1(BX)(R9*1), R11
+ MOVQ DI, R9
+ SHRQ $0x08, R9
+ CMPL R9, R11
+ JNE no_repeat_found_encodeBlockAsm12B
+ LEAL 1(DX), DI
+ MOVL 12(SP), R8
+ MOVL DI, SI
+ SUBL 16(SP), SI
+ JZ repeat_extend_back_end_encodeBlockAsm12B
+
+repeat_extend_back_loop_encodeBlockAsm12B:
+ CMPL DI, R8
+ JBE repeat_extend_back_end_encodeBlockAsm12B
+ MOVB -1(BX)(SI*1), R9
+ MOVB -1(BX)(DI*1), R10
+ CMPB R9, R10
+ JNE repeat_extend_back_end_encodeBlockAsm12B
+ LEAL -1(DI), DI
+ DECL SI
+ JNZ repeat_extend_back_loop_encodeBlockAsm12B
+
+repeat_extend_back_end_encodeBlockAsm12B:
+ MOVL DI, SI
+ SUBL 12(SP), SI
+ LEAQ 3(CX)(SI*1), SI
+ CMPQ SI, (SP)
+ JB repeat_dst_size_check_encodeBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+repeat_dst_size_check_encodeBlockAsm12B:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_repeat_emit_encodeBlockAsm12B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_repeat_emit_encodeBlockAsm12B
+ CMPL SI, $0x00000100
+ JB two_bytes_repeat_emit_encodeBlockAsm12B
+ JB three_bytes_repeat_emit_encodeBlockAsm12B
+
+three_bytes_repeat_emit_encodeBlockAsm12B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_repeat_emit_encodeBlockAsm12B
+
+two_bytes_repeat_emit_encodeBlockAsm12B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_repeat_emit_encodeBlockAsm12B
+ JMP memmove_long_repeat_emit_encodeBlockAsm12B
+
+one_byte_repeat_emit_encodeBlockAsm12B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_repeat_emit_encodeBlockAsm12B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm12B_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm12B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm12B_memmove_move_17through32
+ JMP emit_lit_memmove_repeat_emit_encodeBlockAsm12B_memmove_move_33through64
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm12B_memmove_move_8:
+ MOVQ (R10), R11
+ MOVQ R11, (CX)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm12B
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm12B_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm12B
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm12B_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm12B
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm12B_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_repeat_emit_encodeBlockAsm12B:
+ MOVQ SI, CX
+ JMP emit_literal_done_repeat_emit_encodeBlockAsm12B
+
+memmove_long_repeat_emit_encodeBlockAsm12B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R12
+ SHRQ $0x05, R12
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R13
+ SUBQ R11, R13
+ DECQ R12
+ JA emit_lit_memmove_long_repeat_emit_encodeBlockAsm12Blarge_forward_sse_loop_32
+ LEAQ -32(R10)(R13*1), R11
+ LEAQ -32(CX)(R13*1), R14
+
+emit_lit_memmove_long_repeat_emit_encodeBlockAsm12Blarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R14)
+ MOVOA X5, 16(R14)
+ ADDQ $0x20, R14
+ ADDQ $0x20, R11
+ ADDQ $0x20, R13
+ DECQ R12
+ JNA emit_lit_memmove_long_repeat_emit_encodeBlockAsm12Blarge_big_loop_back
+
+emit_lit_memmove_long_repeat_emit_encodeBlockAsm12Blarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R13*1), X4
+ MOVOU -16(R10)(R13*1), X5
+ MOVOA X4, -32(CX)(R13*1)
+ MOVOA X5, -16(CX)(R13*1)
+ ADDQ $0x20, R13
+ CMPQ R9, R13
+ JAE emit_lit_memmove_long_repeat_emit_encodeBlockAsm12Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_repeat_emit_encodeBlockAsm12B:
+ ADDL $0x05, DX
+ MOVL DX, SI
+ SUBL 16(SP), SI
+ MOVQ src_len+32(FP), R9
+ SUBL DX, R9
+ LEAQ (BX)(DX*1), R10
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_repeat_extend_encodeBlockAsm12B:
+ CMPL R9, $0x10
+ JB matchlen_match8_repeat_extend_encodeBlockAsm12B
+ MOVQ (R10)(R12*1), R11
+ MOVQ 8(R10)(R12*1), R13
+ XORQ (SI)(R12*1), R11
+ JNZ matchlen_bsf_8_repeat_extend_encodeBlockAsm12B
+ XORQ 8(SI)(R12*1), R13
+ JNZ matchlen_bsf_16repeat_extend_encodeBlockAsm12B
+ LEAL -16(R9), R9
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_repeat_extend_encodeBlockAsm12B
+
+matchlen_bsf_16repeat_extend_encodeBlockAsm12B:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP repeat_extend_forward_end_encodeBlockAsm12B
+
+matchlen_match8_repeat_extend_encodeBlockAsm12B:
+ CMPL R9, $0x08
+ JB matchlen_match4_repeat_extend_encodeBlockAsm12B
+ MOVQ (R10)(R12*1), R11
+ XORQ (SI)(R12*1), R11
+ JNZ matchlen_bsf_8_repeat_extend_encodeBlockAsm12B
+ LEAL -8(R9), R9
+ LEAL 8(R12), R12
+ JMP matchlen_match4_repeat_extend_encodeBlockAsm12B
+
+matchlen_bsf_8_repeat_extend_encodeBlockAsm12B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP repeat_extend_forward_end_encodeBlockAsm12B
+
+matchlen_match4_repeat_extend_encodeBlockAsm12B:
+ CMPL R9, $0x04
+ JB matchlen_match2_repeat_extend_encodeBlockAsm12B
+ MOVL (R10)(R12*1), R11
+ CMPL (SI)(R12*1), R11
+ JNE matchlen_match2_repeat_extend_encodeBlockAsm12B
+ LEAL -4(R9), R9
+ LEAL 4(R12), R12
+
+matchlen_match2_repeat_extend_encodeBlockAsm12B:
+ CMPL R9, $0x01
+ JE matchlen_match1_repeat_extend_encodeBlockAsm12B
+ JB repeat_extend_forward_end_encodeBlockAsm12B
+ MOVW (R10)(R12*1), R11
+ CMPW (SI)(R12*1), R11
+ JNE matchlen_match1_repeat_extend_encodeBlockAsm12B
+ LEAL 2(R12), R12
+ SUBL $0x02, R9
+ JZ repeat_extend_forward_end_encodeBlockAsm12B
+
+matchlen_match1_repeat_extend_encodeBlockAsm12B:
+ MOVB (R10)(R12*1), R11
+ CMPB (SI)(R12*1), R11
+ JNE repeat_extend_forward_end_encodeBlockAsm12B
+ LEAL 1(R12), R12
+
+repeat_extend_forward_end_encodeBlockAsm12B:
+ ADDL R12, DX
+ MOVL DX, SI
+ SUBL DI, SI
+ MOVL 16(SP), DI
+ TESTL R8, R8
+ JZ repeat_as_copy_encodeBlockAsm12B
+
+ // emitRepeat
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_match_repeat_encodeBlockAsm12B
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_match_repeat_encodeBlockAsm12B
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_match_repeat_encodeBlockAsm12B
+
+cant_repeat_two_offset_match_repeat_encodeBlockAsm12B:
+ CMPL SI, $0x00000104
+ JB repeat_three_match_repeat_encodeBlockAsm12B
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+repeat_three_match_repeat_encodeBlockAsm12B:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+repeat_two_match_repeat_encodeBlockAsm12B:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+repeat_two_offset_match_repeat_encodeBlockAsm12B:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+repeat_as_copy_encodeBlockAsm12B:
+ // emitCopy
+ CMPL SI, $0x40
+ JBE two_byte_offset_short_repeat_as_copy_encodeBlockAsm12B
+ CMPL DI, $0x00000800
+ JAE long_offset_short_repeat_as_copy_encodeBlockAsm12B
+ MOVL $0x00000001, R8
+ LEAL 16(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, SI
+
+ // emitRepeat
+ LEAL -4(SI), SI
+ JMP cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm12B_emit_copy_short_2b
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_repeat_as_copy_encodeBlockAsm12B_emit_copy_short_2b
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm12B_emit_copy_short_2b
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_repeat_as_copy_encodeBlockAsm12B_emit_copy_short_2b
+
+cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm12B_emit_copy_short_2b:
+ CMPL SI, $0x00000104
+ JB repeat_three_repeat_as_copy_encodeBlockAsm12B_emit_copy_short_2b
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+repeat_three_repeat_as_copy_encodeBlockAsm12B_emit_copy_short_2b:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+repeat_two_repeat_as_copy_encodeBlockAsm12B_emit_copy_short_2b:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+repeat_two_offset_repeat_as_copy_encodeBlockAsm12B_emit_copy_short_2b:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+long_offset_short_repeat_as_copy_encodeBlockAsm12B:
+ MOVB $0xee, (CX)
+ MOVW DI, 1(CX)
+ LEAL -60(SI), SI
+ ADDQ $0x03, CX
+
+ // emitRepeat
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_repeat_as_copy_encodeBlockAsm12B_emit_copy_short
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm12B_emit_copy_short
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_repeat_as_copy_encodeBlockAsm12B_emit_copy_short
+
+cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm12B_emit_copy_short:
+ CMPL SI, $0x00000104
+ JB repeat_three_repeat_as_copy_encodeBlockAsm12B_emit_copy_short
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+repeat_three_repeat_as_copy_encodeBlockAsm12B_emit_copy_short:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+repeat_two_repeat_as_copy_encodeBlockAsm12B_emit_copy_short:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+repeat_two_offset_repeat_as_copy_encodeBlockAsm12B_emit_copy_short:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+two_byte_offset_short_repeat_as_copy_encodeBlockAsm12B:
+ MOVL SI, R8
+ SHLL $0x02, R8
+ CMPL SI, $0x0c
+ JAE emit_copy_three_repeat_as_copy_encodeBlockAsm12B
+ CMPL DI, $0x00000800
+ JAE emit_copy_three_repeat_as_copy_encodeBlockAsm12B
+ LEAL -15(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm12B
+
+emit_copy_three_repeat_as_copy_encodeBlockAsm12B:
+ LEAL -2(R8), R8
+ MOVB R8, (CX)
+ MOVW DI, 1(CX)
+ ADDQ $0x03, CX
+
+repeat_end_emit_encodeBlockAsm12B:
+ MOVL DX, 12(SP)
+ JMP search_loop_encodeBlockAsm12B
+
+no_repeat_found_encodeBlockAsm12B:
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeBlockAsm12B
+ SHRQ $0x08, DI
+ MOVL (AX)(R10*4), SI
+ LEAL 2(DX), R9
+ CMPL (BX)(R8*1), DI
+ JEQ candidate2_match_encodeBlockAsm12B
+ MOVL R9, (AX)(R10*4)
+ SHRQ $0x08, DI
+ CMPL (BX)(SI*1), DI
+ JEQ candidate3_match_encodeBlockAsm12B
+ MOVL 20(SP), DX
+ JMP search_loop_encodeBlockAsm12B
+
+candidate3_match_encodeBlockAsm12B:
+ ADDL $0x02, DX
+ JMP candidate_match_encodeBlockAsm12B
+
+candidate2_match_encodeBlockAsm12B:
+ MOVL R9, (AX)(R10*4)
+ INCL DX
+ MOVL R8, SI
+
+candidate_match_encodeBlockAsm12B:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeBlockAsm12B
+
+match_extend_back_loop_encodeBlockAsm12B:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeBlockAsm12B
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeBlockAsm12B
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeBlockAsm12B
+ JMP match_extend_back_loop_encodeBlockAsm12B
+
+match_extend_back_end_encodeBlockAsm12B:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeBlockAsm12B:
+ MOVL DX, DI
+ MOVL 12(SP), R8
+ CMPL R8, DI
+ JEQ emit_literal_done_match_emit_encodeBlockAsm12B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(R8*1), DI
+ SUBL R8, R9
+ LEAL -1(R9), R8
+ CMPL R8, $0x3c
+ JB one_byte_match_emit_encodeBlockAsm12B
+ CMPL R8, $0x00000100
+ JB two_bytes_match_emit_encodeBlockAsm12B
+ JB three_bytes_match_emit_encodeBlockAsm12B
+
+three_bytes_match_emit_encodeBlockAsm12B:
+ MOVB $0xf4, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeBlockAsm12B
+
+two_bytes_match_emit_encodeBlockAsm12B:
+ MOVB $0xf0, (CX)
+ MOVB R8, 1(CX)
+ ADDQ $0x02, CX
+ CMPL R8, $0x40
+ JB memmove_match_emit_encodeBlockAsm12B
+ JMP memmove_long_match_emit_encodeBlockAsm12B
+
+one_byte_match_emit_encodeBlockAsm12B:
+ SHLB $0x02, R8
+ MOVB R8, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeBlockAsm12B:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm12B_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm12B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm12B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeBlockAsm12B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeBlockAsm12B_memmove_move_8:
+ MOVQ (DI), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeBlockAsm12B_memmove_move_8through16:
+ MOVQ (DI), R10
+ MOVQ -8(DI)(R9*1), DI
+ MOVQ R10, (CX)
+ MOVQ DI, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeBlockAsm12B_memmove_move_17through32:
+ MOVOU (DI), X0
+ MOVOU -16(DI)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeBlockAsm12B_memmove_move_33through64:
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeBlockAsm12B:
+ MOVQ R8, CX
+ JMP emit_literal_done_match_emit_encodeBlockAsm12B
+
+memmove_long_match_emit_encodeBlockAsm12B:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveLong
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVQ R9, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_match_emit_encodeBlockAsm12Blarge_forward_sse_loop_32
+ LEAQ -32(DI)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_match_emit_encodeBlockAsm12Blarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_match_emit_encodeBlockAsm12Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeBlockAsm12Blarge_forward_sse_loop_32:
+ MOVOU -32(DI)(R12*1), X4
+ MOVOU -16(DI)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R9, R12
+ JAE emit_lit_memmove_long_match_emit_encodeBlockAsm12Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ R8, CX
+
+emit_literal_done_match_emit_encodeBlockAsm12B:
+match_nolit_loop_encodeBlockAsm12B:
+ MOVL DX, DI
+ SUBL SI, DI
+ MOVL DI, 16(SP)
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), DI
+ SUBL DX, DI
+ LEAQ (BX)(DX*1), R8
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R10, R10
+
+matchlen_loopback_16_match_nolit_encodeBlockAsm12B:
+ CMPL DI, $0x10
+ JB matchlen_match8_match_nolit_encodeBlockAsm12B
+ MOVQ (R8)(R10*1), R9
+ MOVQ 8(R8)(R10*1), R11
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeBlockAsm12B
+ XORQ 8(SI)(R10*1), R11
+ JNZ matchlen_bsf_16match_nolit_encodeBlockAsm12B
+ LEAL -16(DI), DI
+ LEAL 16(R10), R10
+ JMP matchlen_loopback_16_match_nolit_encodeBlockAsm12B
+
+matchlen_bsf_16match_nolit_encodeBlockAsm12B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL 8(R10)(R11*1), R10
+ JMP match_nolit_end_encodeBlockAsm12B
+
+matchlen_match8_match_nolit_encodeBlockAsm12B:
+ CMPL DI, $0x08
+ JB matchlen_match4_match_nolit_encodeBlockAsm12B
+ MOVQ (R8)(R10*1), R9
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeBlockAsm12B
+ LEAL -8(DI), DI
+ LEAL 8(R10), R10
+ JMP matchlen_match4_match_nolit_encodeBlockAsm12B
+
+matchlen_bsf_8_match_nolit_encodeBlockAsm12B:
+#ifdef GOAMD64_v3
+ TZCNTQ R9, R9
+
+#else
+ BSFQ R9, R9
+
+#endif
+ SARQ $0x03, R9
+ LEAL (R10)(R9*1), R10
+ JMP match_nolit_end_encodeBlockAsm12B
+
+matchlen_match4_match_nolit_encodeBlockAsm12B:
+ CMPL DI, $0x04
+ JB matchlen_match2_match_nolit_encodeBlockAsm12B
+ MOVL (R8)(R10*1), R9
+ CMPL (SI)(R10*1), R9
+ JNE matchlen_match2_match_nolit_encodeBlockAsm12B
+ LEAL -4(DI), DI
+ LEAL 4(R10), R10
+
+matchlen_match2_match_nolit_encodeBlockAsm12B:
+ CMPL DI, $0x01
+ JE matchlen_match1_match_nolit_encodeBlockAsm12B
+ JB match_nolit_end_encodeBlockAsm12B
+ MOVW (R8)(R10*1), R9
+ CMPW (SI)(R10*1), R9
+ JNE matchlen_match1_match_nolit_encodeBlockAsm12B
+ LEAL 2(R10), R10
+ SUBL $0x02, DI
+ JZ match_nolit_end_encodeBlockAsm12B
+
+matchlen_match1_match_nolit_encodeBlockAsm12B:
+ MOVB (R8)(R10*1), R9
+ CMPB (SI)(R10*1), R9
+ JNE match_nolit_end_encodeBlockAsm12B
+ LEAL 1(R10), R10
+
+match_nolit_end_encodeBlockAsm12B:
+ ADDL R10, DX
+ MOVL 16(SP), SI
+ ADDL $0x04, R10
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeBlockAsm12B
+ CMPL SI, $0x00000800
+ JAE long_offset_short_match_nolit_encodeBlockAsm12B
+ MOVL $0x00000001, DI
+ LEAL 16(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, R10
+
+ // emitRepeat
+ LEAL -4(R10), R10
+ JMP cant_repeat_two_offset_match_nolit_encodeBlockAsm12B_emit_copy_short_2b
+ MOVL R10, DI
+ LEAL -4(R10), R10
+ CMPL DI, $0x08
+ JBE repeat_two_match_nolit_encodeBlockAsm12B_emit_copy_short_2b
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBlockAsm12B_emit_copy_short_2b
+ CMPL SI, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBlockAsm12B_emit_copy_short_2b
+
+cant_repeat_two_offset_match_nolit_encodeBlockAsm12B_emit_copy_short_2b:
+ CMPL R10, $0x00000104
+ JB repeat_three_match_nolit_encodeBlockAsm12B_emit_copy_short_2b
+ LEAL -256(R10), R10
+ MOVW $0x0019, (CX)
+ MOVW R10, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm12B
+
+repeat_three_match_nolit_encodeBlockAsm12B_emit_copy_short_2b:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (CX)
+ MOVB R10, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm12B
+
+repeat_two_match_nolit_encodeBlockAsm12B_emit_copy_short_2b:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm12B
+
+repeat_two_offset_match_nolit_encodeBlockAsm12B_emit_copy_short_2b:
+ XORQ DI, DI
+ LEAL 1(DI)(R10*4), R10
+ MOVB SI, 1(CX)
+ SARL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, R10
+ MOVB R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm12B
+
+long_offset_short_match_nolit_encodeBlockAsm12B:
+ MOVB $0xee, (CX)
+ MOVW SI, 1(CX)
+ LEAL -60(R10), R10
+ ADDQ $0x03, CX
+
+ // emitRepeat
+ MOVL R10, DI
+ LEAL -4(R10), R10
+ CMPL DI, $0x08
+ JBE repeat_two_match_nolit_encodeBlockAsm12B_emit_copy_short
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBlockAsm12B_emit_copy_short
+ CMPL SI, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBlockAsm12B_emit_copy_short
+
+cant_repeat_two_offset_match_nolit_encodeBlockAsm12B_emit_copy_short:
+ CMPL R10, $0x00000104
+ JB repeat_three_match_nolit_encodeBlockAsm12B_emit_copy_short
+ LEAL -256(R10), R10
+ MOVW $0x0019, (CX)
+ MOVW R10, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm12B
+
+repeat_three_match_nolit_encodeBlockAsm12B_emit_copy_short:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (CX)
+ MOVB R10, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm12B
+
+repeat_two_match_nolit_encodeBlockAsm12B_emit_copy_short:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm12B
+
+repeat_two_offset_match_nolit_encodeBlockAsm12B_emit_copy_short:
+ XORQ DI, DI
+ LEAL 1(DI)(R10*4), R10
+ MOVB SI, 1(CX)
+ SARL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, R10
+ MOVB R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm12B
+
+two_byte_offset_short_match_nolit_encodeBlockAsm12B:
+ MOVL R10, DI
+ SHLL $0x02, DI
+ CMPL R10, $0x0c
+ JAE emit_copy_three_match_nolit_encodeBlockAsm12B
+ CMPL SI, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeBlockAsm12B
+ LEAL -15(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm12B
+
+emit_copy_three_match_nolit_encodeBlockAsm12B:
+ LEAL -2(DI), DI
+ MOVB DI, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeBlockAsm12B:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeBlockAsm12B
+ MOVQ -2(BX)(DX*1), DI
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeBlockAsm12B:
+ MOVQ $0x000000cf1bbcdcbb, R9
+ MOVQ DI, R8
+ SHRQ $0x10, DI
+ MOVQ DI, SI
+ SHLQ $0x18, R8
+ IMULQ R9, R8
+ SHRQ $0x34, R8
+ SHLQ $0x18, SI
+ IMULQ R9, SI
+ SHRQ $0x34, SI
+ LEAL -2(DX), R9
+ LEAQ (AX)(SI*4), R10
+ MOVL (R10), SI
+ MOVL R9, (AX)(R8*4)
+ MOVL DX, (R10)
+ CMPL (BX)(SI*1), DI
+ JEQ match_nolit_loop_encodeBlockAsm12B
+ INCL DX
+ JMP search_loop_encodeBlockAsm12B
+
+emit_remainder_encodeBlockAsm12B:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeBlockAsm12B:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeBlockAsm12B
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeBlockAsm12B
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeBlockAsm12B
+ JB three_bytes_emit_remainder_encodeBlockAsm12B
+
+three_bytes_emit_remainder_encodeBlockAsm12B:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeBlockAsm12B
+
+two_bytes_emit_remainder_encodeBlockAsm12B:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeBlockAsm12B
+ JMP memmove_long_emit_remainder_encodeBlockAsm12B
+
+one_byte_emit_remainder_encodeBlockAsm12B:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeBlockAsm12B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeBlockAsm12B_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeBlockAsm12B_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeBlockAsm12B_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeBlockAsm12B_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeBlockAsm12B_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeBlockAsm12B_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm12B_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm12B_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm12B_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm12B_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm12B_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm12B_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeBlockAsm12B:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeBlockAsm12B
+
+memmove_long_emit_remainder_encodeBlockAsm12B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeBlockAsm12Blarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeBlockAsm12Blarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeBlockAsm12Blarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeBlockAsm12Blarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeBlockAsm12Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeBlockAsm12B:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeBlockAsm10B(dst []byte, src []byte, tmp *[4096]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeBlockAsm10B(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000020, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeBlockAsm10B:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeBlockAsm10B
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL DX, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeBlockAsm10B:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x05, SI
+ LEAL 4(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeBlockAsm10B
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x9e3779b1, R9
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHRQ $0x08, R11
+ SHLQ $0x20, R10
+ IMULQ R9, R10
+ SHRQ $0x36, R10
+ SHLQ $0x20, R11
+ IMULQ R9, R11
+ SHRQ $0x36, R11
+ MOVL (AX)(R10*4), SI
+ MOVL (AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ LEAL 1(DX), R10
+ MOVL R10, (AX)(R11*4)
+ MOVQ DI, R10
+ SHRQ $0x10, R10
+ SHLQ $0x20, R10
+ IMULQ R9, R10
+ SHRQ $0x36, R10
+ MOVL DX, R9
+ SUBL 16(SP), R9
+ MOVL 1(BX)(R9*1), R11
+ MOVQ DI, R9
+ SHRQ $0x08, R9
+ CMPL R9, R11
+ JNE no_repeat_found_encodeBlockAsm10B
+ LEAL 1(DX), DI
+ MOVL 12(SP), R8
+ MOVL DI, SI
+ SUBL 16(SP), SI
+ JZ repeat_extend_back_end_encodeBlockAsm10B
+
+repeat_extend_back_loop_encodeBlockAsm10B:
+ CMPL DI, R8
+ JBE repeat_extend_back_end_encodeBlockAsm10B
+ MOVB -1(BX)(SI*1), R9
+ MOVB -1(BX)(DI*1), R10
+ CMPB R9, R10
+ JNE repeat_extend_back_end_encodeBlockAsm10B
+ LEAL -1(DI), DI
+ DECL SI
+ JNZ repeat_extend_back_loop_encodeBlockAsm10B
+
+repeat_extend_back_end_encodeBlockAsm10B:
+ MOVL DI, SI
+ SUBL 12(SP), SI
+ LEAQ 3(CX)(SI*1), SI
+ CMPQ SI, (SP)
+ JB repeat_dst_size_check_encodeBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+repeat_dst_size_check_encodeBlockAsm10B:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_repeat_emit_encodeBlockAsm10B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_repeat_emit_encodeBlockAsm10B
+ CMPL SI, $0x00000100
+ JB two_bytes_repeat_emit_encodeBlockAsm10B
+ JB three_bytes_repeat_emit_encodeBlockAsm10B
+
+three_bytes_repeat_emit_encodeBlockAsm10B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_repeat_emit_encodeBlockAsm10B
+
+two_bytes_repeat_emit_encodeBlockAsm10B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_repeat_emit_encodeBlockAsm10B
+ JMP memmove_long_repeat_emit_encodeBlockAsm10B
+
+one_byte_repeat_emit_encodeBlockAsm10B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_repeat_emit_encodeBlockAsm10B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm10B_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm10B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm10B_memmove_move_17through32
+ JMP emit_lit_memmove_repeat_emit_encodeBlockAsm10B_memmove_move_33through64
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm10B_memmove_move_8:
+ MOVQ (R10), R11
+ MOVQ R11, (CX)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm10B
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm10B_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm10B
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm10B_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm10B
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm10B_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_repeat_emit_encodeBlockAsm10B:
+ MOVQ SI, CX
+ JMP emit_literal_done_repeat_emit_encodeBlockAsm10B
+
+memmove_long_repeat_emit_encodeBlockAsm10B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R12
+ SHRQ $0x05, R12
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R13
+ SUBQ R11, R13
+ DECQ R12
+ JA emit_lit_memmove_long_repeat_emit_encodeBlockAsm10Blarge_forward_sse_loop_32
+ LEAQ -32(R10)(R13*1), R11
+ LEAQ -32(CX)(R13*1), R14
+
+emit_lit_memmove_long_repeat_emit_encodeBlockAsm10Blarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R14)
+ MOVOA X5, 16(R14)
+ ADDQ $0x20, R14
+ ADDQ $0x20, R11
+ ADDQ $0x20, R13
+ DECQ R12
+ JNA emit_lit_memmove_long_repeat_emit_encodeBlockAsm10Blarge_big_loop_back
+
+emit_lit_memmove_long_repeat_emit_encodeBlockAsm10Blarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R13*1), X4
+ MOVOU -16(R10)(R13*1), X5
+ MOVOA X4, -32(CX)(R13*1)
+ MOVOA X5, -16(CX)(R13*1)
+ ADDQ $0x20, R13
+ CMPQ R9, R13
+ JAE emit_lit_memmove_long_repeat_emit_encodeBlockAsm10Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_repeat_emit_encodeBlockAsm10B:
+ ADDL $0x05, DX
+ MOVL DX, SI
+ SUBL 16(SP), SI
+ MOVQ src_len+32(FP), R9
+ SUBL DX, R9
+ LEAQ (BX)(DX*1), R10
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_repeat_extend_encodeBlockAsm10B:
+ CMPL R9, $0x10
+ JB matchlen_match8_repeat_extend_encodeBlockAsm10B
+ MOVQ (R10)(R12*1), R11
+ MOVQ 8(R10)(R12*1), R13
+ XORQ (SI)(R12*1), R11
+ JNZ matchlen_bsf_8_repeat_extend_encodeBlockAsm10B
+ XORQ 8(SI)(R12*1), R13
+ JNZ matchlen_bsf_16repeat_extend_encodeBlockAsm10B
+ LEAL -16(R9), R9
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_repeat_extend_encodeBlockAsm10B
+
+matchlen_bsf_16repeat_extend_encodeBlockAsm10B:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP repeat_extend_forward_end_encodeBlockAsm10B
+
+matchlen_match8_repeat_extend_encodeBlockAsm10B:
+ CMPL R9, $0x08
+ JB matchlen_match4_repeat_extend_encodeBlockAsm10B
+ MOVQ (R10)(R12*1), R11
+ XORQ (SI)(R12*1), R11
+ JNZ matchlen_bsf_8_repeat_extend_encodeBlockAsm10B
+ LEAL -8(R9), R9
+ LEAL 8(R12), R12
+ JMP matchlen_match4_repeat_extend_encodeBlockAsm10B
+
+matchlen_bsf_8_repeat_extend_encodeBlockAsm10B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP repeat_extend_forward_end_encodeBlockAsm10B
+
+matchlen_match4_repeat_extend_encodeBlockAsm10B:
+ CMPL R9, $0x04
+ JB matchlen_match2_repeat_extend_encodeBlockAsm10B
+ MOVL (R10)(R12*1), R11
+ CMPL (SI)(R12*1), R11
+ JNE matchlen_match2_repeat_extend_encodeBlockAsm10B
+ LEAL -4(R9), R9
+ LEAL 4(R12), R12
+
+matchlen_match2_repeat_extend_encodeBlockAsm10B:
+ CMPL R9, $0x01
+ JE matchlen_match1_repeat_extend_encodeBlockAsm10B
+ JB repeat_extend_forward_end_encodeBlockAsm10B
+ MOVW (R10)(R12*1), R11
+ CMPW (SI)(R12*1), R11
+ JNE matchlen_match1_repeat_extend_encodeBlockAsm10B
+ LEAL 2(R12), R12
+ SUBL $0x02, R9
+ JZ repeat_extend_forward_end_encodeBlockAsm10B
+
+matchlen_match1_repeat_extend_encodeBlockAsm10B:
+ MOVB (R10)(R12*1), R11
+ CMPB (SI)(R12*1), R11
+ JNE repeat_extend_forward_end_encodeBlockAsm10B
+ LEAL 1(R12), R12
+
+repeat_extend_forward_end_encodeBlockAsm10B:
+ ADDL R12, DX
+ MOVL DX, SI
+ SUBL DI, SI
+ MOVL 16(SP), DI
+ TESTL R8, R8
+ JZ repeat_as_copy_encodeBlockAsm10B
+
+ // emitRepeat
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_match_repeat_encodeBlockAsm10B
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_match_repeat_encodeBlockAsm10B
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_match_repeat_encodeBlockAsm10B
+
+cant_repeat_two_offset_match_repeat_encodeBlockAsm10B:
+ CMPL SI, $0x00000104
+ JB repeat_three_match_repeat_encodeBlockAsm10B
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+repeat_three_match_repeat_encodeBlockAsm10B:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+repeat_two_match_repeat_encodeBlockAsm10B:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+repeat_two_offset_match_repeat_encodeBlockAsm10B:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+repeat_as_copy_encodeBlockAsm10B:
+ // emitCopy
+ CMPL SI, $0x40
+ JBE two_byte_offset_short_repeat_as_copy_encodeBlockAsm10B
+ CMPL DI, $0x00000800
+ JAE long_offset_short_repeat_as_copy_encodeBlockAsm10B
+ MOVL $0x00000001, R8
+ LEAL 16(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, SI
+
+ // emitRepeat
+ LEAL -4(SI), SI
+ JMP cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm10B_emit_copy_short_2b
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_repeat_as_copy_encodeBlockAsm10B_emit_copy_short_2b
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm10B_emit_copy_short_2b
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_repeat_as_copy_encodeBlockAsm10B_emit_copy_short_2b
+
+cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm10B_emit_copy_short_2b:
+ CMPL SI, $0x00000104
+ JB repeat_three_repeat_as_copy_encodeBlockAsm10B_emit_copy_short_2b
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+repeat_three_repeat_as_copy_encodeBlockAsm10B_emit_copy_short_2b:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+repeat_two_repeat_as_copy_encodeBlockAsm10B_emit_copy_short_2b:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+repeat_two_offset_repeat_as_copy_encodeBlockAsm10B_emit_copy_short_2b:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+long_offset_short_repeat_as_copy_encodeBlockAsm10B:
+ MOVB $0xee, (CX)
+ MOVW DI, 1(CX)
+ LEAL -60(SI), SI
+ ADDQ $0x03, CX
+
+ // emitRepeat
+ MOVL SI, R8
+ LEAL -4(SI), SI
+ CMPL R8, $0x08
+ JBE repeat_two_repeat_as_copy_encodeBlockAsm10B_emit_copy_short
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm10B_emit_copy_short
+ CMPL DI, $0x00000800
+ JB repeat_two_offset_repeat_as_copy_encodeBlockAsm10B_emit_copy_short
+
+cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm10B_emit_copy_short:
+ CMPL SI, $0x00000104
+ JB repeat_three_repeat_as_copy_encodeBlockAsm10B_emit_copy_short
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+repeat_three_repeat_as_copy_encodeBlockAsm10B_emit_copy_short:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+repeat_two_repeat_as_copy_encodeBlockAsm10B_emit_copy_short:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+repeat_two_offset_repeat_as_copy_encodeBlockAsm10B_emit_copy_short:
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+two_byte_offset_short_repeat_as_copy_encodeBlockAsm10B:
+ MOVL SI, R8
+ SHLL $0x02, R8
+ CMPL SI, $0x0c
+ JAE emit_copy_three_repeat_as_copy_encodeBlockAsm10B
+ CMPL DI, $0x00000800
+ JAE emit_copy_three_repeat_as_copy_encodeBlockAsm10B
+ LEAL -15(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm10B
+
+emit_copy_three_repeat_as_copy_encodeBlockAsm10B:
+ LEAL -2(R8), R8
+ MOVB R8, (CX)
+ MOVW DI, 1(CX)
+ ADDQ $0x03, CX
+
+repeat_end_emit_encodeBlockAsm10B:
+ MOVL DX, 12(SP)
+ JMP search_loop_encodeBlockAsm10B
+
+no_repeat_found_encodeBlockAsm10B:
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeBlockAsm10B
+ SHRQ $0x08, DI
+ MOVL (AX)(R10*4), SI
+ LEAL 2(DX), R9
+ CMPL (BX)(R8*1), DI
+ JEQ candidate2_match_encodeBlockAsm10B
+ MOVL R9, (AX)(R10*4)
+ SHRQ $0x08, DI
+ CMPL (BX)(SI*1), DI
+ JEQ candidate3_match_encodeBlockAsm10B
+ MOVL 20(SP), DX
+ JMP search_loop_encodeBlockAsm10B
+
+candidate3_match_encodeBlockAsm10B:
+ ADDL $0x02, DX
+ JMP candidate_match_encodeBlockAsm10B
+
+candidate2_match_encodeBlockAsm10B:
+ MOVL R9, (AX)(R10*4)
+ INCL DX
+ MOVL R8, SI
+
+candidate_match_encodeBlockAsm10B:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeBlockAsm10B
+
+match_extend_back_loop_encodeBlockAsm10B:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeBlockAsm10B
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeBlockAsm10B
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeBlockAsm10B
+ JMP match_extend_back_loop_encodeBlockAsm10B
+
+match_extend_back_end_encodeBlockAsm10B:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeBlockAsm10B:
+ MOVL DX, DI
+ MOVL 12(SP), R8
+ CMPL R8, DI
+ JEQ emit_literal_done_match_emit_encodeBlockAsm10B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(R8*1), DI
+ SUBL R8, R9
+ LEAL -1(R9), R8
+ CMPL R8, $0x3c
+ JB one_byte_match_emit_encodeBlockAsm10B
+ CMPL R8, $0x00000100
+ JB two_bytes_match_emit_encodeBlockAsm10B
+ JB three_bytes_match_emit_encodeBlockAsm10B
+
+three_bytes_match_emit_encodeBlockAsm10B:
+ MOVB $0xf4, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeBlockAsm10B
+
+two_bytes_match_emit_encodeBlockAsm10B:
+ MOVB $0xf0, (CX)
+ MOVB R8, 1(CX)
+ ADDQ $0x02, CX
+ CMPL R8, $0x40
+ JB memmove_match_emit_encodeBlockAsm10B
+ JMP memmove_long_match_emit_encodeBlockAsm10B
+
+one_byte_match_emit_encodeBlockAsm10B:
+ SHLB $0x02, R8
+ MOVB R8, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeBlockAsm10B:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm10B_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm10B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm10B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeBlockAsm10B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeBlockAsm10B_memmove_move_8:
+ MOVQ (DI), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeBlockAsm10B_memmove_move_8through16:
+ MOVQ (DI), R10
+ MOVQ -8(DI)(R9*1), DI
+ MOVQ R10, (CX)
+ MOVQ DI, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeBlockAsm10B_memmove_move_17through32:
+ MOVOU (DI), X0
+ MOVOU -16(DI)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeBlockAsm10B_memmove_move_33through64:
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeBlockAsm10B:
+ MOVQ R8, CX
+ JMP emit_literal_done_match_emit_encodeBlockAsm10B
+
+memmove_long_match_emit_encodeBlockAsm10B:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveLong
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVQ R9, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_match_emit_encodeBlockAsm10Blarge_forward_sse_loop_32
+ LEAQ -32(DI)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_match_emit_encodeBlockAsm10Blarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_match_emit_encodeBlockAsm10Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeBlockAsm10Blarge_forward_sse_loop_32:
+ MOVOU -32(DI)(R12*1), X4
+ MOVOU -16(DI)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R9, R12
+ JAE emit_lit_memmove_long_match_emit_encodeBlockAsm10Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ R8, CX
+
+emit_literal_done_match_emit_encodeBlockAsm10B:
+match_nolit_loop_encodeBlockAsm10B:
+ MOVL DX, DI
+ SUBL SI, DI
+ MOVL DI, 16(SP)
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), DI
+ SUBL DX, DI
+ LEAQ (BX)(DX*1), R8
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R10, R10
+
+matchlen_loopback_16_match_nolit_encodeBlockAsm10B:
+ CMPL DI, $0x10
+ JB matchlen_match8_match_nolit_encodeBlockAsm10B
+ MOVQ (R8)(R10*1), R9
+ MOVQ 8(R8)(R10*1), R11
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeBlockAsm10B
+ XORQ 8(SI)(R10*1), R11
+ JNZ matchlen_bsf_16match_nolit_encodeBlockAsm10B
+ LEAL -16(DI), DI
+ LEAL 16(R10), R10
+ JMP matchlen_loopback_16_match_nolit_encodeBlockAsm10B
+
+matchlen_bsf_16match_nolit_encodeBlockAsm10B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL 8(R10)(R11*1), R10
+ JMP match_nolit_end_encodeBlockAsm10B
+
+matchlen_match8_match_nolit_encodeBlockAsm10B:
+ CMPL DI, $0x08
+ JB matchlen_match4_match_nolit_encodeBlockAsm10B
+ MOVQ (R8)(R10*1), R9
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeBlockAsm10B
+ LEAL -8(DI), DI
+ LEAL 8(R10), R10
+ JMP matchlen_match4_match_nolit_encodeBlockAsm10B
+
+matchlen_bsf_8_match_nolit_encodeBlockAsm10B:
+#ifdef GOAMD64_v3
+ TZCNTQ R9, R9
+
+#else
+ BSFQ R9, R9
+
+#endif
+ SARQ $0x03, R9
+ LEAL (R10)(R9*1), R10
+ JMP match_nolit_end_encodeBlockAsm10B
+
+matchlen_match4_match_nolit_encodeBlockAsm10B:
+ CMPL DI, $0x04
+ JB matchlen_match2_match_nolit_encodeBlockAsm10B
+ MOVL (R8)(R10*1), R9
+ CMPL (SI)(R10*1), R9
+ JNE matchlen_match2_match_nolit_encodeBlockAsm10B
+ LEAL -4(DI), DI
+ LEAL 4(R10), R10
+
+matchlen_match2_match_nolit_encodeBlockAsm10B:
+ CMPL DI, $0x01
+ JE matchlen_match1_match_nolit_encodeBlockAsm10B
+ JB match_nolit_end_encodeBlockAsm10B
+ MOVW (R8)(R10*1), R9
+ CMPW (SI)(R10*1), R9
+ JNE matchlen_match1_match_nolit_encodeBlockAsm10B
+ LEAL 2(R10), R10
+ SUBL $0x02, DI
+ JZ match_nolit_end_encodeBlockAsm10B
+
+matchlen_match1_match_nolit_encodeBlockAsm10B:
+ MOVB (R8)(R10*1), R9
+ CMPB (SI)(R10*1), R9
+ JNE match_nolit_end_encodeBlockAsm10B
+ LEAL 1(R10), R10
+
+match_nolit_end_encodeBlockAsm10B:
+ ADDL R10, DX
+ MOVL 16(SP), SI
+ ADDL $0x04, R10
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeBlockAsm10B
+ CMPL SI, $0x00000800
+ JAE long_offset_short_match_nolit_encodeBlockAsm10B
+ MOVL $0x00000001, DI
+ LEAL 16(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, R10
+
+ // emitRepeat
+ LEAL -4(R10), R10
+ JMP cant_repeat_two_offset_match_nolit_encodeBlockAsm10B_emit_copy_short_2b
+ MOVL R10, DI
+ LEAL -4(R10), R10
+ CMPL DI, $0x08
+ JBE repeat_two_match_nolit_encodeBlockAsm10B_emit_copy_short_2b
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBlockAsm10B_emit_copy_short_2b
+ CMPL SI, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBlockAsm10B_emit_copy_short_2b
+
+cant_repeat_two_offset_match_nolit_encodeBlockAsm10B_emit_copy_short_2b:
+ CMPL R10, $0x00000104
+ JB repeat_three_match_nolit_encodeBlockAsm10B_emit_copy_short_2b
+ LEAL -256(R10), R10
+ MOVW $0x0019, (CX)
+ MOVW R10, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm10B
+
+repeat_three_match_nolit_encodeBlockAsm10B_emit_copy_short_2b:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (CX)
+ MOVB R10, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm10B
+
+repeat_two_match_nolit_encodeBlockAsm10B_emit_copy_short_2b:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm10B
+
+repeat_two_offset_match_nolit_encodeBlockAsm10B_emit_copy_short_2b:
+ XORQ DI, DI
+ LEAL 1(DI)(R10*4), R10
+ MOVB SI, 1(CX)
+ SARL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, R10
+ MOVB R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm10B
+
+long_offset_short_match_nolit_encodeBlockAsm10B:
+ MOVB $0xee, (CX)
+ MOVW SI, 1(CX)
+ LEAL -60(R10), R10
+ ADDQ $0x03, CX
+
+ // emitRepeat
+ MOVL R10, DI
+ LEAL -4(R10), R10
+ CMPL DI, $0x08
+ JBE repeat_two_match_nolit_encodeBlockAsm10B_emit_copy_short
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBlockAsm10B_emit_copy_short
+ CMPL SI, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBlockAsm10B_emit_copy_short
+
+cant_repeat_two_offset_match_nolit_encodeBlockAsm10B_emit_copy_short:
+ CMPL R10, $0x00000104
+ JB repeat_three_match_nolit_encodeBlockAsm10B_emit_copy_short
+ LEAL -256(R10), R10
+ MOVW $0x0019, (CX)
+ MOVW R10, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm10B
+
+repeat_three_match_nolit_encodeBlockAsm10B_emit_copy_short:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (CX)
+ MOVB R10, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm10B
+
+repeat_two_match_nolit_encodeBlockAsm10B_emit_copy_short:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm10B
+
+repeat_two_offset_match_nolit_encodeBlockAsm10B_emit_copy_short:
+ XORQ DI, DI
+ LEAL 1(DI)(R10*4), R10
+ MOVB SI, 1(CX)
+ SARL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, R10
+ MOVB R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm10B
+
+two_byte_offset_short_match_nolit_encodeBlockAsm10B:
+ MOVL R10, DI
+ SHLL $0x02, DI
+ CMPL R10, $0x0c
+ JAE emit_copy_three_match_nolit_encodeBlockAsm10B
+ CMPL SI, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeBlockAsm10B
+ LEAL -15(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm10B
+
+emit_copy_three_match_nolit_encodeBlockAsm10B:
+ LEAL -2(DI), DI
+ MOVB DI, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeBlockAsm10B:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeBlockAsm10B
+ MOVQ -2(BX)(DX*1), DI
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeBlockAsm10B:
+ MOVQ $0x9e3779b1, R9
+ MOVQ DI, R8
+ SHRQ $0x10, DI
+ MOVQ DI, SI
+ SHLQ $0x20, R8
+ IMULQ R9, R8
+ SHRQ $0x36, R8
+ SHLQ $0x20, SI
+ IMULQ R9, SI
+ SHRQ $0x36, SI
+ LEAL -2(DX), R9
+ LEAQ (AX)(SI*4), R10
+ MOVL (R10), SI
+ MOVL R9, (AX)(R8*4)
+ MOVL DX, (R10)
+ CMPL (BX)(SI*1), DI
+ JEQ match_nolit_loop_encodeBlockAsm10B
+ INCL DX
+ JMP search_loop_encodeBlockAsm10B
+
+emit_remainder_encodeBlockAsm10B:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeBlockAsm10B:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeBlockAsm10B
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeBlockAsm10B
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeBlockAsm10B
+ JB three_bytes_emit_remainder_encodeBlockAsm10B
+
+three_bytes_emit_remainder_encodeBlockAsm10B:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeBlockAsm10B
+
+two_bytes_emit_remainder_encodeBlockAsm10B:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeBlockAsm10B
+ JMP memmove_long_emit_remainder_encodeBlockAsm10B
+
+one_byte_emit_remainder_encodeBlockAsm10B:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeBlockAsm10B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeBlockAsm10B_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeBlockAsm10B_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeBlockAsm10B_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeBlockAsm10B_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeBlockAsm10B_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeBlockAsm10B_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm10B_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm10B_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm10B_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm10B_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm10B_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm10B_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeBlockAsm10B:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeBlockAsm10B
+
+memmove_long_emit_remainder_encodeBlockAsm10B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeBlockAsm10Blarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeBlockAsm10Blarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeBlockAsm10Blarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeBlockAsm10Blarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeBlockAsm10Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeBlockAsm10B:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeBlockAsm8B(dst []byte, src []byte, tmp *[1024]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeBlockAsm8B(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000008, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeBlockAsm8B:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeBlockAsm8B
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL DX, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeBlockAsm8B:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x04, SI
+ LEAL 4(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeBlockAsm8B
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x9e3779b1, R9
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHRQ $0x08, R11
+ SHLQ $0x20, R10
+ IMULQ R9, R10
+ SHRQ $0x38, R10
+ SHLQ $0x20, R11
+ IMULQ R9, R11
+ SHRQ $0x38, R11
+ MOVL (AX)(R10*4), SI
+ MOVL (AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ LEAL 1(DX), R10
+ MOVL R10, (AX)(R11*4)
+ MOVQ DI, R10
+ SHRQ $0x10, R10
+ SHLQ $0x20, R10
+ IMULQ R9, R10
+ SHRQ $0x38, R10
+ MOVL DX, R9
+ SUBL 16(SP), R9
+ MOVL 1(BX)(R9*1), R11
+ MOVQ DI, R9
+ SHRQ $0x08, R9
+ CMPL R9, R11
+ JNE no_repeat_found_encodeBlockAsm8B
+ LEAL 1(DX), DI
+ MOVL 12(SP), R8
+ MOVL DI, SI
+ SUBL 16(SP), SI
+ JZ repeat_extend_back_end_encodeBlockAsm8B
+
+repeat_extend_back_loop_encodeBlockAsm8B:
+ CMPL DI, R8
+ JBE repeat_extend_back_end_encodeBlockAsm8B
+ MOVB -1(BX)(SI*1), R9
+ MOVB -1(BX)(DI*1), R10
+ CMPB R9, R10
+ JNE repeat_extend_back_end_encodeBlockAsm8B
+ LEAL -1(DI), DI
+ DECL SI
+ JNZ repeat_extend_back_loop_encodeBlockAsm8B
+
+repeat_extend_back_end_encodeBlockAsm8B:
+ MOVL DI, SI
+ SUBL 12(SP), SI
+ LEAQ 3(CX)(SI*1), SI
+ CMPQ SI, (SP)
+ JB repeat_dst_size_check_encodeBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+repeat_dst_size_check_encodeBlockAsm8B:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_repeat_emit_encodeBlockAsm8B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_repeat_emit_encodeBlockAsm8B
+ CMPL SI, $0x00000100
+ JB two_bytes_repeat_emit_encodeBlockAsm8B
+ JB three_bytes_repeat_emit_encodeBlockAsm8B
+
+three_bytes_repeat_emit_encodeBlockAsm8B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_repeat_emit_encodeBlockAsm8B
+
+two_bytes_repeat_emit_encodeBlockAsm8B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_repeat_emit_encodeBlockAsm8B
+ JMP memmove_long_repeat_emit_encodeBlockAsm8B
+
+one_byte_repeat_emit_encodeBlockAsm8B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_repeat_emit_encodeBlockAsm8B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm8B_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm8B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_repeat_emit_encodeBlockAsm8B_memmove_move_17through32
+ JMP emit_lit_memmove_repeat_emit_encodeBlockAsm8B_memmove_move_33through64
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm8B_memmove_move_8:
+ MOVQ (R10), R11
+ MOVQ R11, (CX)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm8B
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm8B_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm8B
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm8B_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_repeat_emit_encodeBlockAsm8B
+
+emit_lit_memmove_repeat_emit_encodeBlockAsm8B_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_repeat_emit_encodeBlockAsm8B:
+ MOVQ SI, CX
+ JMP emit_literal_done_repeat_emit_encodeBlockAsm8B
+
+memmove_long_repeat_emit_encodeBlockAsm8B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R12
+ SHRQ $0x05, R12
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R13
+ SUBQ R11, R13
+ DECQ R12
+ JA emit_lit_memmove_long_repeat_emit_encodeBlockAsm8Blarge_forward_sse_loop_32
+ LEAQ -32(R10)(R13*1), R11
+ LEAQ -32(CX)(R13*1), R14
+
+emit_lit_memmove_long_repeat_emit_encodeBlockAsm8Blarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R14)
+ MOVOA X5, 16(R14)
+ ADDQ $0x20, R14
+ ADDQ $0x20, R11
+ ADDQ $0x20, R13
+ DECQ R12
+ JNA emit_lit_memmove_long_repeat_emit_encodeBlockAsm8Blarge_big_loop_back
+
+emit_lit_memmove_long_repeat_emit_encodeBlockAsm8Blarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R13*1), X4
+ MOVOU -16(R10)(R13*1), X5
+ MOVOA X4, -32(CX)(R13*1)
+ MOVOA X5, -16(CX)(R13*1)
+ ADDQ $0x20, R13
+ CMPQ R9, R13
+ JAE emit_lit_memmove_long_repeat_emit_encodeBlockAsm8Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_repeat_emit_encodeBlockAsm8B:
+ ADDL $0x05, DX
+ MOVL DX, SI
+ SUBL 16(SP), SI
+ MOVQ src_len+32(FP), R9
+ SUBL DX, R9
+ LEAQ (BX)(DX*1), R10
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_repeat_extend_encodeBlockAsm8B:
+ CMPL R9, $0x10
+ JB matchlen_match8_repeat_extend_encodeBlockAsm8B
+ MOVQ (R10)(R12*1), R11
+ MOVQ 8(R10)(R12*1), R13
+ XORQ (SI)(R12*1), R11
+ JNZ matchlen_bsf_8_repeat_extend_encodeBlockAsm8B
+ XORQ 8(SI)(R12*1), R13
+ JNZ matchlen_bsf_16repeat_extend_encodeBlockAsm8B
+ LEAL -16(R9), R9
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_repeat_extend_encodeBlockAsm8B
+
+matchlen_bsf_16repeat_extend_encodeBlockAsm8B:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP repeat_extend_forward_end_encodeBlockAsm8B
+
+matchlen_match8_repeat_extend_encodeBlockAsm8B:
+ CMPL R9, $0x08
+ JB matchlen_match4_repeat_extend_encodeBlockAsm8B
+ MOVQ (R10)(R12*1), R11
+ XORQ (SI)(R12*1), R11
+ JNZ matchlen_bsf_8_repeat_extend_encodeBlockAsm8B
+ LEAL -8(R9), R9
+ LEAL 8(R12), R12
+ JMP matchlen_match4_repeat_extend_encodeBlockAsm8B
+
+matchlen_bsf_8_repeat_extend_encodeBlockAsm8B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP repeat_extend_forward_end_encodeBlockAsm8B
+
+matchlen_match4_repeat_extend_encodeBlockAsm8B:
+ CMPL R9, $0x04
+ JB matchlen_match2_repeat_extend_encodeBlockAsm8B
+ MOVL (R10)(R12*1), R11
+ CMPL (SI)(R12*1), R11
+ JNE matchlen_match2_repeat_extend_encodeBlockAsm8B
+ LEAL -4(R9), R9
+ LEAL 4(R12), R12
+
+matchlen_match2_repeat_extend_encodeBlockAsm8B:
+ CMPL R9, $0x01
+ JE matchlen_match1_repeat_extend_encodeBlockAsm8B
+ JB repeat_extend_forward_end_encodeBlockAsm8B
+ MOVW (R10)(R12*1), R11
+ CMPW (SI)(R12*1), R11
+ JNE matchlen_match1_repeat_extend_encodeBlockAsm8B
+ LEAL 2(R12), R12
+ SUBL $0x02, R9
+ JZ repeat_extend_forward_end_encodeBlockAsm8B
+
+matchlen_match1_repeat_extend_encodeBlockAsm8B:
+ MOVB (R10)(R12*1), R11
+ CMPB (SI)(R12*1), R11
+ JNE repeat_extend_forward_end_encodeBlockAsm8B
+ LEAL 1(R12), R12
+
+repeat_extend_forward_end_encodeBlockAsm8B:
+ ADDL R12, DX
+ MOVL DX, SI
+ SUBL DI, SI
+ MOVL 16(SP), DI
+ TESTL R8, R8
+ JZ repeat_as_copy_encodeBlockAsm8B
+
+ // emitRepeat
+ MOVL SI, DI
+ LEAL -4(SI), SI
+ CMPL DI, $0x08
+ JBE repeat_two_match_repeat_encodeBlockAsm8B
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_match_repeat_encodeBlockAsm8B
+
+cant_repeat_two_offset_match_repeat_encodeBlockAsm8B:
+ CMPL SI, $0x00000104
+ JB repeat_three_match_repeat_encodeBlockAsm8B
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+
+repeat_three_match_repeat_encodeBlockAsm8B:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+
+repeat_two_match_repeat_encodeBlockAsm8B:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+
+repeat_as_copy_encodeBlockAsm8B:
+ // emitCopy
+ CMPL SI, $0x40
+ JBE two_byte_offset_short_repeat_as_copy_encodeBlockAsm8B
+ CMPL DI, $0x00000800
+ JAE long_offset_short_repeat_as_copy_encodeBlockAsm8B
+ MOVL $0x00000001, R8
+ LEAL 16(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, SI
+
+ // emitRepeat
+ LEAL -4(SI), SI
+ JMP cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm8B_emit_copy_short_2b
+ MOVL SI, DI
+ LEAL -4(SI), SI
+ CMPL DI, $0x08
+ JBE repeat_two_repeat_as_copy_encodeBlockAsm8B_emit_copy_short_2b
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm8B_emit_copy_short_2b
+
+cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm8B_emit_copy_short_2b:
+ CMPL SI, $0x00000104
+ JB repeat_three_repeat_as_copy_encodeBlockAsm8B_emit_copy_short_2b
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+
+repeat_three_repeat_as_copy_encodeBlockAsm8B_emit_copy_short_2b:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+
+repeat_two_repeat_as_copy_encodeBlockAsm8B_emit_copy_short_2b:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+
+long_offset_short_repeat_as_copy_encodeBlockAsm8B:
+ MOVB $0xee, (CX)
+ MOVW DI, 1(CX)
+ LEAL -60(SI), SI
+ ADDQ $0x03, CX
+
+ // emitRepeat
+ MOVL SI, DI
+ LEAL -4(SI), SI
+ CMPL DI, $0x08
+ JBE repeat_two_repeat_as_copy_encodeBlockAsm8B_emit_copy_short
+ CMPL DI, $0x0c
+ JAE cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm8B_emit_copy_short
+
+cant_repeat_two_offset_repeat_as_copy_encodeBlockAsm8B_emit_copy_short:
+ CMPL SI, $0x00000104
+ JB repeat_three_repeat_as_copy_encodeBlockAsm8B_emit_copy_short
+ LEAL -256(SI), SI
+ MOVW $0x0019, (CX)
+ MOVW SI, 2(CX)
+ ADDQ $0x04, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+
+repeat_three_repeat_as_copy_encodeBlockAsm8B_emit_copy_short:
+ LEAL -4(SI), SI
+ MOVW $0x0015, (CX)
+ MOVB SI, 2(CX)
+ ADDQ $0x03, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+
+repeat_two_repeat_as_copy_encodeBlockAsm8B_emit_copy_short:
+ SHLL $0x02, SI
+ ORL $0x01, SI
+ MOVW SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+ XORQ R8, R8
+ LEAL 1(R8)(SI*4), SI
+ MOVB DI, 1(CX)
+ SARL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+
+two_byte_offset_short_repeat_as_copy_encodeBlockAsm8B:
+ MOVL SI, R8
+ SHLL $0x02, R8
+ CMPL SI, $0x0c
+ JAE emit_copy_three_repeat_as_copy_encodeBlockAsm8B
+ LEAL -15(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeBlockAsm8B
+
+emit_copy_three_repeat_as_copy_encodeBlockAsm8B:
+ LEAL -2(R8), R8
+ MOVB R8, (CX)
+ MOVW DI, 1(CX)
+ ADDQ $0x03, CX
+
+repeat_end_emit_encodeBlockAsm8B:
+ MOVL DX, 12(SP)
+ JMP search_loop_encodeBlockAsm8B
+
+no_repeat_found_encodeBlockAsm8B:
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeBlockAsm8B
+ SHRQ $0x08, DI
+ MOVL (AX)(R10*4), SI
+ LEAL 2(DX), R9
+ CMPL (BX)(R8*1), DI
+ JEQ candidate2_match_encodeBlockAsm8B
+ MOVL R9, (AX)(R10*4)
+ SHRQ $0x08, DI
+ CMPL (BX)(SI*1), DI
+ JEQ candidate3_match_encodeBlockAsm8B
+ MOVL 20(SP), DX
+ JMP search_loop_encodeBlockAsm8B
+
+candidate3_match_encodeBlockAsm8B:
+ ADDL $0x02, DX
+ JMP candidate_match_encodeBlockAsm8B
+
+candidate2_match_encodeBlockAsm8B:
+ MOVL R9, (AX)(R10*4)
+ INCL DX
+ MOVL R8, SI
+
+candidate_match_encodeBlockAsm8B:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeBlockAsm8B
+
+match_extend_back_loop_encodeBlockAsm8B:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeBlockAsm8B
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeBlockAsm8B
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeBlockAsm8B
+ JMP match_extend_back_loop_encodeBlockAsm8B
+
+match_extend_back_end_encodeBlockAsm8B:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeBlockAsm8B:
+ MOVL DX, DI
+ MOVL 12(SP), R8
+ CMPL R8, DI
+ JEQ emit_literal_done_match_emit_encodeBlockAsm8B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(R8*1), DI
+ SUBL R8, R9
+ LEAL -1(R9), R8
+ CMPL R8, $0x3c
+ JB one_byte_match_emit_encodeBlockAsm8B
+ CMPL R8, $0x00000100
+ JB two_bytes_match_emit_encodeBlockAsm8B
+ JB three_bytes_match_emit_encodeBlockAsm8B
+
+three_bytes_match_emit_encodeBlockAsm8B:
+ MOVB $0xf4, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeBlockAsm8B
+
+two_bytes_match_emit_encodeBlockAsm8B:
+ MOVB $0xf0, (CX)
+ MOVB R8, 1(CX)
+ ADDQ $0x02, CX
+ CMPL R8, $0x40
+ JB memmove_match_emit_encodeBlockAsm8B
+ JMP memmove_long_match_emit_encodeBlockAsm8B
+
+one_byte_match_emit_encodeBlockAsm8B:
+ SHLB $0x02, R8
+ MOVB R8, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeBlockAsm8B:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm8B_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm8B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeBlockAsm8B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeBlockAsm8B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeBlockAsm8B_memmove_move_8:
+ MOVQ (DI), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeBlockAsm8B_memmove_move_8through16:
+ MOVQ (DI), R10
+ MOVQ -8(DI)(R9*1), DI
+ MOVQ R10, (CX)
+ MOVQ DI, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeBlockAsm8B_memmove_move_17through32:
+ MOVOU (DI), X0
+ MOVOU -16(DI)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeBlockAsm8B_memmove_move_33through64:
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeBlockAsm8B:
+ MOVQ R8, CX
+ JMP emit_literal_done_match_emit_encodeBlockAsm8B
+
+memmove_long_match_emit_encodeBlockAsm8B:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveLong
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVQ R9, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_match_emit_encodeBlockAsm8Blarge_forward_sse_loop_32
+ LEAQ -32(DI)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_match_emit_encodeBlockAsm8Blarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_match_emit_encodeBlockAsm8Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeBlockAsm8Blarge_forward_sse_loop_32:
+ MOVOU -32(DI)(R12*1), X4
+ MOVOU -16(DI)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R9, R12
+ JAE emit_lit_memmove_long_match_emit_encodeBlockAsm8Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ R8, CX
+
+emit_literal_done_match_emit_encodeBlockAsm8B:
+match_nolit_loop_encodeBlockAsm8B:
+ MOVL DX, DI
+ SUBL SI, DI
+ MOVL DI, 16(SP)
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), DI
+ SUBL DX, DI
+ LEAQ (BX)(DX*1), R8
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R10, R10
+
+matchlen_loopback_16_match_nolit_encodeBlockAsm8B:
+ CMPL DI, $0x10
+ JB matchlen_match8_match_nolit_encodeBlockAsm8B
+ MOVQ (R8)(R10*1), R9
+ MOVQ 8(R8)(R10*1), R11
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeBlockAsm8B
+ XORQ 8(SI)(R10*1), R11
+ JNZ matchlen_bsf_16match_nolit_encodeBlockAsm8B
+ LEAL -16(DI), DI
+ LEAL 16(R10), R10
+ JMP matchlen_loopback_16_match_nolit_encodeBlockAsm8B
+
+matchlen_bsf_16match_nolit_encodeBlockAsm8B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL 8(R10)(R11*1), R10
+ JMP match_nolit_end_encodeBlockAsm8B
+
+matchlen_match8_match_nolit_encodeBlockAsm8B:
+ CMPL DI, $0x08
+ JB matchlen_match4_match_nolit_encodeBlockAsm8B
+ MOVQ (R8)(R10*1), R9
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeBlockAsm8B
+ LEAL -8(DI), DI
+ LEAL 8(R10), R10
+ JMP matchlen_match4_match_nolit_encodeBlockAsm8B
+
+matchlen_bsf_8_match_nolit_encodeBlockAsm8B:
+#ifdef GOAMD64_v3
+ TZCNTQ R9, R9
+
+#else
+ BSFQ R9, R9
+
+#endif
+ SARQ $0x03, R9
+ LEAL (R10)(R9*1), R10
+ JMP match_nolit_end_encodeBlockAsm8B
+
+matchlen_match4_match_nolit_encodeBlockAsm8B:
+ CMPL DI, $0x04
+ JB matchlen_match2_match_nolit_encodeBlockAsm8B
+ MOVL (R8)(R10*1), R9
+ CMPL (SI)(R10*1), R9
+ JNE matchlen_match2_match_nolit_encodeBlockAsm8B
+ LEAL -4(DI), DI
+ LEAL 4(R10), R10
+
+matchlen_match2_match_nolit_encodeBlockAsm8B:
+ CMPL DI, $0x01
+ JE matchlen_match1_match_nolit_encodeBlockAsm8B
+ JB match_nolit_end_encodeBlockAsm8B
+ MOVW (R8)(R10*1), R9
+ CMPW (SI)(R10*1), R9
+ JNE matchlen_match1_match_nolit_encodeBlockAsm8B
+ LEAL 2(R10), R10
+ SUBL $0x02, DI
+ JZ match_nolit_end_encodeBlockAsm8B
+
+matchlen_match1_match_nolit_encodeBlockAsm8B:
+ MOVB (R8)(R10*1), R9
+ CMPB (SI)(R10*1), R9
+ JNE match_nolit_end_encodeBlockAsm8B
+ LEAL 1(R10), R10
+
+match_nolit_end_encodeBlockAsm8B:
+ ADDL R10, DX
+ MOVL 16(SP), SI
+ ADDL $0x04, R10
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeBlockAsm8B
+ CMPL SI, $0x00000800
+ JAE long_offset_short_match_nolit_encodeBlockAsm8B
+ MOVL $0x00000001, DI
+ LEAL 16(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, R10
+
+ // emitRepeat
+ LEAL -4(R10), R10
+ JMP cant_repeat_two_offset_match_nolit_encodeBlockAsm8B_emit_copy_short_2b
+ MOVL R10, SI
+ LEAL -4(R10), R10
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBlockAsm8B_emit_copy_short_2b
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBlockAsm8B_emit_copy_short_2b
+
+cant_repeat_two_offset_match_nolit_encodeBlockAsm8B_emit_copy_short_2b:
+ CMPL R10, $0x00000104
+ JB repeat_three_match_nolit_encodeBlockAsm8B_emit_copy_short_2b
+ LEAL -256(R10), R10
+ MOVW $0x0019, (CX)
+ MOVW R10, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm8B
+
+repeat_three_match_nolit_encodeBlockAsm8B_emit_copy_short_2b:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (CX)
+ MOVB R10, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm8B
+
+repeat_two_match_nolit_encodeBlockAsm8B_emit_copy_short_2b:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm8B
+ XORQ DI, DI
+ LEAL 1(DI)(R10*4), R10
+ MOVB SI, 1(CX)
+ SARL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, R10
+ MOVB R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm8B
+
+long_offset_short_match_nolit_encodeBlockAsm8B:
+ MOVB $0xee, (CX)
+ MOVW SI, 1(CX)
+ LEAL -60(R10), R10
+ ADDQ $0x03, CX
+
+ // emitRepeat
+ MOVL R10, SI
+ LEAL -4(R10), R10
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBlockAsm8B_emit_copy_short
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBlockAsm8B_emit_copy_short
+
+cant_repeat_two_offset_match_nolit_encodeBlockAsm8B_emit_copy_short:
+ CMPL R10, $0x00000104
+ JB repeat_three_match_nolit_encodeBlockAsm8B_emit_copy_short
+ LEAL -256(R10), R10
+ MOVW $0x0019, (CX)
+ MOVW R10, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm8B
+
+repeat_three_match_nolit_encodeBlockAsm8B_emit_copy_short:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (CX)
+ MOVB R10, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm8B
+
+repeat_two_match_nolit_encodeBlockAsm8B_emit_copy_short:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm8B
+ XORQ DI, DI
+ LEAL 1(DI)(R10*4), R10
+ MOVB SI, 1(CX)
+ SARL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, R10
+ MOVB R10, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm8B
+
+two_byte_offset_short_match_nolit_encodeBlockAsm8B:
+ MOVL R10, DI
+ SHLL $0x02, DI
+ CMPL R10, $0x0c
+ JAE emit_copy_three_match_nolit_encodeBlockAsm8B
+ LEAL -15(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBlockAsm8B
+
+emit_copy_three_match_nolit_encodeBlockAsm8B:
+ LEAL -2(DI), DI
+ MOVB DI, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeBlockAsm8B:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeBlockAsm8B
+ MOVQ -2(BX)(DX*1), DI
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeBlockAsm8B:
+ MOVQ $0x9e3779b1, R9
+ MOVQ DI, R8
+ SHRQ $0x10, DI
+ MOVQ DI, SI
+ SHLQ $0x20, R8
+ IMULQ R9, R8
+ SHRQ $0x38, R8
+ SHLQ $0x20, SI
+ IMULQ R9, SI
+ SHRQ $0x38, SI
+ LEAL -2(DX), R9
+ LEAQ (AX)(SI*4), R10
+ MOVL (R10), SI
+ MOVL R9, (AX)(R8*4)
+ MOVL DX, (R10)
+ CMPL (BX)(SI*1), DI
+ JEQ match_nolit_loop_encodeBlockAsm8B
+ INCL DX
+ JMP search_loop_encodeBlockAsm8B
+
+emit_remainder_encodeBlockAsm8B:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeBlockAsm8B:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeBlockAsm8B
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeBlockAsm8B
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeBlockAsm8B
+ JB three_bytes_emit_remainder_encodeBlockAsm8B
+
+three_bytes_emit_remainder_encodeBlockAsm8B:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeBlockAsm8B
+
+two_bytes_emit_remainder_encodeBlockAsm8B:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeBlockAsm8B
+ JMP memmove_long_emit_remainder_encodeBlockAsm8B
+
+one_byte_emit_remainder_encodeBlockAsm8B:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeBlockAsm8B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeBlockAsm8B_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeBlockAsm8B_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeBlockAsm8B_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeBlockAsm8B_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeBlockAsm8B_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeBlockAsm8B_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm8B_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm8B_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm8B_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm8B_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm8B_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeBlockAsm8B_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeBlockAsm8B:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeBlockAsm8B
+
+memmove_long_emit_remainder_encodeBlockAsm8B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeBlockAsm8Blarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeBlockAsm8Blarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeBlockAsm8Blarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeBlockAsm8Blarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeBlockAsm8Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeBlockAsm8B:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeBetterBlockAsm(dst []byte, src []byte, tmp *[589824]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeBetterBlockAsm(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00001200, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeBetterBlockAsm:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeBetterBlockAsm
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -6(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL $0x00000000, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeBetterBlockAsm:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x07, SI
+ CMPL SI, $0x63
+ JBE check_maxskip_ok_encodeBetterBlockAsm
+ LEAL 100(DX), SI
+ JMP check_maxskip_cont_encodeBetterBlockAsm
+
+check_maxskip_ok_encodeBetterBlockAsm:
+ LEAL 1(DX)(SI*1), SI
+
+check_maxskip_cont_encodeBetterBlockAsm:
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeBetterBlockAsm
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x00cf1bbcdcbfa563, R9
+ MOVQ $0x9e3779b1, SI
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHLQ $0x08, R10
+ IMULQ R9, R10
+ SHRQ $0x2f, R10
+ SHLQ $0x20, R11
+ IMULQ SI, R11
+ SHRQ $0x32, R11
+ MOVL (AX)(R10*4), SI
+ MOVL 524288(AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ MOVL DX, 524288(AX)(R11*4)
+ MOVQ (BX)(SI*1), R10
+ MOVQ (BX)(R8*1), R11
+ CMPQ R10, DI
+ JEQ candidate_match_encodeBetterBlockAsm
+ CMPQ R11, DI
+ JNE no_short_found_encodeBetterBlockAsm
+ MOVL R8, SI
+ JMP candidate_match_encodeBetterBlockAsm
+
+no_short_found_encodeBetterBlockAsm:
+ CMPL R10, DI
+ JEQ candidate_match_encodeBetterBlockAsm
+ CMPL R11, DI
+ JEQ candidateS_match_encodeBetterBlockAsm
+ MOVL 20(SP), DX
+ JMP search_loop_encodeBetterBlockAsm
+
+candidateS_match_encodeBetterBlockAsm:
+ SHRQ $0x08, DI
+ MOVQ DI, R10
+ SHLQ $0x08, R10
+ IMULQ R9, R10
+ SHRQ $0x2f, R10
+ MOVL (AX)(R10*4), SI
+ INCL DX
+ MOVL DX, (AX)(R10*4)
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeBetterBlockAsm
+ DECL DX
+ MOVL R8, SI
+
+candidate_match_encodeBetterBlockAsm:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeBetterBlockAsm
+
+match_extend_back_loop_encodeBetterBlockAsm:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeBetterBlockAsm
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeBetterBlockAsm
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeBetterBlockAsm
+ JMP match_extend_back_loop_encodeBetterBlockAsm
+
+match_extend_back_end_encodeBetterBlockAsm:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 5(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeBetterBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeBetterBlockAsm:
+ MOVL DX, DI
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), R10
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_match_nolit_encodeBetterBlockAsm:
+ CMPL R8, $0x10
+ JB matchlen_match8_match_nolit_encodeBetterBlockAsm
+ MOVQ (R9)(R12*1), R11
+ MOVQ 8(R9)(R12*1), R13
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeBetterBlockAsm
+ XORQ 8(R10)(R12*1), R13
+ JNZ matchlen_bsf_16match_nolit_encodeBetterBlockAsm
+ LEAL -16(R8), R8
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_match_nolit_encodeBetterBlockAsm
+
+matchlen_bsf_16match_nolit_encodeBetterBlockAsm:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP match_nolit_end_encodeBetterBlockAsm
+
+matchlen_match8_match_nolit_encodeBetterBlockAsm:
+ CMPL R8, $0x08
+ JB matchlen_match4_match_nolit_encodeBetterBlockAsm
+ MOVQ (R9)(R12*1), R11
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeBetterBlockAsm
+ LEAL -8(R8), R8
+ LEAL 8(R12), R12
+ JMP matchlen_match4_match_nolit_encodeBetterBlockAsm
+
+matchlen_bsf_8_match_nolit_encodeBetterBlockAsm:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP match_nolit_end_encodeBetterBlockAsm
+
+matchlen_match4_match_nolit_encodeBetterBlockAsm:
+ CMPL R8, $0x04
+ JB matchlen_match2_match_nolit_encodeBetterBlockAsm
+ MOVL (R9)(R12*1), R11
+ CMPL (R10)(R12*1), R11
+ JNE matchlen_match2_match_nolit_encodeBetterBlockAsm
+ LEAL -4(R8), R8
+ LEAL 4(R12), R12
+
+matchlen_match2_match_nolit_encodeBetterBlockAsm:
+ CMPL R8, $0x01
+ JE matchlen_match1_match_nolit_encodeBetterBlockAsm
+ JB match_nolit_end_encodeBetterBlockAsm
+ MOVW (R9)(R12*1), R11
+ CMPW (R10)(R12*1), R11
+ JNE matchlen_match1_match_nolit_encodeBetterBlockAsm
+ LEAL 2(R12), R12
+ SUBL $0x02, R8
+ JZ match_nolit_end_encodeBetterBlockAsm
+
+matchlen_match1_match_nolit_encodeBetterBlockAsm:
+ MOVB (R9)(R12*1), R11
+ CMPB (R10)(R12*1), R11
+ JNE match_nolit_end_encodeBetterBlockAsm
+ LEAL 1(R12), R12
+
+match_nolit_end_encodeBetterBlockAsm:
+ MOVL DX, R8
+ SUBL SI, R8
+
+ // Check if repeat
+ CMPL 16(SP), R8
+ JEQ match_is_repeat_encodeBetterBlockAsm
+ CMPL R12, $0x01
+ JA match_length_ok_encodeBetterBlockAsm
+ CMPL R8, $0x0000ffff
+ JBE match_length_ok_encodeBetterBlockAsm
+ MOVL 20(SP), DX
+ INCL DX
+ JMP search_loop_encodeBetterBlockAsm
+
+match_length_ok_encodeBetterBlockAsm:
+ MOVL R8, 16(SP)
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_encodeBetterBlockAsm
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_encodeBetterBlockAsm
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_encodeBetterBlockAsm
+ CMPL SI, $0x00010000
+ JB three_bytes_match_emit_encodeBetterBlockAsm
+ CMPL SI, $0x01000000
+ JB four_bytes_match_emit_encodeBetterBlockAsm
+ MOVB $0xfc, (CX)
+ MOVL SI, 1(CX)
+ ADDQ $0x05, CX
+ JMP memmove_long_match_emit_encodeBetterBlockAsm
+
+four_bytes_match_emit_encodeBetterBlockAsm:
+ MOVL SI, R11
+ SHRL $0x10, R11
+ MOVB $0xf8, (CX)
+ MOVW SI, 1(CX)
+ MOVB R11, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_match_emit_encodeBetterBlockAsm
+
+three_bytes_match_emit_encodeBetterBlockAsm:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeBetterBlockAsm
+
+two_bytes_match_emit_encodeBetterBlockAsm:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_encodeBetterBlockAsm
+ JMP memmove_long_match_emit_encodeBetterBlockAsm
+
+one_byte_match_emit_encodeBetterBlockAsm:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeBetterBlockAsm:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x04
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm_memmove_move_4
+ CMPQ R9, $0x08
+ JB emit_lit_memmove_match_emit_encodeBetterBlockAsm_memmove_move_4through7
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeBetterBlockAsm_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm_memmove_move_4:
+ MOVL (R10), R11
+ MOVL R11, (CX)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm_memmove_move_4through7:
+ MOVL (R10), R11
+ MOVL -4(R10)(R9*1), R10
+ MOVL R11, (CX)
+ MOVL R10, -4(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeBetterBlockAsm:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_encodeBetterBlockAsm
+
+memmove_long_match_emit_encodeBetterBlockAsm:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_encodeBetterBlockAsmlarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_encodeBetterBlockAsmlarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_encodeBetterBlockAsmlarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeBetterBlockAsmlarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_encodeBetterBlockAsmlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_encodeBetterBlockAsm:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL R8, $0x00010000
+ JB two_byte_offset_match_nolit_encodeBetterBlockAsm
+ CMPL R12, $0x40
+ JBE four_bytes_remain_match_nolit_encodeBetterBlockAsm
+ MOVB $0xff, (CX)
+ MOVL R8, 1(CX)
+ LEAL -64(R12), R12
+ ADDQ $0x05, CX
+ CMPL R12, $0x04
+ JB four_bytes_remain_match_nolit_encodeBetterBlockAsm
+
+ // emitRepeat
+emit_repeat_again_match_nolit_encodeBetterBlockAsm_emit_copy:
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBetterBlockAsm_emit_copy
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy
+
+cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_encodeBetterBlockAsm_emit_copy
+ CMPL R12, $0x00010100
+ JB repeat_four_match_nolit_encodeBetterBlockAsm_emit_copy
+ CMPL R12, $0x0100ffff
+ JB repeat_five_match_nolit_encodeBetterBlockAsm_emit_copy
+ LEAL -16842747(R12), R12
+ MOVL $0xfffb001d, (CX)
+ MOVB $0xff, 4(CX)
+ ADDQ $0x05, CX
+ JMP emit_repeat_again_match_nolit_encodeBetterBlockAsm_emit_copy
+
+repeat_five_match_nolit_encodeBetterBlockAsm_emit_copy:
+ LEAL -65536(R12), R12
+ MOVL R12, R8
+ MOVW $0x001d, (CX)
+ MOVW R12, 2(CX)
+ SARL $0x10, R8
+ MOVB R8, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_four_match_nolit_encodeBetterBlockAsm_emit_copy:
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_three_match_nolit_encodeBetterBlockAsm_emit_copy:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_two_match_nolit_encodeBetterBlockAsm_emit_copy:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+four_bytes_remain_match_nolit_encodeBetterBlockAsm:
+ TESTL R12, R12
+ JZ match_nolit_emitcopy_end_encodeBetterBlockAsm
+ XORL SI, SI
+ LEAL -1(SI)(R12*4), R12
+ MOVB R12, (CX)
+ MOVL R8, 1(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+two_byte_offset_match_nolit_encodeBetterBlockAsm:
+ CMPL R12, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeBetterBlockAsm
+ CMPL R8, $0x00000800
+ JAE long_offset_short_match_nolit_encodeBetterBlockAsm
+ MOVL $0x00000001, SI
+ LEAL 16(SI), SI
+ MOVB R8, 1(CX)
+ MOVL R8, R9
+ SHRL $0x08, R9
+ SHLL $0x05, R9
+ ORL R9, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, R12
+
+ // emitRepeat
+ LEAL -4(R12), R12
+ JMP cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b
+
+emit_repeat_again_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b:
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b
+
+cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b
+ CMPL R12, $0x00010100
+ JB repeat_four_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b
+ CMPL R12, $0x0100ffff
+ JB repeat_five_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b
+ LEAL -16842747(R12), R12
+ MOVL $0xfffb001d, (CX)
+ MOVB $0xff, 4(CX)
+ ADDQ $0x05, CX
+ JMP emit_repeat_again_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b
+
+repeat_five_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b:
+ LEAL -65536(R12), R12
+ MOVL R12, R8
+ MOVW $0x001d, (CX)
+ MOVW R12, 2(CX)
+ SARL $0x10, R8
+ MOVB R8, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_four_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b:
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_three_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_two_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy_short_2b:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+long_offset_short_match_nolit_encodeBetterBlockAsm:
+ MOVB $0xee, (CX)
+ MOVW R8, 1(CX)
+ LEAL -60(R12), R12
+ ADDQ $0x03, CX
+
+ // emitRepeat
+emit_repeat_again_match_nolit_encodeBetterBlockAsm_emit_copy_short:
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBetterBlockAsm_emit_copy_short
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy_short
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy_short
+
+cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy_short:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_encodeBetterBlockAsm_emit_copy_short
+ CMPL R12, $0x00010100
+ JB repeat_four_match_nolit_encodeBetterBlockAsm_emit_copy_short
+ CMPL R12, $0x0100ffff
+ JB repeat_five_match_nolit_encodeBetterBlockAsm_emit_copy_short
+ LEAL -16842747(R12), R12
+ MOVL $0xfffb001d, (CX)
+ MOVB $0xff, 4(CX)
+ ADDQ $0x05, CX
+ JMP emit_repeat_again_match_nolit_encodeBetterBlockAsm_emit_copy_short
+
+repeat_five_match_nolit_encodeBetterBlockAsm_emit_copy_short:
+ LEAL -65536(R12), R12
+ MOVL R12, R8
+ MOVW $0x001d, (CX)
+ MOVW R12, 2(CX)
+ SARL $0x10, R8
+ MOVB R8, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_four_match_nolit_encodeBetterBlockAsm_emit_copy_short:
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_three_match_nolit_encodeBetterBlockAsm_emit_copy_short:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_two_match_nolit_encodeBetterBlockAsm_emit_copy_short:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_two_offset_match_nolit_encodeBetterBlockAsm_emit_copy_short:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+two_byte_offset_short_match_nolit_encodeBetterBlockAsm:
+ MOVL R12, SI
+ SHLL $0x02, SI
+ CMPL R12, $0x0c
+ JAE emit_copy_three_match_nolit_encodeBetterBlockAsm
+ CMPL R8, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeBetterBlockAsm
+ LEAL -15(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+emit_copy_three_match_nolit_encodeBetterBlockAsm:
+ LEAL -2(SI), SI
+ MOVB SI, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+match_is_repeat_encodeBetterBlockAsm:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_repeat_encodeBetterBlockAsm
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_repeat_encodeBetterBlockAsm
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_repeat_encodeBetterBlockAsm
+ CMPL SI, $0x00010000
+ JB three_bytes_match_emit_repeat_encodeBetterBlockAsm
+ CMPL SI, $0x01000000
+ JB four_bytes_match_emit_repeat_encodeBetterBlockAsm
+ MOVB $0xfc, (CX)
+ MOVL SI, 1(CX)
+ ADDQ $0x05, CX
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm
+
+four_bytes_match_emit_repeat_encodeBetterBlockAsm:
+ MOVL SI, R11
+ SHRL $0x10, R11
+ MOVB $0xf8, (CX)
+ MOVW SI, 1(CX)
+ MOVB R11, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm
+
+three_bytes_match_emit_repeat_encodeBetterBlockAsm:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm
+
+two_bytes_match_emit_repeat_encodeBetterBlockAsm:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_repeat_encodeBetterBlockAsm
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm
+
+one_byte_match_emit_repeat_encodeBetterBlockAsm:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_repeat_encodeBetterBlockAsm:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x04
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm_memmove_move_4
+ CMPQ R9, $0x08
+ JB emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm_memmove_move_4through7
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm_memmove_move_33through64
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm_memmove_move_4:
+ MOVL (R10), R11
+ MOVL R11, (CX)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm_memmove_move_4through7:
+ MOVL (R10), R11
+ MOVL -4(R10)(R9*1), R10
+ MOVL R11, (CX)
+ MOVL R10, -4(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_repeat_encodeBetterBlockAsm
+
+memmove_long_match_emit_repeat_encodeBetterBlockAsm:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsmlarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsmlarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsmlarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsmlarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsmlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_repeat_encodeBetterBlockAsm:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitRepeat
+emit_repeat_again_match_nolit_repeat_encodeBetterBlockAsm:
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_repeat_encodeBetterBlockAsm
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm
+
+cant_repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_repeat_encodeBetterBlockAsm
+ CMPL R12, $0x00010100
+ JB repeat_four_match_nolit_repeat_encodeBetterBlockAsm
+ CMPL R12, $0x0100ffff
+ JB repeat_five_match_nolit_repeat_encodeBetterBlockAsm
+ LEAL -16842747(R12), R12
+ MOVL $0xfffb001d, (CX)
+ MOVB $0xff, 4(CX)
+ ADDQ $0x05, CX
+ JMP emit_repeat_again_match_nolit_repeat_encodeBetterBlockAsm
+
+repeat_five_match_nolit_repeat_encodeBetterBlockAsm:
+ LEAL -65536(R12), R12
+ MOVL R12, R8
+ MOVW $0x001d, (CX)
+ MOVW R12, 2(CX)
+ SARL $0x10, R8
+ MOVB R8, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_four_match_nolit_repeat_encodeBetterBlockAsm:
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_three_match_nolit_repeat_encodeBetterBlockAsm:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_two_match_nolit_repeat_encodeBetterBlockAsm:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm
+
+repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+
+match_nolit_emitcopy_end_encodeBetterBlockAsm:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeBetterBlockAsm
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeBetterBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeBetterBlockAsm:
+ MOVQ $0x00cf1bbcdcbfa563, SI
+ MOVQ $0x9e3779b1, R8
+ LEAQ 1(DI), DI
+ LEAQ -2(DX), R9
+ MOVQ (BX)(DI*1), R10
+ MOVQ 1(BX)(DI*1), R11
+ MOVQ (BX)(R9*1), R12
+ MOVQ 1(BX)(R9*1), R13
+ SHLQ $0x08, R10
+ IMULQ SI, R10
+ SHRQ $0x2f, R10
+ SHLQ $0x20, R11
+ IMULQ R8, R11
+ SHRQ $0x32, R11
+ SHLQ $0x08, R12
+ IMULQ SI, R12
+ SHRQ $0x2f, R12
+ SHLQ $0x20, R13
+ IMULQ R8, R13
+ SHRQ $0x32, R13
+ LEAQ 1(DI), R8
+ LEAQ 1(R9), R14
+ MOVL DI, (AX)(R10*4)
+ MOVL R9, (AX)(R12*4)
+ MOVL R8, 524288(AX)(R11*4)
+ MOVL R14, 524288(AX)(R13*4)
+ LEAQ 1(R9)(DI*1), R8
+ SHRQ $0x01, R8
+ ADDQ $0x01, DI
+ SUBQ $0x01, R9
+
+index_loop_encodeBetterBlockAsm:
+ CMPQ R8, R9
+ JAE search_loop_encodeBetterBlockAsm
+ MOVQ (BX)(DI*1), R10
+ MOVQ (BX)(R8*1), R11
+ SHLQ $0x08, R10
+ IMULQ SI, R10
+ SHRQ $0x2f, R10
+ SHLQ $0x08, R11
+ IMULQ SI, R11
+ SHRQ $0x2f, R11
+ MOVL DI, (AX)(R10*4)
+ MOVL R8, (AX)(R11*4)
+ ADDQ $0x02, DI
+ ADDQ $0x02, R8
+ JMP index_loop_encodeBetterBlockAsm
+
+emit_remainder_encodeBetterBlockAsm:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 5(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeBetterBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeBetterBlockAsm:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeBetterBlockAsm
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeBetterBlockAsm
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeBetterBlockAsm
+ CMPL DX, $0x00010000
+ JB three_bytes_emit_remainder_encodeBetterBlockAsm
+ CMPL DX, $0x01000000
+ JB four_bytes_emit_remainder_encodeBetterBlockAsm
+ MOVB $0xfc, (CX)
+ MOVL DX, 1(CX)
+ ADDQ $0x05, CX
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm
+
+four_bytes_emit_remainder_encodeBetterBlockAsm:
+ MOVL DX, BX
+ SHRL $0x10, BX
+ MOVB $0xf8, (CX)
+ MOVW DX, 1(CX)
+ MOVB BL, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm
+
+three_bytes_emit_remainder_encodeBetterBlockAsm:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm
+
+two_bytes_emit_remainder_encodeBetterBlockAsm:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeBetterBlockAsm
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm
+
+one_byte_emit_remainder_encodeBetterBlockAsm:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeBetterBlockAsm:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeBetterBlockAsm_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeBetterBlockAsm_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeBetterBlockAsm_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeBetterBlockAsm:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeBetterBlockAsm
+
+memmove_long_emit_remainder_encodeBetterBlockAsm:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsmlarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsmlarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsmlarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsmlarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsmlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeBetterBlockAsm:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeBetterBlockAsm4MB(dst []byte, src []byte, tmp *[589824]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeBetterBlockAsm4MB(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00001200, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeBetterBlockAsm4MB:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeBetterBlockAsm4MB
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -6(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL $0x00000000, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeBetterBlockAsm4MB:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x07, SI
+ CMPL SI, $0x63
+ JBE check_maxskip_ok_encodeBetterBlockAsm4MB
+ LEAL 100(DX), SI
+ JMP check_maxskip_cont_encodeBetterBlockAsm4MB
+
+check_maxskip_ok_encodeBetterBlockAsm4MB:
+ LEAL 1(DX)(SI*1), SI
+
+check_maxskip_cont_encodeBetterBlockAsm4MB:
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeBetterBlockAsm4MB
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x00cf1bbcdcbfa563, R9
+ MOVQ $0x9e3779b1, SI
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHLQ $0x08, R10
+ IMULQ R9, R10
+ SHRQ $0x2f, R10
+ SHLQ $0x20, R11
+ IMULQ SI, R11
+ SHRQ $0x32, R11
+ MOVL (AX)(R10*4), SI
+ MOVL 524288(AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ MOVL DX, 524288(AX)(R11*4)
+ MOVQ (BX)(SI*1), R10
+ MOVQ (BX)(R8*1), R11
+ CMPQ R10, DI
+ JEQ candidate_match_encodeBetterBlockAsm4MB
+ CMPQ R11, DI
+ JNE no_short_found_encodeBetterBlockAsm4MB
+ MOVL R8, SI
+ JMP candidate_match_encodeBetterBlockAsm4MB
+
+no_short_found_encodeBetterBlockAsm4MB:
+ CMPL R10, DI
+ JEQ candidate_match_encodeBetterBlockAsm4MB
+ CMPL R11, DI
+ JEQ candidateS_match_encodeBetterBlockAsm4MB
+ MOVL 20(SP), DX
+ JMP search_loop_encodeBetterBlockAsm4MB
+
+candidateS_match_encodeBetterBlockAsm4MB:
+ SHRQ $0x08, DI
+ MOVQ DI, R10
+ SHLQ $0x08, R10
+ IMULQ R9, R10
+ SHRQ $0x2f, R10
+ MOVL (AX)(R10*4), SI
+ INCL DX
+ MOVL DX, (AX)(R10*4)
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeBetterBlockAsm4MB
+ DECL DX
+ MOVL R8, SI
+
+candidate_match_encodeBetterBlockAsm4MB:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeBetterBlockAsm4MB
+
+match_extend_back_loop_encodeBetterBlockAsm4MB:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeBetterBlockAsm4MB
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeBetterBlockAsm4MB
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeBetterBlockAsm4MB
+ JMP match_extend_back_loop_encodeBetterBlockAsm4MB
+
+match_extend_back_end_encodeBetterBlockAsm4MB:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 4(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeBetterBlockAsm4MB
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeBetterBlockAsm4MB:
+ MOVL DX, DI
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), R10
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_match_nolit_encodeBetterBlockAsm4MB:
+ CMPL R8, $0x10
+ JB matchlen_match8_match_nolit_encodeBetterBlockAsm4MB
+ MOVQ (R9)(R12*1), R11
+ MOVQ 8(R9)(R12*1), R13
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeBetterBlockAsm4MB
+ XORQ 8(R10)(R12*1), R13
+ JNZ matchlen_bsf_16match_nolit_encodeBetterBlockAsm4MB
+ LEAL -16(R8), R8
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_match_nolit_encodeBetterBlockAsm4MB
+
+matchlen_bsf_16match_nolit_encodeBetterBlockAsm4MB:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP match_nolit_end_encodeBetterBlockAsm4MB
+
+matchlen_match8_match_nolit_encodeBetterBlockAsm4MB:
+ CMPL R8, $0x08
+ JB matchlen_match4_match_nolit_encodeBetterBlockAsm4MB
+ MOVQ (R9)(R12*1), R11
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeBetterBlockAsm4MB
+ LEAL -8(R8), R8
+ LEAL 8(R12), R12
+ JMP matchlen_match4_match_nolit_encodeBetterBlockAsm4MB
+
+matchlen_bsf_8_match_nolit_encodeBetterBlockAsm4MB:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP match_nolit_end_encodeBetterBlockAsm4MB
+
+matchlen_match4_match_nolit_encodeBetterBlockAsm4MB:
+ CMPL R8, $0x04
+ JB matchlen_match2_match_nolit_encodeBetterBlockAsm4MB
+ MOVL (R9)(R12*1), R11
+ CMPL (R10)(R12*1), R11
+ JNE matchlen_match2_match_nolit_encodeBetterBlockAsm4MB
+ LEAL -4(R8), R8
+ LEAL 4(R12), R12
+
+matchlen_match2_match_nolit_encodeBetterBlockAsm4MB:
+ CMPL R8, $0x01
+ JE matchlen_match1_match_nolit_encodeBetterBlockAsm4MB
+ JB match_nolit_end_encodeBetterBlockAsm4MB
+ MOVW (R9)(R12*1), R11
+ CMPW (R10)(R12*1), R11
+ JNE matchlen_match1_match_nolit_encodeBetterBlockAsm4MB
+ LEAL 2(R12), R12
+ SUBL $0x02, R8
+ JZ match_nolit_end_encodeBetterBlockAsm4MB
+
+matchlen_match1_match_nolit_encodeBetterBlockAsm4MB:
+ MOVB (R9)(R12*1), R11
+ CMPB (R10)(R12*1), R11
+ JNE match_nolit_end_encodeBetterBlockAsm4MB
+ LEAL 1(R12), R12
+
+match_nolit_end_encodeBetterBlockAsm4MB:
+ MOVL DX, R8
+ SUBL SI, R8
+
+ // Check if repeat
+ CMPL 16(SP), R8
+ JEQ match_is_repeat_encodeBetterBlockAsm4MB
+ CMPL R12, $0x01
+ JA match_length_ok_encodeBetterBlockAsm4MB
+ CMPL R8, $0x0000ffff
+ JBE match_length_ok_encodeBetterBlockAsm4MB
+ MOVL 20(SP), DX
+ INCL DX
+ JMP search_loop_encodeBetterBlockAsm4MB
+
+match_length_ok_encodeBetterBlockAsm4MB:
+ MOVL R8, 16(SP)
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_encodeBetterBlockAsm4MB
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_encodeBetterBlockAsm4MB
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_encodeBetterBlockAsm4MB
+ CMPL SI, $0x00010000
+ JB three_bytes_match_emit_encodeBetterBlockAsm4MB
+ MOVL SI, R11
+ SHRL $0x10, R11
+ MOVB $0xf8, (CX)
+ MOVW SI, 1(CX)
+ MOVB R11, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_match_emit_encodeBetterBlockAsm4MB
+
+three_bytes_match_emit_encodeBetterBlockAsm4MB:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeBetterBlockAsm4MB
+
+two_bytes_match_emit_encodeBetterBlockAsm4MB:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_encodeBetterBlockAsm4MB
+ JMP memmove_long_match_emit_encodeBetterBlockAsm4MB
+
+one_byte_match_emit_encodeBetterBlockAsm4MB:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeBetterBlockAsm4MB:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x04
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm4MB_memmove_move_4
+ CMPQ R9, $0x08
+ JB emit_lit_memmove_match_emit_encodeBetterBlockAsm4MB_memmove_move_4through7
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm4MB_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm4MB_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeBetterBlockAsm4MB_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm4MB_memmove_move_4:
+ MOVL (R10), R11
+ MOVL R11, (CX)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm4MB_memmove_move_4through7:
+ MOVL (R10), R11
+ MOVL -4(R10)(R9*1), R10
+ MOVL R11, (CX)
+ MOVL R10, -4(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm4MB_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm4MB_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm4MB_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeBetterBlockAsm4MB:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_encodeBetterBlockAsm4MB
+
+memmove_long_match_emit_encodeBetterBlockAsm4MB:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_encodeBetterBlockAsm4MBlarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_encodeBetterBlockAsm4MBlarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_encodeBetterBlockAsm4MBlarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeBetterBlockAsm4MBlarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_encodeBetterBlockAsm4MBlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_encodeBetterBlockAsm4MB:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL R8, $0x00010000
+ JB two_byte_offset_match_nolit_encodeBetterBlockAsm4MB
+ CMPL R12, $0x40
+ JBE four_bytes_remain_match_nolit_encodeBetterBlockAsm4MB
+ MOVB $0xff, (CX)
+ MOVL R8, 1(CX)
+ LEAL -64(R12), R12
+ ADDQ $0x05, CX
+ CMPL R12, $0x04
+ JB four_bytes_remain_match_nolit_encodeBetterBlockAsm4MB
+
+ // emitRepeat
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBetterBlockAsm4MB_emit_copy
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy
+
+cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_encodeBetterBlockAsm4MB_emit_copy
+ CMPL R12, $0x00010100
+ JB repeat_four_match_nolit_encodeBetterBlockAsm4MB_emit_copy
+ LEAL -65536(R12), R12
+ MOVL R12, R8
+ MOVW $0x001d, (CX)
+ MOVW R12, 2(CX)
+ SARL $0x10, R8
+ MOVB R8, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_four_match_nolit_encodeBetterBlockAsm4MB_emit_copy:
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_three_match_nolit_encodeBetterBlockAsm4MB_emit_copy:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_two_match_nolit_encodeBetterBlockAsm4MB_emit_copy:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+four_bytes_remain_match_nolit_encodeBetterBlockAsm4MB:
+ TESTL R12, R12
+ JZ match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+ XORL SI, SI
+ LEAL -1(SI)(R12*4), R12
+ MOVB R12, (CX)
+ MOVL R8, 1(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+two_byte_offset_match_nolit_encodeBetterBlockAsm4MB:
+ CMPL R12, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeBetterBlockAsm4MB
+ CMPL R8, $0x00000800
+ JAE long_offset_short_match_nolit_encodeBetterBlockAsm4MB
+ MOVL $0x00000001, SI
+ LEAL 16(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, R12
+
+ // emitRepeat
+ LEAL -4(R12), R12
+ JMP cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short_2b
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short_2b
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short_2b
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short_2b
+
+cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short_2b:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short_2b
+ CMPL R12, $0x00010100
+ JB repeat_four_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short_2b
+ LEAL -65536(R12), R12
+ MOVL R12, R8
+ MOVW $0x001d, (CX)
+ MOVW R12, 2(CX)
+ SARL $0x10, R8
+ MOVB R8, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_four_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short_2b:
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_three_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short_2b:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_two_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short_2b:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short_2b:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+long_offset_short_match_nolit_encodeBetterBlockAsm4MB:
+ MOVB $0xee, (CX)
+ MOVW R8, 1(CX)
+ LEAL -60(R12), R12
+ ADDQ $0x03, CX
+
+ // emitRepeat
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short
+
+cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short
+ CMPL R12, $0x00010100
+ JB repeat_four_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short
+ LEAL -65536(R12), R12
+ MOVL R12, R8
+ MOVW $0x001d, (CX)
+ MOVW R12, 2(CX)
+ SARL $0x10, R8
+ MOVB R8, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_four_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short:
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_three_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_two_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_two_offset_match_nolit_encodeBetterBlockAsm4MB_emit_copy_short:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+two_byte_offset_short_match_nolit_encodeBetterBlockAsm4MB:
+ MOVL R12, SI
+ SHLL $0x02, SI
+ CMPL R12, $0x0c
+ JAE emit_copy_three_match_nolit_encodeBetterBlockAsm4MB
+ CMPL R8, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeBetterBlockAsm4MB
+ LEAL -15(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+emit_copy_three_match_nolit_encodeBetterBlockAsm4MB:
+ LEAL -2(SI), SI
+ MOVB SI, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+match_is_repeat_encodeBetterBlockAsm4MB:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_repeat_encodeBetterBlockAsm4MB
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_repeat_encodeBetterBlockAsm4MB
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_repeat_encodeBetterBlockAsm4MB
+ CMPL SI, $0x00010000
+ JB three_bytes_match_emit_repeat_encodeBetterBlockAsm4MB
+ MOVL SI, R11
+ SHRL $0x10, R11
+ MOVB $0xf8, (CX)
+ MOVW SI, 1(CX)
+ MOVB R11, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm4MB
+
+three_bytes_match_emit_repeat_encodeBetterBlockAsm4MB:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm4MB
+
+two_bytes_match_emit_repeat_encodeBetterBlockAsm4MB:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_repeat_encodeBetterBlockAsm4MB
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm4MB
+
+one_byte_match_emit_repeat_encodeBetterBlockAsm4MB:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_repeat_encodeBetterBlockAsm4MB:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x04
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm4MB_memmove_move_4
+ CMPQ R9, $0x08
+ JB emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm4MB_memmove_move_4through7
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm4MB_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm4MB_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm4MB_memmove_move_33through64
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm4MB_memmove_move_4:
+ MOVL (R10), R11
+ MOVL R11, (CX)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm4MB_memmove_move_4through7:
+ MOVL (R10), R11
+ MOVL -4(R10)(R9*1), R10
+ MOVL R11, (CX)
+ MOVL R10, -4(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm4MB_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm4MB_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm4MB_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm4MB:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_repeat_encodeBetterBlockAsm4MB
+
+memmove_long_match_emit_repeat_encodeBetterBlockAsm4MB:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm4MBlarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm4MBlarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm4MBlarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm4MBlarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm4MBlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_repeat_encodeBetterBlockAsm4MB:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitRepeat
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_repeat_encodeBetterBlockAsm4MB
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm4MB
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm4MB
+
+cant_repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm4MB:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_repeat_encodeBetterBlockAsm4MB
+ CMPL R12, $0x00010100
+ JB repeat_four_match_nolit_repeat_encodeBetterBlockAsm4MB
+ LEAL -65536(R12), R12
+ MOVL R12, R8
+ MOVW $0x001d, (CX)
+ MOVW R12, 2(CX)
+ SARL $0x10, R8
+ MOVB R8, 4(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_four_match_nolit_repeat_encodeBetterBlockAsm4MB:
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_three_match_nolit_repeat_encodeBetterBlockAsm4MB:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_two_match_nolit_repeat_encodeBetterBlockAsm4MB:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm4MB
+
+repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm4MB:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+
+match_nolit_emitcopy_end_encodeBetterBlockAsm4MB:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeBetterBlockAsm4MB
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeBetterBlockAsm4MB
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeBetterBlockAsm4MB:
+ MOVQ $0x00cf1bbcdcbfa563, SI
+ MOVQ $0x9e3779b1, R8
+ LEAQ 1(DI), DI
+ LEAQ -2(DX), R9
+ MOVQ (BX)(DI*1), R10
+ MOVQ 1(BX)(DI*1), R11
+ MOVQ (BX)(R9*1), R12
+ MOVQ 1(BX)(R9*1), R13
+ SHLQ $0x08, R10
+ IMULQ SI, R10
+ SHRQ $0x2f, R10
+ SHLQ $0x20, R11
+ IMULQ R8, R11
+ SHRQ $0x32, R11
+ SHLQ $0x08, R12
+ IMULQ SI, R12
+ SHRQ $0x2f, R12
+ SHLQ $0x20, R13
+ IMULQ R8, R13
+ SHRQ $0x32, R13
+ LEAQ 1(DI), R8
+ LEAQ 1(R9), R14
+ MOVL DI, (AX)(R10*4)
+ MOVL R9, (AX)(R12*4)
+ MOVL R8, 524288(AX)(R11*4)
+ MOVL R14, 524288(AX)(R13*4)
+ LEAQ 1(R9)(DI*1), R8
+ SHRQ $0x01, R8
+ ADDQ $0x01, DI
+ SUBQ $0x01, R9
+
+index_loop_encodeBetterBlockAsm4MB:
+ CMPQ R8, R9
+ JAE search_loop_encodeBetterBlockAsm4MB
+ MOVQ (BX)(DI*1), R10
+ MOVQ (BX)(R8*1), R11
+ SHLQ $0x08, R10
+ IMULQ SI, R10
+ SHRQ $0x2f, R10
+ SHLQ $0x08, R11
+ IMULQ SI, R11
+ SHRQ $0x2f, R11
+ MOVL DI, (AX)(R10*4)
+ MOVL R8, (AX)(R11*4)
+ ADDQ $0x02, DI
+ ADDQ $0x02, R8
+ JMP index_loop_encodeBetterBlockAsm4MB
+
+emit_remainder_encodeBetterBlockAsm4MB:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 4(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeBetterBlockAsm4MB
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeBetterBlockAsm4MB:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeBetterBlockAsm4MB
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeBetterBlockAsm4MB
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeBetterBlockAsm4MB
+ CMPL DX, $0x00010000
+ JB three_bytes_emit_remainder_encodeBetterBlockAsm4MB
+ MOVL DX, BX
+ SHRL $0x10, BX
+ MOVB $0xf8, (CX)
+ MOVW DX, 1(CX)
+ MOVB BL, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm4MB
+
+three_bytes_emit_remainder_encodeBetterBlockAsm4MB:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm4MB
+
+two_bytes_emit_remainder_encodeBetterBlockAsm4MB:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeBetterBlockAsm4MB
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm4MB
+
+one_byte_emit_remainder_encodeBetterBlockAsm4MB:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeBetterBlockAsm4MB:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeBetterBlockAsm4MB_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm4MB_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeBetterBlockAsm4MB_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm4MB_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm4MB_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeBetterBlockAsm4MB_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm4MB_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm4MB_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm4MB_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm4MB_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm4MB_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm4MB
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm4MB_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeBetterBlockAsm4MB:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeBetterBlockAsm4MB
+
+memmove_long_emit_remainder_encodeBetterBlockAsm4MB:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm4MBlarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm4MBlarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm4MBlarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm4MBlarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm4MBlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeBetterBlockAsm4MB:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeBetterBlockAsm12B(dst []byte, src []byte, tmp *[81920]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeBetterBlockAsm12B(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000280, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeBetterBlockAsm12B:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeBetterBlockAsm12B
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -6(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL $0x00000000, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeBetterBlockAsm12B:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x06, SI
+ LEAL 1(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeBetterBlockAsm12B
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ $0x9e3779b1, SI
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x32, R10
+ SHLQ $0x20, R11
+ IMULQ SI, R11
+ SHRQ $0x34, R11
+ MOVL (AX)(R10*4), SI
+ MOVL 65536(AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ MOVL DX, 65536(AX)(R11*4)
+ MOVQ (BX)(SI*1), R10
+ MOVQ (BX)(R8*1), R11
+ CMPQ R10, DI
+ JEQ candidate_match_encodeBetterBlockAsm12B
+ CMPQ R11, DI
+ JNE no_short_found_encodeBetterBlockAsm12B
+ MOVL R8, SI
+ JMP candidate_match_encodeBetterBlockAsm12B
+
+no_short_found_encodeBetterBlockAsm12B:
+ CMPL R10, DI
+ JEQ candidate_match_encodeBetterBlockAsm12B
+ CMPL R11, DI
+ JEQ candidateS_match_encodeBetterBlockAsm12B
+ MOVL 20(SP), DX
+ JMP search_loop_encodeBetterBlockAsm12B
+
+candidateS_match_encodeBetterBlockAsm12B:
+ SHRQ $0x08, DI
+ MOVQ DI, R10
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x32, R10
+ MOVL (AX)(R10*4), SI
+ INCL DX
+ MOVL DX, (AX)(R10*4)
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeBetterBlockAsm12B
+ DECL DX
+ MOVL R8, SI
+
+candidate_match_encodeBetterBlockAsm12B:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeBetterBlockAsm12B
+
+match_extend_back_loop_encodeBetterBlockAsm12B:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeBetterBlockAsm12B
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeBetterBlockAsm12B
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeBetterBlockAsm12B
+ JMP match_extend_back_loop_encodeBetterBlockAsm12B
+
+match_extend_back_end_encodeBetterBlockAsm12B:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeBetterBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeBetterBlockAsm12B:
+ MOVL DX, DI
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), R10
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_match_nolit_encodeBetterBlockAsm12B:
+ CMPL R8, $0x10
+ JB matchlen_match8_match_nolit_encodeBetterBlockAsm12B
+ MOVQ (R9)(R12*1), R11
+ MOVQ 8(R9)(R12*1), R13
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeBetterBlockAsm12B
+ XORQ 8(R10)(R12*1), R13
+ JNZ matchlen_bsf_16match_nolit_encodeBetterBlockAsm12B
+ LEAL -16(R8), R8
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_match_nolit_encodeBetterBlockAsm12B
+
+matchlen_bsf_16match_nolit_encodeBetterBlockAsm12B:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP match_nolit_end_encodeBetterBlockAsm12B
+
+matchlen_match8_match_nolit_encodeBetterBlockAsm12B:
+ CMPL R8, $0x08
+ JB matchlen_match4_match_nolit_encodeBetterBlockAsm12B
+ MOVQ (R9)(R12*1), R11
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeBetterBlockAsm12B
+ LEAL -8(R8), R8
+ LEAL 8(R12), R12
+ JMP matchlen_match4_match_nolit_encodeBetterBlockAsm12B
+
+matchlen_bsf_8_match_nolit_encodeBetterBlockAsm12B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP match_nolit_end_encodeBetterBlockAsm12B
+
+matchlen_match4_match_nolit_encodeBetterBlockAsm12B:
+ CMPL R8, $0x04
+ JB matchlen_match2_match_nolit_encodeBetterBlockAsm12B
+ MOVL (R9)(R12*1), R11
+ CMPL (R10)(R12*1), R11
+ JNE matchlen_match2_match_nolit_encodeBetterBlockAsm12B
+ LEAL -4(R8), R8
+ LEAL 4(R12), R12
+
+matchlen_match2_match_nolit_encodeBetterBlockAsm12B:
+ CMPL R8, $0x01
+ JE matchlen_match1_match_nolit_encodeBetterBlockAsm12B
+ JB match_nolit_end_encodeBetterBlockAsm12B
+ MOVW (R9)(R12*1), R11
+ CMPW (R10)(R12*1), R11
+ JNE matchlen_match1_match_nolit_encodeBetterBlockAsm12B
+ LEAL 2(R12), R12
+ SUBL $0x02, R8
+ JZ match_nolit_end_encodeBetterBlockAsm12B
+
+matchlen_match1_match_nolit_encodeBetterBlockAsm12B:
+ MOVB (R9)(R12*1), R11
+ CMPB (R10)(R12*1), R11
+ JNE match_nolit_end_encodeBetterBlockAsm12B
+ LEAL 1(R12), R12
+
+match_nolit_end_encodeBetterBlockAsm12B:
+ MOVL DX, R8
+ SUBL SI, R8
+
+ // Check if repeat
+ CMPL 16(SP), R8
+ JEQ match_is_repeat_encodeBetterBlockAsm12B
+ MOVL R8, 16(SP)
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_encodeBetterBlockAsm12B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_encodeBetterBlockAsm12B
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_encodeBetterBlockAsm12B
+ JB three_bytes_match_emit_encodeBetterBlockAsm12B
+
+three_bytes_match_emit_encodeBetterBlockAsm12B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeBetterBlockAsm12B
+
+two_bytes_match_emit_encodeBetterBlockAsm12B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_encodeBetterBlockAsm12B
+ JMP memmove_long_match_emit_encodeBetterBlockAsm12B
+
+one_byte_match_emit_encodeBetterBlockAsm12B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeBetterBlockAsm12B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x04
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm12B_memmove_move_4
+ CMPQ R9, $0x08
+ JB emit_lit_memmove_match_emit_encodeBetterBlockAsm12B_memmove_move_4through7
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm12B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm12B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeBetterBlockAsm12B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm12B_memmove_move_4:
+ MOVL (R10), R11
+ MOVL R11, (CX)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm12B_memmove_move_4through7:
+ MOVL (R10), R11
+ MOVL -4(R10)(R9*1), R10
+ MOVL R11, (CX)
+ MOVL R10, -4(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm12B_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm12B_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm12B_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeBetterBlockAsm12B:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_encodeBetterBlockAsm12B
+
+memmove_long_match_emit_encodeBetterBlockAsm12B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_encodeBetterBlockAsm12Blarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_encodeBetterBlockAsm12Blarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_encodeBetterBlockAsm12Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeBetterBlockAsm12Blarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_encodeBetterBlockAsm12Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_encodeBetterBlockAsm12B:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL R12, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeBetterBlockAsm12B
+ CMPL R8, $0x00000800
+ JAE long_offset_short_match_nolit_encodeBetterBlockAsm12B
+ MOVL $0x00000001, SI
+ LEAL 16(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, R12
+
+ // emitRepeat
+ LEAL -4(R12), R12
+ JMP cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm12B_emit_copy_short_2b
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBetterBlockAsm12B_emit_copy_short_2b
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm12B_emit_copy_short_2b
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBetterBlockAsm12B_emit_copy_short_2b
+
+cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm12B_emit_copy_short_2b:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_encodeBetterBlockAsm12B_emit_copy_short_2b
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+repeat_three_match_nolit_encodeBetterBlockAsm12B_emit_copy_short_2b:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+repeat_two_match_nolit_encodeBetterBlockAsm12B_emit_copy_short_2b:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+repeat_two_offset_match_nolit_encodeBetterBlockAsm12B_emit_copy_short_2b:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+long_offset_short_match_nolit_encodeBetterBlockAsm12B:
+ MOVB $0xee, (CX)
+ MOVW R8, 1(CX)
+ LEAL -60(R12), R12
+ ADDQ $0x03, CX
+
+ // emitRepeat
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBetterBlockAsm12B_emit_copy_short
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm12B_emit_copy_short
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBetterBlockAsm12B_emit_copy_short
+
+cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm12B_emit_copy_short:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_encodeBetterBlockAsm12B_emit_copy_short
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+repeat_three_match_nolit_encodeBetterBlockAsm12B_emit_copy_short:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+repeat_two_match_nolit_encodeBetterBlockAsm12B_emit_copy_short:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+repeat_two_offset_match_nolit_encodeBetterBlockAsm12B_emit_copy_short:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+two_byte_offset_short_match_nolit_encodeBetterBlockAsm12B:
+ MOVL R12, SI
+ SHLL $0x02, SI
+ CMPL R12, $0x0c
+ JAE emit_copy_three_match_nolit_encodeBetterBlockAsm12B
+ CMPL R8, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeBetterBlockAsm12B
+ LEAL -15(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+emit_copy_three_match_nolit_encodeBetterBlockAsm12B:
+ LEAL -2(SI), SI
+ MOVB SI, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+match_is_repeat_encodeBetterBlockAsm12B:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_repeat_encodeBetterBlockAsm12B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_repeat_encodeBetterBlockAsm12B
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_repeat_encodeBetterBlockAsm12B
+ JB three_bytes_match_emit_repeat_encodeBetterBlockAsm12B
+
+three_bytes_match_emit_repeat_encodeBetterBlockAsm12B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm12B
+
+two_bytes_match_emit_repeat_encodeBetterBlockAsm12B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_repeat_encodeBetterBlockAsm12B
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm12B
+
+one_byte_match_emit_repeat_encodeBetterBlockAsm12B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_repeat_encodeBetterBlockAsm12B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x04
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm12B_memmove_move_4
+ CMPQ R9, $0x08
+ JB emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm12B_memmove_move_4through7
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm12B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm12B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm12B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm12B_memmove_move_4:
+ MOVL (R10), R11
+ MOVL R11, (CX)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm12B
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm12B_memmove_move_4through7:
+ MOVL (R10), R11
+ MOVL -4(R10)(R9*1), R10
+ MOVL R11, (CX)
+ MOVL R10, -4(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm12B
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm12B_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm12B
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm12B_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm12B
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm12B_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm12B:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_repeat_encodeBetterBlockAsm12B
+
+memmove_long_match_emit_repeat_encodeBetterBlockAsm12B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm12Blarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm12Blarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm12Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm12Blarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm12Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_repeat_encodeBetterBlockAsm12B:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitRepeat
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_repeat_encodeBetterBlockAsm12B
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm12B
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm12B
+
+cant_repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm12B:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_repeat_encodeBetterBlockAsm12B
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+repeat_three_match_nolit_repeat_encodeBetterBlockAsm12B:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+repeat_two_match_nolit_repeat_encodeBetterBlockAsm12B:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm12B
+
+repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm12B:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+
+match_nolit_emitcopy_end_encodeBetterBlockAsm12B:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeBetterBlockAsm12B
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeBetterBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeBetterBlockAsm12B:
+ MOVQ $0x0000cf1bbcdcbf9b, SI
+ MOVQ $0x9e3779b1, R8
+ LEAQ 1(DI), DI
+ LEAQ -2(DX), R9
+ MOVQ (BX)(DI*1), R10
+ MOVQ 1(BX)(DI*1), R11
+ MOVQ (BX)(R9*1), R12
+ MOVQ 1(BX)(R9*1), R13
+ SHLQ $0x10, R10
+ IMULQ SI, R10
+ SHRQ $0x32, R10
+ SHLQ $0x20, R11
+ IMULQ R8, R11
+ SHRQ $0x34, R11
+ SHLQ $0x10, R12
+ IMULQ SI, R12
+ SHRQ $0x32, R12
+ SHLQ $0x20, R13
+ IMULQ R8, R13
+ SHRQ $0x34, R13
+ LEAQ 1(DI), R8
+ LEAQ 1(R9), R14
+ MOVL DI, (AX)(R10*4)
+ MOVL R9, (AX)(R12*4)
+ MOVL R8, 65536(AX)(R11*4)
+ MOVL R14, 65536(AX)(R13*4)
+ LEAQ 1(R9)(DI*1), R8
+ SHRQ $0x01, R8
+ ADDQ $0x01, DI
+ SUBQ $0x01, R9
+
+index_loop_encodeBetterBlockAsm12B:
+ CMPQ R8, R9
+ JAE search_loop_encodeBetterBlockAsm12B
+ MOVQ (BX)(DI*1), R10
+ MOVQ (BX)(R8*1), R11
+ SHLQ $0x10, R10
+ IMULQ SI, R10
+ SHRQ $0x32, R10
+ SHLQ $0x10, R11
+ IMULQ SI, R11
+ SHRQ $0x32, R11
+ MOVL DI, (AX)(R10*4)
+ MOVL R8, (AX)(R11*4)
+ ADDQ $0x02, DI
+ ADDQ $0x02, R8
+ JMP index_loop_encodeBetterBlockAsm12B
+
+emit_remainder_encodeBetterBlockAsm12B:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeBetterBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeBetterBlockAsm12B:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeBetterBlockAsm12B
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeBetterBlockAsm12B
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeBetterBlockAsm12B
+ JB three_bytes_emit_remainder_encodeBetterBlockAsm12B
+
+three_bytes_emit_remainder_encodeBetterBlockAsm12B:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm12B
+
+two_bytes_emit_remainder_encodeBetterBlockAsm12B:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeBetterBlockAsm12B
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm12B
+
+one_byte_emit_remainder_encodeBetterBlockAsm12B:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeBetterBlockAsm12B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeBetterBlockAsm12B_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm12B_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeBetterBlockAsm12B_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm12B_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm12B_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeBetterBlockAsm12B_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm12B_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm12B_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm12B_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm12B_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm12B_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm12B_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeBetterBlockAsm12B:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeBetterBlockAsm12B
+
+memmove_long_emit_remainder_encodeBetterBlockAsm12B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm12Blarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm12Blarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm12Blarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm12Blarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm12Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeBetterBlockAsm12B:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeBetterBlockAsm10B(dst []byte, src []byte, tmp *[20480]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeBetterBlockAsm10B(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x000000a0, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeBetterBlockAsm10B:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeBetterBlockAsm10B
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -6(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL $0x00000000, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeBetterBlockAsm10B:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x05, SI
+ LEAL 1(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeBetterBlockAsm10B
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ $0x9e3779b1, SI
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x34, R10
+ SHLQ $0x20, R11
+ IMULQ SI, R11
+ SHRQ $0x36, R11
+ MOVL (AX)(R10*4), SI
+ MOVL 16384(AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ MOVL DX, 16384(AX)(R11*4)
+ MOVQ (BX)(SI*1), R10
+ MOVQ (BX)(R8*1), R11
+ CMPQ R10, DI
+ JEQ candidate_match_encodeBetterBlockAsm10B
+ CMPQ R11, DI
+ JNE no_short_found_encodeBetterBlockAsm10B
+ MOVL R8, SI
+ JMP candidate_match_encodeBetterBlockAsm10B
+
+no_short_found_encodeBetterBlockAsm10B:
+ CMPL R10, DI
+ JEQ candidate_match_encodeBetterBlockAsm10B
+ CMPL R11, DI
+ JEQ candidateS_match_encodeBetterBlockAsm10B
+ MOVL 20(SP), DX
+ JMP search_loop_encodeBetterBlockAsm10B
+
+candidateS_match_encodeBetterBlockAsm10B:
+ SHRQ $0x08, DI
+ MOVQ DI, R10
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x34, R10
+ MOVL (AX)(R10*4), SI
+ INCL DX
+ MOVL DX, (AX)(R10*4)
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeBetterBlockAsm10B
+ DECL DX
+ MOVL R8, SI
+
+candidate_match_encodeBetterBlockAsm10B:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeBetterBlockAsm10B
+
+match_extend_back_loop_encodeBetterBlockAsm10B:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeBetterBlockAsm10B
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeBetterBlockAsm10B
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeBetterBlockAsm10B
+ JMP match_extend_back_loop_encodeBetterBlockAsm10B
+
+match_extend_back_end_encodeBetterBlockAsm10B:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeBetterBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeBetterBlockAsm10B:
+ MOVL DX, DI
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), R10
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_match_nolit_encodeBetterBlockAsm10B:
+ CMPL R8, $0x10
+ JB matchlen_match8_match_nolit_encodeBetterBlockAsm10B
+ MOVQ (R9)(R12*1), R11
+ MOVQ 8(R9)(R12*1), R13
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeBetterBlockAsm10B
+ XORQ 8(R10)(R12*1), R13
+ JNZ matchlen_bsf_16match_nolit_encodeBetterBlockAsm10B
+ LEAL -16(R8), R8
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_match_nolit_encodeBetterBlockAsm10B
+
+matchlen_bsf_16match_nolit_encodeBetterBlockAsm10B:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP match_nolit_end_encodeBetterBlockAsm10B
+
+matchlen_match8_match_nolit_encodeBetterBlockAsm10B:
+ CMPL R8, $0x08
+ JB matchlen_match4_match_nolit_encodeBetterBlockAsm10B
+ MOVQ (R9)(R12*1), R11
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeBetterBlockAsm10B
+ LEAL -8(R8), R8
+ LEAL 8(R12), R12
+ JMP matchlen_match4_match_nolit_encodeBetterBlockAsm10B
+
+matchlen_bsf_8_match_nolit_encodeBetterBlockAsm10B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP match_nolit_end_encodeBetterBlockAsm10B
+
+matchlen_match4_match_nolit_encodeBetterBlockAsm10B:
+ CMPL R8, $0x04
+ JB matchlen_match2_match_nolit_encodeBetterBlockAsm10B
+ MOVL (R9)(R12*1), R11
+ CMPL (R10)(R12*1), R11
+ JNE matchlen_match2_match_nolit_encodeBetterBlockAsm10B
+ LEAL -4(R8), R8
+ LEAL 4(R12), R12
+
+matchlen_match2_match_nolit_encodeBetterBlockAsm10B:
+ CMPL R8, $0x01
+ JE matchlen_match1_match_nolit_encodeBetterBlockAsm10B
+ JB match_nolit_end_encodeBetterBlockAsm10B
+ MOVW (R9)(R12*1), R11
+ CMPW (R10)(R12*1), R11
+ JNE matchlen_match1_match_nolit_encodeBetterBlockAsm10B
+ LEAL 2(R12), R12
+ SUBL $0x02, R8
+ JZ match_nolit_end_encodeBetterBlockAsm10B
+
+matchlen_match1_match_nolit_encodeBetterBlockAsm10B:
+ MOVB (R9)(R12*1), R11
+ CMPB (R10)(R12*1), R11
+ JNE match_nolit_end_encodeBetterBlockAsm10B
+ LEAL 1(R12), R12
+
+match_nolit_end_encodeBetterBlockAsm10B:
+ MOVL DX, R8
+ SUBL SI, R8
+
+ // Check if repeat
+ CMPL 16(SP), R8
+ JEQ match_is_repeat_encodeBetterBlockAsm10B
+ MOVL R8, 16(SP)
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_encodeBetterBlockAsm10B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_encodeBetterBlockAsm10B
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_encodeBetterBlockAsm10B
+ JB three_bytes_match_emit_encodeBetterBlockAsm10B
+
+three_bytes_match_emit_encodeBetterBlockAsm10B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeBetterBlockAsm10B
+
+two_bytes_match_emit_encodeBetterBlockAsm10B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_encodeBetterBlockAsm10B
+ JMP memmove_long_match_emit_encodeBetterBlockAsm10B
+
+one_byte_match_emit_encodeBetterBlockAsm10B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeBetterBlockAsm10B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x04
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm10B_memmove_move_4
+ CMPQ R9, $0x08
+ JB emit_lit_memmove_match_emit_encodeBetterBlockAsm10B_memmove_move_4through7
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm10B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm10B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeBetterBlockAsm10B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm10B_memmove_move_4:
+ MOVL (R10), R11
+ MOVL R11, (CX)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm10B_memmove_move_4through7:
+ MOVL (R10), R11
+ MOVL -4(R10)(R9*1), R10
+ MOVL R11, (CX)
+ MOVL R10, -4(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm10B_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm10B_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm10B_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeBetterBlockAsm10B:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_encodeBetterBlockAsm10B
+
+memmove_long_match_emit_encodeBetterBlockAsm10B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_encodeBetterBlockAsm10Blarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_encodeBetterBlockAsm10Blarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_encodeBetterBlockAsm10Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeBetterBlockAsm10Blarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_encodeBetterBlockAsm10Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_encodeBetterBlockAsm10B:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL R12, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeBetterBlockAsm10B
+ CMPL R8, $0x00000800
+ JAE long_offset_short_match_nolit_encodeBetterBlockAsm10B
+ MOVL $0x00000001, SI
+ LEAL 16(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, R12
+
+ // emitRepeat
+ LEAL -4(R12), R12
+ JMP cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm10B_emit_copy_short_2b
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBetterBlockAsm10B_emit_copy_short_2b
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm10B_emit_copy_short_2b
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBetterBlockAsm10B_emit_copy_short_2b
+
+cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm10B_emit_copy_short_2b:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_encodeBetterBlockAsm10B_emit_copy_short_2b
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+repeat_three_match_nolit_encodeBetterBlockAsm10B_emit_copy_short_2b:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+repeat_two_match_nolit_encodeBetterBlockAsm10B_emit_copy_short_2b:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+repeat_two_offset_match_nolit_encodeBetterBlockAsm10B_emit_copy_short_2b:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+long_offset_short_match_nolit_encodeBetterBlockAsm10B:
+ MOVB $0xee, (CX)
+ MOVW R8, 1(CX)
+ LEAL -60(R12), R12
+ ADDQ $0x03, CX
+
+ // emitRepeat
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBetterBlockAsm10B_emit_copy_short
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm10B_emit_copy_short
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_encodeBetterBlockAsm10B_emit_copy_short
+
+cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm10B_emit_copy_short:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_encodeBetterBlockAsm10B_emit_copy_short
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+repeat_three_match_nolit_encodeBetterBlockAsm10B_emit_copy_short:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+repeat_two_match_nolit_encodeBetterBlockAsm10B_emit_copy_short:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+repeat_two_offset_match_nolit_encodeBetterBlockAsm10B_emit_copy_short:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+two_byte_offset_short_match_nolit_encodeBetterBlockAsm10B:
+ MOVL R12, SI
+ SHLL $0x02, SI
+ CMPL R12, $0x0c
+ JAE emit_copy_three_match_nolit_encodeBetterBlockAsm10B
+ CMPL R8, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeBetterBlockAsm10B
+ LEAL -15(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+emit_copy_three_match_nolit_encodeBetterBlockAsm10B:
+ LEAL -2(SI), SI
+ MOVB SI, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+match_is_repeat_encodeBetterBlockAsm10B:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_repeat_encodeBetterBlockAsm10B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_repeat_encodeBetterBlockAsm10B
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_repeat_encodeBetterBlockAsm10B
+ JB three_bytes_match_emit_repeat_encodeBetterBlockAsm10B
+
+three_bytes_match_emit_repeat_encodeBetterBlockAsm10B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm10B
+
+two_bytes_match_emit_repeat_encodeBetterBlockAsm10B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_repeat_encodeBetterBlockAsm10B
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm10B
+
+one_byte_match_emit_repeat_encodeBetterBlockAsm10B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_repeat_encodeBetterBlockAsm10B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x04
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm10B_memmove_move_4
+ CMPQ R9, $0x08
+ JB emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm10B_memmove_move_4through7
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm10B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm10B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm10B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm10B_memmove_move_4:
+ MOVL (R10), R11
+ MOVL R11, (CX)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm10B
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm10B_memmove_move_4through7:
+ MOVL (R10), R11
+ MOVL -4(R10)(R9*1), R10
+ MOVL R11, (CX)
+ MOVL R10, -4(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm10B
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm10B_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm10B
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm10B_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm10B
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm10B_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm10B:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_repeat_encodeBetterBlockAsm10B
+
+memmove_long_match_emit_repeat_encodeBetterBlockAsm10B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm10Blarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm10Blarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm10Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm10Blarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm10Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_repeat_encodeBetterBlockAsm10B:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitRepeat
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_repeat_encodeBetterBlockAsm10B
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm10B
+ CMPL R8, $0x00000800
+ JB repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm10B
+
+cant_repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm10B:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_repeat_encodeBetterBlockAsm10B
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+repeat_three_match_nolit_repeat_encodeBetterBlockAsm10B:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+repeat_two_match_nolit_repeat_encodeBetterBlockAsm10B:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm10B
+
+repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm10B:
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+
+match_nolit_emitcopy_end_encodeBetterBlockAsm10B:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeBetterBlockAsm10B
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeBetterBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeBetterBlockAsm10B:
+ MOVQ $0x0000cf1bbcdcbf9b, SI
+ MOVQ $0x9e3779b1, R8
+ LEAQ 1(DI), DI
+ LEAQ -2(DX), R9
+ MOVQ (BX)(DI*1), R10
+ MOVQ 1(BX)(DI*1), R11
+ MOVQ (BX)(R9*1), R12
+ MOVQ 1(BX)(R9*1), R13
+ SHLQ $0x10, R10
+ IMULQ SI, R10
+ SHRQ $0x34, R10
+ SHLQ $0x20, R11
+ IMULQ R8, R11
+ SHRQ $0x36, R11
+ SHLQ $0x10, R12
+ IMULQ SI, R12
+ SHRQ $0x34, R12
+ SHLQ $0x20, R13
+ IMULQ R8, R13
+ SHRQ $0x36, R13
+ LEAQ 1(DI), R8
+ LEAQ 1(R9), R14
+ MOVL DI, (AX)(R10*4)
+ MOVL R9, (AX)(R12*4)
+ MOVL R8, 16384(AX)(R11*4)
+ MOVL R14, 16384(AX)(R13*4)
+ LEAQ 1(R9)(DI*1), R8
+ SHRQ $0x01, R8
+ ADDQ $0x01, DI
+ SUBQ $0x01, R9
+
+index_loop_encodeBetterBlockAsm10B:
+ CMPQ R8, R9
+ JAE search_loop_encodeBetterBlockAsm10B
+ MOVQ (BX)(DI*1), R10
+ MOVQ (BX)(R8*1), R11
+ SHLQ $0x10, R10
+ IMULQ SI, R10
+ SHRQ $0x34, R10
+ SHLQ $0x10, R11
+ IMULQ SI, R11
+ SHRQ $0x34, R11
+ MOVL DI, (AX)(R10*4)
+ MOVL R8, (AX)(R11*4)
+ ADDQ $0x02, DI
+ ADDQ $0x02, R8
+ JMP index_loop_encodeBetterBlockAsm10B
+
+emit_remainder_encodeBetterBlockAsm10B:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeBetterBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeBetterBlockAsm10B:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeBetterBlockAsm10B
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeBetterBlockAsm10B
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeBetterBlockAsm10B
+ JB three_bytes_emit_remainder_encodeBetterBlockAsm10B
+
+three_bytes_emit_remainder_encodeBetterBlockAsm10B:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm10B
+
+two_bytes_emit_remainder_encodeBetterBlockAsm10B:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeBetterBlockAsm10B
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm10B
+
+one_byte_emit_remainder_encodeBetterBlockAsm10B:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeBetterBlockAsm10B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeBetterBlockAsm10B_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm10B_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeBetterBlockAsm10B_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm10B_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm10B_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeBetterBlockAsm10B_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm10B_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm10B_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm10B_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm10B_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm10B_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm10B_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeBetterBlockAsm10B:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeBetterBlockAsm10B
+
+memmove_long_emit_remainder_encodeBetterBlockAsm10B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm10Blarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm10Blarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm10Blarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm10Blarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm10Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeBetterBlockAsm10B:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeBetterBlockAsm8B(dst []byte, src []byte, tmp *[5120]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeBetterBlockAsm8B(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000028, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeBetterBlockAsm8B:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeBetterBlockAsm8B
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -6(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL $0x00000000, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeBetterBlockAsm8B:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x04, SI
+ LEAL 1(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeBetterBlockAsm8B
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ $0x9e3779b1, SI
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x36, R10
+ SHLQ $0x20, R11
+ IMULQ SI, R11
+ SHRQ $0x38, R11
+ MOVL (AX)(R10*4), SI
+ MOVL 4096(AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ MOVL DX, 4096(AX)(R11*4)
+ MOVQ (BX)(SI*1), R10
+ MOVQ (BX)(R8*1), R11
+ CMPQ R10, DI
+ JEQ candidate_match_encodeBetterBlockAsm8B
+ CMPQ R11, DI
+ JNE no_short_found_encodeBetterBlockAsm8B
+ MOVL R8, SI
+ JMP candidate_match_encodeBetterBlockAsm8B
+
+no_short_found_encodeBetterBlockAsm8B:
+ CMPL R10, DI
+ JEQ candidate_match_encodeBetterBlockAsm8B
+ CMPL R11, DI
+ JEQ candidateS_match_encodeBetterBlockAsm8B
+ MOVL 20(SP), DX
+ JMP search_loop_encodeBetterBlockAsm8B
+
+candidateS_match_encodeBetterBlockAsm8B:
+ SHRQ $0x08, DI
+ MOVQ DI, R10
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x36, R10
+ MOVL (AX)(R10*4), SI
+ INCL DX
+ MOVL DX, (AX)(R10*4)
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeBetterBlockAsm8B
+ DECL DX
+ MOVL R8, SI
+
+candidate_match_encodeBetterBlockAsm8B:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeBetterBlockAsm8B
+
+match_extend_back_loop_encodeBetterBlockAsm8B:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeBetterBlockAsm8B
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeBetterBlockAsm8B
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeBetterBlockAsm8B
+ JMP match_extend_back_loop_encodeBetterBlockAsm8B
+
+match_extend_back_end_encodeBetterBlockAsm8B:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeBetterBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeBetterBlockAsm8B:
+ MOVL DX, DI
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), R10
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_match_nolit_encodeBetterBlockAsm8B:
+ CMPL R8, $0x10
+ JB matchlen_match8_match_nolit_encodeBetterBlockAsm8B
+ MOVQ (R9)(R12*1), R11
+ MOVQ 8(R9)(R12*1), R13
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeBetterBlockAsm8B
+ XORQ 8(R10)(R12*1), R13
+ JNZ matchlen_bsf_16match_nolit_encodeBetterBlockAsm8B
+ LEAL -16(R8), R8
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_match_nolit_encodeBetterBlockAsm8B
+
+matchlen_bsf_16match_nolit_encodeBetterBlockAsm8B:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP match_nolit_end_encodeBetterBlockAsm8B
+
+matchlen_match8_match_nolit_encodeBetterBlockAsm8B:
+ CMPL R8, $0x08
+ JB matchlen_match4_match_nolit_encodeBetterBlockAsm8B
+ MOVQ (R9)(R12*1), R11
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeBetterBlockAsm8B
+ LEAL -8(R8), R8
+ LEAL 8(R12), R12
+ JMP matchlen_match4_match_nolit_encodeBetterBlockAsm8B
+
+matchlen_bsf_8_match_nolit_encodeBetterBlockAsm8B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP match_nolit_end_encodeBetterBlockAsm8B
+
+matchlen_match4_match_nolit_encodeBetterBlockAsm8B:
+ CMPL R8, $0x04
+ JB matchlen_match2_match_nolit_encodeBetterBlockAsm8B
+ MOVL (R9)(R12*1), R11
+ CMPL (R10)(R12*1), R11
+ JNE matchlen_match2_match_nolit_encodeBetterBlockAsm8B
+ LEAL -4(R8), R8
+ LEAL 4(R12), R12
+
+matchlen_match2_match_nolit_encodeBetterBlockAsm8B:
+ CMPL R8, $0x01
+ JE matchlen_match1_match_nolit_encodeBetterBlockAsm8B
+ JB match_nolit_end_encodeBetterBlockAsm8B
+ MOVW (R9)(R12*1), R11
+ CMPW (R10)(R12*1), R11
+ JNE matchlen_match1_match_nolit_encodeBetterBlockAsm8B
+ LEAL 2(R12), R12
+ SUBL $0x02, R8
+ JZ match_nolit_end_encodeBetterBlockAsm8B
+
+matchlen_match1_match_nolit_encodeBetterBlockAsm8B:
+ MOVB (R9)(R12*1), R11
+ CMPB (R10)(R12*1), R11
+ JNE match_nolit_end_encodeBetterBlockAsm8B
+ LEAL 1(R12), R12
+
+match_nolit_end_encodeBetterBlockAsm8B:
+ MOVL DX, R8
+ SUBL SI, R8
+
+ // Check if repeat
+ CMPL 16(SP), R8
+ JEQ match_is_repeat_encodeBetterBlockAsm8B
+ MOVL R8, 16(SP)
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_encodeBetterBlockAsm8B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_encodeBetterBlockAsm8B
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_encodeBetterBlockAsm8B
+ JB three_bytes_match_emit_encodeBetterBlockAsm8B
+
+three_bytes_match_emit_encodeBetterBlockAsm8B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeBetterBlockAsm8B
+
+two_bytes_match_emit_encodeBetterBlockAsm8B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_encodeBetterBlockAsm8B
+ JMP memmove_long_match_emit_encodeBetterBlockAsm8B
+
+one_byte_match_emit_encodeBetterBlockAsm8B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeBetterBlockAsm8B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x04
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm8B_memmove_move_4
+ CMPQ R9, $0x08
+ JB emit_lit_memmove_match_emit_encodeBetterBlockAsm8B_memmove_move_4through7
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm8B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeBetterBlockAsm8B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeBetterBlockAsm8B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm8B_memmove_move_4:
+ MOVL (R10), R11
+ MOVL R11, (CX)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm8B_memmove_move_4through7:
+ MOVL (R10), R11
+ MOVL -4(R10)(R9*1), R10
+ MOVL R11, (CX)
+ MOVL R10, -4(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm8B_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm8B_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeBetterBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeBetterBlockAsm8B_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeBetterBlockAsm8B:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_encodeBetterBlockAsm8B
+
+memmove_long_match_emit_encodeBetterBlockAsm8B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_encodeBetterBlockAsm8Blarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_encodeBetterBlockAsm8Blarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_encodeBetterBlockAsm8Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeBetterBlockAsm8Blarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_encodeBetterBlockAsm8Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_encodeBetterBlockAsm8B:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL R12, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeBetterBlockAsm8B
+ CMPL R8, $0x00000800
+ JAE long_offset_short_match_nolit_encodeBetterBlockAsm8B
+ MOVL $0x00000001, SI
+ LEAL 16(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ SUBL $0x08, R12
+
+ // emitRepeat
+ LEAL -4(R12), R12
+ JMP cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm8B_emit_copy_short_2b
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBetterBlockAsm8B_emit_copy_short_2b
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm8B_emit_copy_short_2b
+
+cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm8B_emit_copy_short_2b:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_encodeBetterBlockAsm8B_emit_copy_short_2b
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+
+repeat_three_match_nolit_encodeBetterBlockAsm8B_emit_copy_short_2b:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+
+repeat_two_match_nolit_encodeBetterBlockAsm8B_emit_copy_short_2b:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+
+long_offset_short_match_nolit_encodeBetterBlockAsm8B:
+ MOVB $0xee, (CX)
+ MOVW R8, 1(CX)
+ LEAL -60(R12), R12
+ ADDQ $0x03, CX
+
+ // emitRepeat
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_encodeBetterBlockAsm8B_emit_copy_short
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm8B_emit_copy_short
+
+cant_repeat_two_offset_match_nolit_encodeBetterBlockAsm8B_emit_copy_short:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_encodeBetterBlockAsm8B_emit_copy_short
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+
+repeat_three_match_nolit_encodeBetterBlockAsm8B_emit_copy_short:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+
+repeat_two_match_nolit_encodeBetterBlockAsm8B_emit_copy_short:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+
+two_byte_offset_short_match_nolit_encodeBetterBlockAsm8B:
+ MOVL R12, SI
+ SHLL $0x02, SI
+ CMPL R12, $0x0c
+ JAE emit_copy_three_match_nolit_encodeBetterBlockAsm8B
+ LEAL -15(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+
+emit_copy_three_match_nolit_encodeBetterBlockAsm8B:
+ LEAL -2(SI), SI
+ MOVB SI, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+
+match_is_repeat_encodeBetterBlockAsm8B:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_repeat_encodeBetterBlockAsm8B
+ MOVL DI, R8
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R9
+ SUBL SI, R8
+ LEAL -1(R8), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_repeat_encodeBetterBlockAsm8B
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_repeat_encodeBetterBlockAsm8B
+ JB three_bytes_match_emit_repeat_encodeBetterBlockAsm8B
+
+three_bytes_match_emit_repeat_encodeBetterBlockAsm8B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm8B
+
+two_bytes_match_emit_repeat_encodeBetterBlockAsm8B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_repeat_encodeBetterBlockAsm8B
+ JMP memmove_long_match_emit_repeat_encodeBetterBlockAsm8B
+
+one_byte_match_emit_repeat_encodeBetterBlockAsm8B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_repeat_encodeBetterBlockAsm8B:
+ LEAQ (CX)(R8*1), SI
+
+ // genMemMoveShort
+ CMPQ R8, $0x04
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm8B_memmove_move_4
+ CMPQ R8, $0x08
+ JB emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm8B_memmove_move_4through7
+ CMPQ R8, $0x10
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm8B_memmove_move_8through16
+ CMPQ R8, $0x20
+ JBE emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm8B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm8B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm8B_memmove_move_4:
+ MOVL (R9), R10
+ MOVL R10, (CX)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm8B
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm8B_memmove_move_4through7:
+ MOVL (R9), R10
+ MOVL -4(R9)(R8*1), R9
+ MOVL R10, (CX)
+ MOVL R9, -4(CX)(R8*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm8B
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm8B_memmove_move_8through16:
+ MOVQ (R9), R10
+ MOVQ -8(R9)(R8*1), R9
+ MOVQ R10, (CX)
+ MOVQ R9, -8(CX)(R8*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm8B
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm8B_memmove_move_17through32:
+ MOVOU (R9), X0
+ MOVOU -16(R9)(R8*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R8*1)
+ JMP memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm8B
+
+emit_lit_memmove_match_emit_repeat_encodeBetterBlockAsm8B_memmove_move_33through64:
+ MOVOU (R9), X0
+ MOVOU 16(R9), X1
+ MOVOU -32(R9)(R8*1), X2
+ MOVOU -16(R9)(R8*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R8*1)
+ MOVOU X3, -16(CX)(R8*1)
+
+memmove_end_copy_match_emit_repeat_encodeBetterBlockAsm8B:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_repeat_encodeBetterBlockAsm8B
+
+memmove_long_match_emit_repeat_encodeBetterBlockAsm8B:
+ LEAQ (CX)(R8*1), SI
+
+ // genMemMoveLong
+ MOVOU (R9), X0
+ MOVOU 16(R9), X1
+ MOVOU -32(R9)(R8*1), X2
+ MOVOU -16(R9)(R8*1), X3
+ MOVQ R8, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R13
+ SUBQ R10, R13
+ DECQ R11
+ JA emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm8Blarge_forward_sse_loop_32
+ LEAQ -32(R9)(R13*1), R10
+ LEAQ -32(CX)(R13*1), R14
+
+emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm8Blarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R14)
+ MOVOA X5, 16(R14)
+ ADDQ $0x20, R14
+ ADDQ $0x20, R10
+ ADDQ $0x20, R13
+ DECQ R11
+ JNA emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm8Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm8Blarge_forward_sse_loop_32:
+ MOVOU -32(R9)(R13*1), X4
+ MOVOU -16(R9)(R13*1), X5
+ MOVOA X4, -32(CX)(R13*1)
+ MOVOA X5, -16(CX)(R13*1)
+ ADDQ $0x20, R13
+ CMPQ R8, R13
+ JAE emit_lit_memmove_long_match_emit_repeat_encodeBetterBlockAsm8Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R8*1)
+ MOVOU X3, -16(CX)(R8*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_repeat_encodeBetterBlockAsm8B:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitRepeat
+ MOVL R12, SI
+ LEAL -4(R12), R12
+ CMPL SI, $0x08
+ JBE repeat_two_match_nolit_repeat_encodeBetterBlockAsm8B
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm8B
+
+cant_repeat_two_offset_match_nolit_repeat_encodeBetterBlockAsm8B:
+ CMPL R12, $0x00000104
+ JB repeat_three_match_nolit_repeat_encodeBetterBlockAsm8B
+ LEAL -256(R12), R12
+ MOVW $0x0019, (CX)
+ MOVW R12, 2(CX)
+ ADDQ $0x04, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+
+repeat_three_match_nolit_repeat_encodeBetterBlockAsm8B:
+ LEAL -4(R12), R12
+ MOVW $0x0015, (CX)
+ MOVB R12, 2(CX)
+ ADDQ $0x03, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+
+repeat_two_match_nolit_repeat_encodeBetterBlockAsm8B:
+ SHLL $0x02, R12
+ ORL $0x01, R12
+ MOVW R12, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeBetterBlockAsm8B
+ XORQ SI, SI
+ LEAL 1(SI)(R12*4), R12
+ MOVB R8, 1(CX)
+ SARL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, R12
+ MOVB R12, (CX)
+ ADDQ $0x02, CX
+
+match_nolit_emitcopy_end_encodeBetterBlockAsm8B:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeBetterBlockAsm8B
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeBetterBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeBetterBlockAsm8B:
+ MOVQ $0x0000cf1bbcdcbf9b, SI
+ MOVQ $0x9e3779b1, R8
+ LEAQ 1(DI), DI
+ LEAQ -2(DX), R9
+ MOVQ (BX)(DI*1), R10
+ MOVQ 1(BX)(DI*1), R11
+ MOVQ (BX)(R9*1), R12
+ MOVQ 1(BX)(R9*1), R13
+ SHLQ $0x10, R10
+ IMULQ SI, R10
+ SHRQ $0x36, R10
+ SHLQ $0x20, R11
+ IMULQ R8, R11
+ SHRQ $0x38, R11
+ SHLQ $0x10, R12
+ IMULQ SI, R12
+ SHRQ $0x36, R12
+ SHLQ $0x20, R13
+ IMULQ R8, R13
+ SHRQ $0x38, R13
+ LEAQ 1(DI), R8
+ LEAQ 1(R9), R14
+ MOVL DI, (AX)(R10*4)
+ MOVL R9, (AX)(R12*4)
+ MOVL R8, 4096(AX)(R11*4)
+ MOVL R14, 4096(AX)(R13*4)
+ LEAQ 1(R9)(DI*1), R8
+ SHRQ $0x01, R8
+ ADDQ $0x01, DI
+ SUBQ $0x01, R9
+
+index_loop_encodeBetterBlockAsm8B:
+ CMPQ R8, R9
+ JAE search_loop_encodeBetterBlockAsm8B
+ MOVQ (BX)(DI*1), R10
+ MOVQ (BX)(R8*1), R11
+ SHLQ $0x10, R10
+ IMULQ SI, R10
+ SHRQ $0x36, R10
+ SHLQ $0x10, R11
+ IMULQ SI, R11
+ SHRQ $0x36, R11
+ MOVL DI, (AX)(R10*4)
+ MOVL R8, (AX)(R11*4)
+ ADDQ $0x02, DI
+ ADDQ $0x02, R8
+ JMP index_loop_encodeBetterBlockAsm8B
+
+emit_remainder_encodeBetterBlockAsm8B:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeBetterBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeBetterBlockAsm8B:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeBetterBlockAsm8B
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeBetterBlockAsm8B
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeBetterBlockAsm8B
+ JB three_bytes_emit_remainder_encodeBetterBlockAsm8B
+
+three_bytes_emit_remainder_encodeBetterBlockAsm8B:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm8B
+
+two_bytes_emit_remainder_encodeBetterBlockAsm8B:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeBetterBlockAsm8B
+ JMP memmove_long_emit_remainder_encodeBetterBlockAsm8B
+
+one_byte_emit_remainder_encodeBetterBlockAsm8B:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeBetterBlockAsm8B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeBetterBlockAsm8B_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm8B_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeBetterBlockAsm8B_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm8B_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeBetterBlockAsm8B_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeBetterBlockAsm8B_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm8B_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm8B_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm8B_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm8B_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm8B_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeBetterBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeBetterBlockAsm8B_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeBetterBlockAsm8B:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeBetterBlockAsm8B
+
+memmove_long_emit_remainder_encodeBetterBlockAsm8B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm8Blarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm8Blarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm8Blarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm8Blarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeBetterBlockAsm8Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeBetterBlockAsm8B:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeSnappyBlockAsm(dst []byte, src []byte, tmp *[65536]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeSnappyBlockAsm(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000200, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeSnappyBlockAsm:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeSnappyBlockAsm
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL DX, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeSnappyBlockAsm:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x06, SI
+ LEAL 4(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeSnappyBlockAsm
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHRQ $0x08, R11
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x32, R10
+ SHLQ $0x10, R11
+ IMULQ R9, R11
+ SHRQ $0x32, R11
+ MOVL (AX)(R10*4), SI
+ MOVL (AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ LEAL 1(DX), R10
+ MOVL R10, (AX)(R11*4)
+ MOVQ DI, R10
+ SHRQ $0x10, R10
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x32, R10
+ MOVL DX, R9
+ SUBL 16(SP), R9
+ MOVL 1(BX)(R9*1), R11
+ MOVQ DI, R9
+ SHRQ $0x08, R9
+ CMPL R9, R11
+ JNE no_repeat_found_encodeSnappyBlockAsm
+ LEAL 1(DX), DI
+ MOVL 12(SP), SI
+ MOVL DI, R8
+ SUBL 16(SP), R8
+ JZ repeat_extend_back_end_encodeSnappyBlockAsm
+
+repeat_extend_back_loop_encodeSnappyBlockAsm:
+ CMPL DI, SI
+ JBE repeat_extend_back_end_encodeSnappyBlockAsm
+ MOVB -1(BX)(R8*1), R9
+ MOVB -1(BX)(DI*1), R10
+ CMPB R9, R10
+ JNE repeat_extend_back_end_encodeSnappyBlockAsm
+ LEAL -1(DI), DI
+ DECL R8
+ JNZ repeat_extend_back_loop_encodeSnappyBlockAsm
+
+repeat_extend_back_end_encodeSnappyBlockAsm:
+ MOVL DI, SI
+ SUBL 12(SP), SI
+ LEAQ 5(CX)(SI*1), SI
+ CMPQ SI, (SP)
+ JB repeat_dst_size_check_encodeSnappyBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+repeat_dst_size_check_encodeSnappyBlockAsm:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm
+ MOVL DI, R8
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R9
+ SUBL SI, R8
+ LEAL -1(R8), SI
+ CMPL SI, $0x3c
+ JB one_byte_repeat_emit_encodeSnappyBlockAsm
+ CMPL SI, $0x00000100
+ JB two_bytes_repeat_emit_encodeSnappyBlockAsm
+ CMPL SI, $0x00010000
+ JB three_bytes_repeat_emit_encodeSnappyBlockAsm
+ CMPL SI, $0x01000000
+ JB four_bytes_repeat_emit_encodeSnappyBlockAsm
+ MOVB $0xfc, (CX)
+ MOVL SI, 1(CX)
+ ADDQ $0x05, CX
+ JMP memmove_long_repeat_emit_encodeSnappyBlockAsm
+
+four_bytes_repeat_emit_encodeSnappyBlockAsm:
+ MOVL SI, R10
+ SHRL $0x10, R10
+ MOVB $0xf8, (CX)
+ MOVW SI, 1(CX)
+ MOVB R10, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_repeat_emit_encodeSnappyBlockAsm
+
+three_bytes_repeat_emit_encodeSnappyBlockAsm:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_repeat_emit_encodeSnappyBlockAsm
+
+two_bytes_repeat_emit_encodeSnappyBlockAsm:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_repeat_emit_encodeSnappyBlockAsm
+ JMP memmove_long_repeat_emit_encodeSnappyBlockAsm
+
+one_byte_repeat_emit_encodeSnappyBlockAsm:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_repeat_emit_encodeSnappyBlockAsm:
+ LEAQ (CX)(R8*1), SI
+
+ // genMemMoveShort
+ CMPQ R8, $0x08
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm_memmove_move_8
+ CMPQ R8, $0x10
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm_memmove_move_8through16
+ CMPQ R8, $0x20
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm_memmove_move_17through32
+ JMP emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm_memmove_move_33through64
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm_memmove_move_8:
+ MOVQ (R9), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm_memmove_move_8through16:
+ MOVQ (R9), R10
+ MOVQ -8(R9)(R8*1), R9
+ MOVQ R10, (CX)
+ MOVQ R9, -8(CX)(R8*1)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm_memmove_move_17through32:
+ MOVOU (R9), X0
+ MOVOU -16(R9)(R8*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R8*1)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm_memmove_move_33through64:
+ MOVOU (R9), X0
+ MOVOU 16(R9), X1
+ MOVOU -32(R9)(R8*1), X2
+ MOVOU -16(R9)(R8*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R8*1)
+ MOVOU X3, -16(CX)(R8*1)
+
+memmove_end_copy_repeat_emit_encodeSnappyBlockAsm:
+ MOVQ SI, CX
+ JMP emit_literal_done_repeat_emit_encodeSnappyBlockAsm
+
+memmove_long_repeat_emit_encodeSnappyBlockAsm:
+ LEAQ (CX)(R8*1), SI
+
+ // genMemMoveLong
+ MOVOU (R9), X0
+ MOVOU 16(R9), X1
+ MOVOU -32(R9)(R8*1), X2
+ MOVOU -16(R9)(R8*1), X3
+ MOVQ R8, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsmlarge_forward_sse_loop_32
+ LEAQ -32(R9)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsmlarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsmlarge_big_loop_back
+
+emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsmlarge_forward_sse_loop_32:
+ MOVOU -32(R9)(R12*1), X4
+ MOVOU -16(R9)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R8, R12
+ JAE emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsmlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R8*1)
+ MOVOU X3, -16(CX)(R8*1)
+ MOVQ SI, CX
+
+emit_literal_done_repeat_emit_encodeSnappyBlockAsm:
+ ADDL $0x05, DX
+ MOVL DX, SI
+ SUBL 16(SP), SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R11, R11
+
+matchlen_loopback_16_repeat_extend_encodeSnappyBlockAsm:
+ CMPL R8, $0x10
+ JB matchlen_match8_repeat_extend_encodeSnappyBlockAsm
+ MOVQ (R9)(R11*1), R10
+ MOVQ 8(R9)(R11*1), R12
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm
+ XORQ 8(SI)(R11*1), R12
+ JNZ matchlen_bsf_16repeat_extend_encodeSnappyBlockAsm
+ LEAL -16(R8), R8
+ LEAL 16(R11), R11
+ JMP matchlen_loopback_16_repeat_extend_encodeSnappyBlockAsm
+
+matchlen_bsf_16repeat_extend_encodeSnappyBlockAsm:
+#ifdef GOAMD64_v3
+ TZCNTQ R12, R12
+
+#else
+ BSFQ R12, R12
+
+#endif
+ SARQ $0x03, R12
+ LEAL 8(R11)(R12*1), R11
+ JMP repeat_extend_forward_end_encodeSnappyBlockAsm
+
+matchlen_match8_repeat_extend_encodeSnappyBlockAsm:
+ CMPL R8, $0x08
+ JB matchlen_match4_repeat_extend_encodeSnappyBlockAsm
+ MOVQ (R9)(R11*1), R10
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm
+ LEAL -8(R8), R8
+ LEAL 8(R11), R11
+ JMP matchlen_match4_repeat_extend_encodeSnappyBlockAsm
+
+matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm:
+#ifdef GOAMD64_v3
+ TZCNTQ R10, R10
+
+#else
+ BSFQ R10, R10
+
+#endif
+ SARQ $0x03, R10
+ LEAL (R11)(R10*1), R11
+ JMP repeat_extend_forward_end_encodeSnappyBlockAsm
+
+matchlen_match4_repeat_extend_encodeSnappyBlockAsm:
+ CMPL R8, $0x04
+ JB matchlen_match2_repeat_extend_encodeSnappyBlockAsm
+ MOVL (R9)(R11*1), R10
+ CMPL (SI)(R11*1), R10
+ JNE matchlen_match2_repeat_extend_encodeSnappyBlockAsm
+ LEAL -4(R8), R8
+ LEAL 4(R11), R11
+
+matchlen_match2_repeat_extend_encodeSnappyBlockAsm:
+ CMPL R8, $0x01
+ JE matchlen_match1_repeat_extend_encodeSnappyBlockAsm
+ JB repeat_extend_forward_end_encodeSnappyBlockAsm
+ MOVW (R9)(R11*1), R10
+ CMPW (SI)(R11*1), R10
+ JNE matchlen_match1_repeat_extend_encodeSnappyBlockAsm
+ LEAL 2(R11), R11
+ SUBL $0x02, R8
+ JZ repeat_extend_forward_end_encodeSnappyBlockAsm
+
+matchlen_match1_repeat_extend_encodeSnappyBlockAsm:
+ MOVB (R9)(R11*1), R10
+ CMPB (SI)(R11*1), R10
+ JNE repeat_extend_forward_end_encodeSnappyBlockAsm
+ LEAL 1(R11), R11
+
+repeat_extend_forward_end_encodeSnappyBlockAsm:
+ ADDL R11, DX
+ MOVL DX, SI
+ SUBL DI, SI
+ MOVL 16(SP), DI
+
+ // emitCopy
+ CMPL DI, $0x00010000
+ JB two_byte_offset_repeat_as_copy_encodeSnappyBlockAsm
+
+four_bytes_loop_back_repeat_as_copy_encodeSnappyBlockAsm:
+ CMPL SI, $0x40
+ JBE four_bytes_remain_repeat_as_copy_encodeSnappyBlockAsm
+ MOVB $0xff, (CX)
+ MOVL DI, 1(CX)
+ LEAL -64(SI), SI
+ ADDQ $0x05, CX
+ CMPL SI, $0x04
+ JB four_bytes_remain_repeat_as_copy_encodeSnappyBlockAsm
+ JMP four_bytes_loop_back_repeat_as_copy_encodeSnappyBlockAsm
+
+four_bytes_remain_repeat_as_copy_encodeSnappyBlockAsm:
+ TESTL SI, SI
+ JZ repeat_end_emit_encodeSnappyBlockAsm
+ XORL R8, R8
+ LEAL -1(R8)(SI*4), SI
+ MOVB SI, (CX)
+ MOVL DI, 1(CX)
+ ADDQ $0x05, CX
+ JMP repeat_end_emit_encodeSnappyBlockAsm
+
+two_byte_offset_repeat_as_copy_encodeSnappyBlockAsm:
+ CMPL SI, $0x40
+ JBE two_byte_offset_short_repeat_as_copy_encodeSnappyBlockAsm
+ MOVB $0xee, (CX)
+ MOVW DI, 1(CX)
+ LEAL -60(SI), SI
+ ADDQ $0x03, CX
+ JMP two_byte_offset_repeat_as_copy_encodeSnappyBlockAsm
+
+two_byte_offset_short_repeat_as_copy_encodeSnappyBlockAsm:
+ MOVL SI, R8
+ SHLL $0x02, R8
+ CMPL SI, $0x0c
+ JAE emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm
+ CMPL DI, $0x00000800
+ JAE emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm
+ LEAL -15(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeSnappyBlockAsm
+
+emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm:
+ LEAL -2(R8), R8
+ MOVB R8, (CX)
+ MOVW DI, 1(CX)
+ ADDQ $0x03, CX
+
+repeat_end_emit_encodeSnappyBlockAsm:
+ MOVL DX, 12(SP)
+ JMP search_loop_encodeSnappyBlockAsm
+
+no_repeat_found_encodeSnappyBlockAsm:
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeSnappyBlockAsm
+ SHRQ $0x08, DI
+ MOVL (AX)(R10*4), SI
+ LEAL 2(DX), R9
+ CMPL (BX)(R8*1), DI
+ JEQ candidate2_match_encodeSnappyBlockAsm
+ MOVL R9, (AX)(R10*4)
+ SHRQ $0x08, DI
+ CMPL (BX)(SI*1), DI
+ JEQ candidate3_match_encodeSnappyBlockAsm
+ MOVL 20(SP), DX
+ JMP search_loop_encodeSnappyBlockAsm
+
+candidate3_match_encodeSnappyBlockAsm:
+ ADDL $0x02, DX
+ JMP candidate_match_encodeSnappyBlockAsm
+
+candidate2_match_encodeSnappyBlockAsm:
+ MOVL R9, (AX)(R10*4)
+ INCL DX
+ MOVL R8, SI
+
+candidate_match_encodeSnappyBlockAsm:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeSnappyBlockAsm
+
+match_extend_back_loop_encodeSnappyBlockAsm:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeSnappyBlockAsm
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeSnappyBlockAsm
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeSnappyBlockAsm
+ JMP match_extend_back_loop_encodeSnappyBlockAsm
+
+match_extend_back_end_encodeSnappyBlockAsm:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 5(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeSnappyBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeSnappyBlockAsm:
+ MOVL DX, DI
+ MOVL 12(SP), R8
+ CMPL R8, DI
+ JEQ emit_literal_done_match_emit_encodeSnappyBlockAsm
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(R8*1), DI
+ SUBL R8, R9
+ LEAL -1(R9), R8
+ CMPL R8, $0x3c
+ JB one_byte_match_emit_encodeSnappyBlockAsm
+ CMPL R8, $0x00000100
+ JB two_bytes_match_emit_encodeSnappyBlockAsm
+ CMPL R8, $0x00010000
+ JB three_bytes_match_emit_encodeSnappyBlockAsm
+ CMPL R8, $0x01000000
+ JB four_bytes_match_emit_encodeSnappyBlockAsm
+ MOVB $0xfc, (CX)
+ MOVL R8, 1(CX)
+ ADDQ $0x05, CX
+ JMP memmove_long_match_emit_encodeSnappyBlockAsm
+
+four_bytes_match_emit_encodeSnappyBlockAsm:
+ MOVL R8, R10
+ SHRL $0x10, R10
+ MOVB $0xf8, (CX)
+ MOVW R8, 1(CX)
+ MOVB R10, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_match_emit_encodeSnappyBlockAsm
+
+three_bytes_match_emit_encodeSnappyBlockAsm:
+ MOVB $0xf4, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeSnappyBlockAsm
+
+two_bytes_match_emit_encodeSnappyBlockAsm:
+ MOVB $0xf0, (CX)
+ MOVB R8, 1(CX)
+ ADDQ $0x02, CX
+ CMPL R8, $0x40
+ JB memmove_match_emit_encodeSnappyBlockAsm
+ JMP memmove_long_match_emit_encodeSnappyBlockAsm
+
+one_byte_match_emit_encodeSnappyBlockAsm:
+ SHLB $0x02, R8
+ MOVB R8, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeSnappyBlockAsm:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeSnappyBlockAsm_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm_memmove_move_8:
+ MOVQ (DI), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm_memmove_move_8through16:
+ MOVQ (DI), R10
+ MOVQ -8(DI)(R9*1), DI
+ MOVQ R10, (CX)
+ MOVQ DI, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm_memmove_move_17through32:
+ MOVOU (DI), X0
+ MOVOU -16(DI)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm_memmove_move_33through64:
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeSnappyBlockAsm:
+ MOVQ R8, CX
+ JMP emit_literal_done_match_emit_encodeSnappyBlockAsm
+
+memmove_long_match_emit_encodeSnappyBlockAsm:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveLong
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVQ R9, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_match_emit_encodeSnappyBlockAsmlarge_forward_sse_loop_32
+ LEAQ -32(DI)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_match_emit_encodeSnappyBlockAsmlarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_match_emit_encodeSnappyBlockAsmlarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeSnappyBlockAsmlarge_forward_sse_loop_32:
+ MOVOU -32(DI)(R12*1), X4
+ MOVOU -16(DI)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R9, R12
+ JAE emit_lit_memmove_long_match_emit_encodeSnappyBlockAsmlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ R8, CX
+
+emit_literal_done_match_emit_encodeSnappyBlockAsm:
+match_nolit_loop_encodeSnappyBlockAsm:
+ MOVL DX, DI
+ SUBL SI, DI
+ MOVL DI, 16(SP)
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), DI
+ SUBL DX, DI
+ LEAQ (BX)(DX*1), R8
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R10, R10
+
+matchlen_loopback_16_match_nolit_encodeSnappyBlockAsm:
+ CMPL DI, $0x10
+ JB matchlen_match8_match_nolit_encodeSnappyBlockAsm
+ MOVQ (R8)(R10*1), R9
+ MOVQ 8(R8)(R10*1), R11
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm
+ XORQ 8(SI)(R10*1), R11
+ JNZ matchlen_bsf_16match_nolit_encodeSnappyBlockAsm
+ LEAL -16(DI), DI
+ LEAL 16(R10), R10
+ JMP matchlen_loopback_16_match_nolit_encodeSnappyBlockAsm
+
+matchlen_bsf_16match_nolit_encodeSnappyBlockAsm:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL 8(R10)(R11*1), R10
+ JMP match_nolit_end_encodeSnappyBlockAsm
+
+matchlen_match8_match_nolit_encodeSnappyBlockAsm:
+ CMPL DI, $0x08
+ JB matchlen_match4_match_nolit_encodeSnappyBlockAsm
+ MOVQ (R8)(R10*1), R9
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm
+ LEAL -8(DI), DI
+ LEAL 8(R10), R10
+ JMP matchlen_match4_match_nolit_encodeSnappyBlockAsm
+
+matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm:
+#ifdef GOAMD64_v3
+ TZCNTQ R9, R9
+
+#else
+ BSFQ R9, R9
+
+#endif
+ SARQ $0x03, R9
+ LEAL (R10)(R9*1), R10
+ JMP match_nolit_end_encodeSnappyBlockAsm
+
+matchlen_match4_match_nolit_encodeSnappyBlockAsm:
+ CMPL DI, $0x04
+ JB matchlen_match2_match_nolit_encodeSnappyBlockAsm
+ MOVL (R8)(R10*1), R9
+ CMPL (SI)(R10*1), R9
+ JNE matchlen_match2_match_nolit_encodeSnappyBlockAsm
+ LEAL -4(DI), DI
+ LEAL 4(R10), R10
+
+matchlen_match2_match_nolit_encodeSnappyBlockAsm:
+ CMPL DI, $0x01
+ JE matchlen_match1_match_nolit_encodeSnappyBlockAsm
+ JB match_nolit_end_encodeSnappyBlockAsm
+ MOVW (R8)(R10*1), R9
+ CMPW (SI)(R10*1), R9
+ JNE matchlen_match1_match_nolit_encodeSnappyBlockAsm
+ LEAL 2(R10), R10
+ SUBL $0x02, DI
+ JZ match_nolit_end_encodeSnappyBlockAsm
+
+matchlen_match1_match_nolit_encodeSnappyBlockAsm:
+ MOVB (R8)(R10*1), R9
+ CMPB (SI)(R10*1), R9
+ JNE match_nolit_end_encodeSnappyBlockAsm
+ LEAL 1(R10), R10
+
+match_nolit_end_encodeSnappyBlockAsm:
+ ADDL R10, DX
+ MOVL 16(SP), SI
+ ADDL $0x04, R10
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL SI, $0x00010000
+ JB two_byte_offset_match_nolit_encodeSnappyBlockAsm
+
+four_bytes_loop_back_match_nolit_encodeSnappyBlockAsm:
+ CMPL R10, $0x40
+ JBE four_bytes_remain_match_nolit_encodeSnappyBlockAsm
+ MOVB $0xff, (CX)
+ MOVL SI, 1(CX)
+ LEAL -64(R10), R10
+ ADDQ $0x05, CX
+ CMPL R10, $0x04
+ JB four_bytes_remain_match_nolit_encodeSnappyBlockAsm
+ JMP four_bytes_loop_back_match_nolit_encodeSnappyBlockAsm
+
+four_bytes_remain_match_nolit_encodeSnappyBlockAsm:
+ TESTL R10, R10
+ JZ match_nolit_emitcopy_end_encodeSnappyBlockAsm
+ XORL DI, DI
+ LEAL -1(DI)(R10*4), R10
+ MOVB R10, (CX)
+ MOVL SI, 1(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeSnappyBlockAsm
+
+two_byte_offset_match_nolit_encodeSnappyBlockAsm:
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeSnappyBlockAsm
+ MOVB $0xee, (CX)
+ MOVW SI, 1(CX)
+ LEAL -60(R10), R10
+ ADDQ $0x03, CX
+ JMP two_byte_offset_match_nolit_encodeSnappyBlockAsm
+
+two_byte_offset_short_match_nolit_encodeSnappyBlockAsm:
+ MOVL R10, DI
+ SHLL $0x02, DI
+ CMPL R10, $0x0c
+ JAE emit_copy_three_match_nolit_encodeSnappyBlockAsm
+ CMPL SI, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeSnappyBlockAsm
+ LEAL -15(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeSnappyBlockAsm
+
+emit_copy_three_match_nolit_encodeSnappyBlockAsm:
+ LEAL -2(DI), DI
+ MOVB DI, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeSnappyBlockAsm:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeSnappyBlockAsm
+ MOVQ -2(BX)(DX*1), DI
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeSnappyBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeSnappyBlockAsm:
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ DI, R8
+ SHRQ $0x10, DI
+ MOVQ DI, SI
+ SHLQ $0x10, R8
+ IMULQ R9, R8
+ SHRQ $0x32, R8
+ SHLQ $0x10, SI
+ IMULQ R9, SI
+ SHRQ $0x32, SI
+ LEAL -2(DX), R9
+ LEAQ (AX)(SI*4), R10
+ MOVL (R10), SI
+ MOVL R9, (AX)(R8*4)
+ MOVL DX, (R10)
+ CMPL (BX)(SI*1), DI
+ JEQ match_nolit_loop_encodeSnappyBlockAsm
+ INCL DX
+ JMP search_loop_encodeSnappyBlockAsm
+
+emit_remainder_encodeSnappyBlockAsm:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 5(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeSnappyBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeSnappyBlockAsm:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeSnappyBlockAsm
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeSnappyBlockAsm
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeSnappyBlockAsm
+ CMPL DX, $0x00010000
+ JB three_bytes_emit_remainder_encodeSnappyBlockAsm
+ CMPL DX, $0x01000000
+ JB four_bytes_emit_remainder_encodeSnappyBlockAsm
+ MOVB $0xfc, (CX)
+ MOVL DX, 1(CX)
+ ADDQ $0x05, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBlockAsm
+
+four_bytes_emit_remainder_encodeSnappyBlockAsm:
+ MOVL DX, BX
+ SHRL $0x10, BX
+ MOVB $0xf8, (CX)
+ MOVW DX, 1(CX)
+ MOVB BL, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBlockAsm
+
+three_bytes_emit_remainder_encodeSnappyBlockAsm:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBlockAsm
+
+two_bytes_emit_remainder_encodeSnappyBlockAsm:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeSnappyBlockAsm
+ JMP memmove_long_emit_remainder_encodeSnappyBlockAsm
+
+one_byte_emit_remainder_encodeSnappyBlockAsm:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeSnappyBlockAsm:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeSnappyBlockAsm:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeSnappyBlockAsm
+
+memmove_long_emit_remainder_encodeSnappyBlockAsm:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsmlarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsmlarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsmlarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsmlarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsmlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeSnappyBlockAsm:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeSnappyBlockAsm64K(dst []byte, src []byte, tmp *[65536]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeSnappyBlockAsm64K(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000200, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeSnappyBlockAsm64K:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeSnappyBlockAsm64K
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL DX, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeSnappyBlockAsm64K:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x06, SI
+ LEAL 4(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeSnappyBlockAsm64K
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHRQ $0x08, R11
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x32, R10
+ SHLQ $0x10, R11
+ IMULQ R9, R11
+ SHRQ $0x32, R11
+ MOVL (AX)(R10*4), SI
+ MOVL (AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ LEAL 1(DX), R10
+ MOVL R10, (AX)(R11*4)
+ MOVQ DI, R10
+ SHRQ $0x10, R10
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x32, R10
+ MOVL DX, R9
+ SUBL 16(SP), R9
+ MOVL 1(BX)(R9*1), R11
+ MOVQ DI, R9
+ SHRQ $0x08, R9
+ CMPL R9, R11
+ JNE no_repeat_found_encodeSnappyBlockAsm64K
+ LEAL 1(DX), DI
+ MOVL 12(SP), SI
+ MOVL DI, R8
+ SUBL 16(SP), R8
+ JZ repeat_extend_back_end_encodeSnappyBlockAsm64K
+
+repeat_extend_back_loop_encodeSnappyBlockAsm64K:
+ CMPL DI, SI
+ JBE repeat_extend_back_end_encodeSnappyBlockAsm64K
+ MOVB -1(BX)(R8*1), R9
+ MOVB -1(BX)(DI*1), R10
+ CMPB R9, R10
+ JNE repeat_extend_back_end_encodeSnappyBlockAsm64K
+ LEAL -1(DI), DI
+ DECL R8
+ JNZ repeat_extend_back_loop_encodeSnappyBlockAsm64K
+
+repeat_extend_back_end_encodeSnappyBlockAsm64K:
+ MOVL DI, SI
+ SUBL 12(SP), SI
+ LEAQ 3(CX)(SI*1), SI
+ CMPQ SI, (SP)
+ JB repeat_dst_size_check_encodeSnappyBlockAsm64K
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+repeat_dst_size_check_encodeSnappyBlockAsm64K:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm64K
+ MOVL DI, R8
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R9
+ SUBL SI, R8
+ LEAL -1(R8), SI
+ CMPL SI, $0x3c
+ JB one_byte_repeat_emit_encodeSnappyBlockAsm64K
+ CMPL SI, $0x00000100
+ JB two_bytes_repeat_emit_encodeSnappyBlockAsm64K
+ JB three_bytes_repeat_emit_encodeSnappyBlockAsm64K
+
+three_bytes_repeat_emit_encodeSnappyBlockAsm64K:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_repeat_emit_encodeSnappyBlockAsm64K
+
+two_bytes_repeat_emit_encodeSnappyBlockAsm64K:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_repeat_emit_encodeSnappyBlockAsm64K
+ JMP memmove_long_repeat_emit_encodeSnappyBlockAsm64K
+
+one_byte_repeat_emit_encodeSnappyBlockAsm64K:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_repeat_emit_encodeSnappyBlockAsm64K:
+ LEAQ (CX)(R8*1), SI
+
+ // genMemMoveShort
+ CMPQ R8, $0x08
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm64K_memmove_move_8
+ CMPQ R8, $0x10
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm64K_memmove_move_8through16
+ CMPQ R8, $0x20
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm64K_memmove_move_17through32
+ JMP emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm64K_memmove_move_33through64
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm64K_memmove_move_8:
+ MOVQ (R9), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm64K
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm64K_memmove_move_8through16:
+ MOVQ (R9), R10
+ MOVQ -8(R9)(R8*1), R9
+ MOVQ R10, (CX)
+ MOVQ R9, -8(CX)(R8*1)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm64K
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm64K_memmove_move_17through32:
+ MOVOU (R9), X0
+ MOVOU -16(R9)(R8*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R8*1)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm64K
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm64K_memmove_move_33through64:
+ MOVOU (R9), X0
+ MOVOU 16(R9), X1
+ MOVOU -32(R9)(R8*1), X2
+ MOVOU -16(R9)(R8*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R8*1)
+ MOVOU X3, -16(CX)(R8*1)
+
+memmove_end_copy_repeat_emit_encodeSnappyBlockAsm64K:
+ MOVQ SI, CX
+ JMP emit_literal_done_repeat_emit_encodeSnappyBlockAsm64K
+
+memmove_long_repeat_emit_encodeSnappyBlockAsm64K:
+ LEAQ (CX)(R8*1), SI
+
+ // genMemMoveLong
+ MOVOU (R9), X0
+ MOVOU 16(R9), X1
+ MOVOU -32(R9)(R8*1), X2
+ MOVOU -16(R9)(R8*1), X3
+ MOVQ R8, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm64Klarge_forward_sse_loop_32
+ LEAQ -32(R9)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm64Klarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm64Klarge_big_loop_back
+
+emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm64Klarge_forward_sse_loop_32:
+ MOVOU -32(R9)(R12*1), X4
+ MOVOU -16(R9)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R8, R12
+ JAE emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm64Klarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R8*1)
+ MOVOU X3, -16(CX)(R8*1)
+ MOVQ SI, CX
+
+emit_literal_done_repeat_emit_encodeSnappyBlockAsm64K:
+ ADDL $0x05, DX
+ MOVL DX, SI
+ SUBL 16(SP), SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R11, R11
+
+matchlen_loopback_16_repeat_extend_encodeSnappyBlockAsm64K:
+ CMPL R8, $0x10
+ JB matchlen_match8_repeat_extend_encodeSnappyBlockAsm64K
+ MOVQ (R9)(R11*1), R10
+ MOVQ 8(R9)(R11*1), R12
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm64K
+ XORQ 8(SI)(R11*1), R12
+ JNZ matchlen_bsf_16repeat_extend_encodeSnappyBlockAsm64K
+ LEAL -16(R8), R8
+ LEAL 16(R11), R11
+ JMP matchlen_loopback_16_repeat_extend_encodeSnappyBlockAsm64K
+
+matchlen_bsf_16repeat_extend_encodeSnappyBlockAsm64K:
+#ifdef GOAMD64_v3
+ TZCNTQ R12, R12
+
+#else
+ BSFQ R12, R12
+
+#endif
+ SARQ $0x03, R12
+ LEAL 8(R11)(R12*1), R11
+ JMP repeat_extend_forward_end_encodeSnappyBlockAsm64K
+
+matchlen_match8_repeat_extend_encodeSnappyBlockAsm64K:
+ CMPL R8, $0x08
+ JB matchlen_match4_repeat_extend_encodeSnappyBlockAsm64K
+ MOVQ (R9)(R11*1), R10
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm64K
+ LEAL -8(R8), R8
+ LEAL 8(R11), R11
+ JMP matchlen_match4_repeat_extend_encodeSnappyBlockAsm64K
+
+matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm64K:
+#ifdef GOAMD64_v3
+ TZCNTQ R10, R10
+
+#else
+ BSFQ R10, R10
+
+#endif
+ SARQ $0x03, R10
+ LEAL (R11)(R10*1), R11
+ JMP repeat_extend_forward_end_encodeSnappyBlockAsm64K
+
+matchlen_match4_repeat_extend_encodeSnappyBlockAsm64K:
+ CMPL R8, $0x04
+ JB matchlen_match2_repeat_extend_encodeSnappyBlockAsm64K
+ MOVL (R9)(R11*1), R10
+ CMPL (SI)(R11*1), R10
+ JNE matchlen_match2_repeat_extend_encodeSnappyBlockAsm64K
+ LEAL -4(R8), R8
+ LEAL 4(R11), R11
+
+matchlen_match2_repeat_extend_encodeSnappyBlockAsm64K:
+ CMPL R8, $0x01
+ JE matchlen_match1_repeat_extend_encodeSnappyBlockAsm64K
+ JB repeat_extend_forward_end_encodeSnappyBlockAsm64K
+ MOVW (R9)(R11*1), R10
+ CMPW (SI)(R11*1), R10
+ JNE matchlen_match1_repeat_extend_encodeSnappyBlockAsm64K
+ LEAL 2(R11), R11
+ SUBL $0x02, R8
+ JZ repeat_extend_forward_end_encodeSnappyBlockAsm64K
+
+matchlen_match1_repeat_extend_encodeSnappyBlockAsm64K:
+ MOVB (R9)(R11*1), R10
+ CMPB (SI)(R11*1), R10
+ JNE repeat_extend_forward_end_encodeSnappyBlockAsm64K
+ LEAL 1(R11), R11
+
+repeat_extend_forward_end_encodeSnappyBlockAsm64K:
+ ADDL R11, DX
+ MOVL DX, SI
+ SUBL DI, SI
+ MOVL 16(SP), DI
+
+ // emitCopy
+two_byte_offset_repeat_as_copy_encodeSnappyBlockAsm64K:
+ CMPL SI, $0x40
+ JBE two_byte_offset_short_repeat_as_copy_encodeSnappyBlockAsm64K
+ MOVB $0xee, (CX)
+ MOVW DI, 1(CX)
+ LEAL -60(SI), SI
+ ADDQ $0x03, CX
+ JMP two_byte_offset_repeat_as_copy_encodeSnappyBlockAsm64K
+
+two_byte_offset_short_repeat_as_copy_encodeSnappyBlockAsm64K:
+ MOVL SI, R8
+ SHLL $0x02, R8
+ CMPL SI, $0x0c
+ JAE emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm64K
+ CMPL DI, $0x00000800
+ JAE emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm64K
+ LEAL -15(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeSnappyBlockAsm64K
+
+emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm64K:
+ LEAL -2(R8), R8
+ MOVB R8, (CX)
+ MOVW DI, 1(CX)
+ ADDQ $0x03, CX
+
+repeat_end_emit_encodeSnappyBlockAsm64K:
+ MOVL DX, 12(SP)
+ JMP search_loop_encodeSnappyBlockAsm64K
+
+no_repeat_found_encodeSnappyBlockAsm64K:
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeSnappyBlockAsm64K
+ SHRQ $0x08, DI
+ MOVL (AX)(R10*4), SI
+ LEAL 2(DX), R9
+ CMPL (BX)(R8*1), DI
+ JEQ candidate2_match_encodeSnappyBlockAsm64K
+ MOVL R9, (AX)(R10*4)
+ SHRQ $0x08, DI
+ CMPL (BX)(SI*1), DI
+ JEQ candidate3_match_encodeSnappyBlockAsm64K
+ MOVL 20(SP), DX
+ JMP search_loop_encodeSnappyBlockAsm64K
+
+candidate3_match_encodeSnappyBlockAsm64K:
+ ADDL $0x02, DX
+ JMP candidate_match_encodeSnappyBlockAsm64K
+
+candidate2_match_encodeSnappyBlockAsm64K:
+ MOVL R9, (AX)(R10*4)
+ INCL DX
+ MOVL R8, SI
+
+candidate_match_encodeSnappyBlockAsm64K:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeSnappyBlockAsm64K
+
+match_extend_back_loop_encodeSnappyBlockAsm64K:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeSnappyBlockAsm64K
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeSnappyBlockAsm64K
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeSnappyBlockAsm64K
+ JMP match_extend_back_loop_encodeSnappyBlockAsm64K
+
+match_extend_back_end_encodeSnappyBlockAsm64K:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeSnappyBlockAsm64K
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeSnappyBlockAsm64K:
+ MOVL DX, DI
+ MOVL 12(SP), R8
+ CMPL R8, DI
+ JEQ emit_literal_done_match_emit_encodeSnappyBlockAsm64K
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(R8*1), DI
+ SUBL R8, R9
+ LEAL -1(R9), R8
+ CMPL R8, $0x3c
+ JB one_byte_match_emit_encodeSnappyBlockAsm64K
+ CMPL R8, $0x00000100
+ JB two_bytes_match_emit_encodeSnappyBlockAsm64K
+ JB three_bytes_match_emit_encodeSnappyBlockAsm64K
+
+three_bytes_match_emit_encodeSnappyBlockAsm64K:
+ MOVB $0xf4, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeSnappyBlockAsm64K
+
+two_bytes_match_emit_encodeSnappyBlockAsm64K:
+ MOVB $0xf0, (CX)
+ MOVB R8, 1(CX)
+ ADDQ $0x02, CX
+ CMPL R8, $0x40
+ JB memmove_match_emit_encodeSnappyBlockAsm64K
+ JMP memmove_long_match_emit_encodeSnappyBlockAsm64K
+
+one_byte_match_emit_encodeSnappyBlockAsm64K:
+ SHLB $0x02, R8
+ MOVB R8, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeSnappyBlockAsm64K:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm64K_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm64K_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm64K_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeSnappyBlockAsm64K_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm64K_memmove_move_8:
+ MOVQ (DI), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm64K
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm64K_memmove_move_8through16:
+ MOVQ (DI), R10
+ MOVQ -8(DI)(R9*1), DI
+ MOVQ R10, (CX)
+ MOVQ DI, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm64K
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm64K_memmove_move_17through32:
+ MOVOU (DI), X0
+ MOVOU -16(DI)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm64K
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm64K_memmove_move_33through64:
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeSnappyBlockAsm64K:
+ MOVQ R8, CX
+ JMP emit_literal_done_match_emit_encodeSnappyBlockAsm64K
+
+memmove_long_match_emit_encodeSnappyBlockAsm64K:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveLong
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVQ R9, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm64Klarge_forward_sse_loop_32
+ LEAQ -32(DI)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm64Klarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm64Klarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm64Klarge_forward_sse_loop_32:
+ MOVOU -32(DI)(R12*1), X4
+ MOVOU -16(DI)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R9, R12
+ JAE emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm64Klarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ R8, CX
+
+emit_literal_done_match_emit_encodeSnappyBlockAsm64K:
+match_nolit_loop_encodeSnappyBlockAsm64K:
+ MOVL DX, DI
+ SUBL SI, DI
+ MOVL DI, 16(SP)
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), DI
+ SUBL DX, DI
+ LEAQ (BX)(DX*1), R8
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R10, R10
+
+matchlen_loopback_16_match_nolit_encodeSnappyBlockAsm64K:
+ CMPL DI, $0x10
+ JB matchlen_match8_match_nolit_encodeSnappyBlockAsm64K
+ MOVQ (R8)(R10*1), R9
+ MOVQ 8(R8)(R10*1), R11
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm64K
+ XORQ 8(SI)(R10*1), R11
+ JNZ matchlen_bsf_16match_nolit_encodeSnappyBlockAsm64K
+ LEAL -16(DI), DI
+ LEAL 16(R10), R10
+ JMP matchlen_loopback_16_match_nolit_encodeSnappyBlockAsm64K
+
+matchlen_bsf_16match_nolit_encodeSnappyBlockAsm64K:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL 8(R10)(R11*1), R10
+ JMP match_nolit_end_encodeSnappyBlockAsm64K
+
+matchlen_match8_match_nolit_encodeSnappyBlockAsm64K:
+ CMPL DI, $0x08
+ JB matchlen_match4_match_nolit_encodeSnappyBlockAsm64K
+ MOVQ (R8)(R10*1), R9
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm64K
+ LEAL -8(DI), DI
+ LEAL 8(R10), R10
+ JMP matchlen_match4_match_nolit_encodeSnappyBlockAsm64K
+
+matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm64K:
+#ifdef GOAMD64_v3
+ TZCNTQ R9, R9
+
+#else
+ BSFQ R9, R9
+
+#endif
+ SARQ $0x03, R9
+ LEAL (R10)(R9*1), R10
+ JMP match_nolit_end_encodeSnappyBlockAsm64K
+
+matchlen_match4_match_nolit_encodeSnappyBlockAsm64K:
+ CMPL DI, $0x04
+ JB matchlen_match2_match_nolit_encodeSnappyBlockAsm64K
+ MOVL (R8)(R10*1), R9
+ CMPL (SI)(R10*1), R9
+ JNE matchlen_match2_match_nolit_encodeSnappyBlockAsm64K
+ LEAL -4(DI), DI
+ LEAL 4(R10), R10
+
+matchlen_match2_match_nolit_encodeSnappyBlockAsm64K:
+ CMPL DI, $0x01
+ JE matchlen_match1_match_nolit_encodeSnappyBlockAsm64K
+ JB match_nolit_end_encodeSnappyBlockAsm64K
+ MOVW (R8)(R10*1), R9
+ CMPW (SI)(R10*1), R9
+ JNE matchlen_match1_match_nolit_encodeSnappyBlockAsm64K
+ LEAL 2(R10), R10
+ SUBL $0x02, DI
+ JZ match_nolit_end_encodeSnappyBlockAsm64K
+
+matchlen_match1_match_nolit_encodeSnappyBlockAsm64K:
+ MOVB (R8)(R10*1), R9
+ CMPB (SI)(R10*1), R9
+ JNE match_nolit_end_encodeSnappyBlockAsm64K
+ LEAL 1(R10), R10
+
+match_nolit_end_encodeSnappyBlockAsm64K:
+ ADDL R10, DX
+ MOVL 16(SP), SI
+ ADDL $0x04, R10
+ MOVL DX, 12(SP)
+
+ // emitCopy
+two_byte_offset_match_nolit_encodeSnappyBlockAsm64K:
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeSnappyBlockAsm64K
+ MOVB $0xee, (CX)
+ MOVW SI, 1(CX)
+ LEAL -60(R10), R10
+ ADDQ $0x03, CX
+ JMP two_byte_offset_match_nolit_encodeSnappyBlockAsm64K
+
+two_byte_offset_short_match_nolit_encodeSnappyBlockAsm64K:
+ MOVL R10, DI
+ SHLL $0x02, DI
+ CMPL R10, $0x0c
+ JAE emit_copy_three_match_nolit_encodeSnappyBlockAsm64K
+ CMPL SI, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeSnappyBlockAsm64K
+ LEAL -15(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeSnappyBlockAsm64K
+
+emit_copy_three_match_nolit_encodeSnappyBlockAsm64K:
+ LEAL -2(DI), DI
+ MOVB DI, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeSnappyBlockAsm64K:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeSnappyBlockAsm64K
+ MOVQ -2(BX)(DX*1), DI
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeSnappyBlockAsm64K
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeSnappyBlockAsm64K:
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ DI, R8
+ SHRQ $0x10, DI
+ MOVQ DI, SI
+ SHLQ $0x10, R8
+ IMULQ R9, R8
+ SHRQ $0x32, R8
+ SHLQ $0x10, SI
+ IMULQ R9, SI
+ SHRQ $0x32, SI
+ LEAL -2(DX), R9
+ LEAQ (AX)(SI*4), R10
+ MOVL (R10), SI
+ MOVL R9, (AX)(R8*4)
+ MOVL DX, (R10)
+ CMPL (BX)(SI*1), DI
+ JEQ match_nolit_loop_encodeSnappyBlockAsm64K
+ INCL DX
+ JMP search_loop_encodeSnappyBlockAsm64K
+
+emit_remainder_encodeSnappyBlockAsm64K:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeSnappyBlockAsm64K
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeSnappyBlockAsm64K:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeSnappyBlockAsm64K
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeSnappyBlockAsm64K
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeSnappyBlockAsm64K
+ JB three_bytes_emit_remainder_encodeSnappyBlockAsm64K
+
+three_bytes_emit_remainder_encodeSnappyBlockAsm64K:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBlockAsm64K
+
+two_bytes_emit_remainder_encodeSnappyBlockAsm64K:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeSnappyBlockAsm64K
+ JMP memmove_long_emit_remainder_encodeSnappyBlockAsm64K
+
+one_byte_emit_remainder_encodeSnappyBlockAsm64K:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeSnappyBlockAsm64K:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm64K_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm64K_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm64K_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm64K_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm64K_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm64K_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm64K_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm64K
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm64K_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm64K
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm64K_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm64K
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm64K_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm64K
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm64K_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm64K
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm64K_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeSnappyBlockAsm64K:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeSnappyBlockAsm64K
+
+memmove_long_emit_remainder_encodeSnappyBlockAsm64K:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm64Klarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm64Klarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm64Klarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm64Klarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm64Klarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeSnappyBlockAsm64K:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeSnappyBlockAsm12B(dst []byte, src []byte, tmp *[16384]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeSnappyBlockAsm12B(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000080, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeSnappyBlockAsm12B:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeSnappyBlockAsm12B
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL DX, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeSnappyBlockAsm12B:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x05, SI
+ LEAL 4(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeSnappyBlockAsm12B
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x000000cf1bbcdcbb, R9
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHRQ $0x08, R11
+ SHLQ $0x18, R10
+ IMULQ R9, R10
+ SHRQ $0x34, R10
+ SHLQ $0x18, R11
+ IMULQ R9, R11
+ SHRQ $0x34, R11
+ MOVL (AX)(R10*4), SI
+ MOVL (AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ LEAL 1(DX), R10
+ MOVL R10, (AX)(R11*4)
+ MOVQ DI, R10
+ SHRQ $0x10, R10
+ SHLQ $0x18, R10
+ IMULQ R9, R10
+ SHRQ $0x34, R10
+ MOVL DX, R9
+ SUBL 16(SP), R9
+ MOVL 1(BX)(R9*1), R11
+ MOVQ DI, R9
+ SHRQ $0x08, R9
+ CMPL R9, R11
+ JNE no_repeat_found_encodeSnappyBlockAsm12B
+ LEAL 1(DX), DI
+ MOVL 12(SP), SI
+ MOVL DI, R8
+ SUBL 16(SP), R8
+ JZ repeat_extend_back_end_encodeSnappyBlockAsm12B
+
+repeat_extend_back_loop_encodeSnappyBlockAsm12B:
+ CMPL DI, SI
+ JBE repeat_extend_back_end_encodeSnappyBlockAsm12B
+ MOVB -1(BX)(R8*1), R9
+ MOVB -1(BX)(DI*1), R10
+ CMPB R9, R10
+ JNE repeat_extend_back_end_encodeSnappyBlockAsm12B
+ LEAL -1(DI), DI
+ DECL R8
+ JNZ repeat_extend_back_loop_encodeSnappyBlockAsm12B
+
+repeat_extend_back_end_encodeSnappyBlockAsm12B:
+ MOVL DI, SI
+ SUBL 12(SP), SI
+ LEAQ 3(CX)(SI*1), SI
+ CMPQ SI, (SP)
+ JB repeat_dst_size_check_encodeSnappyBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+repeat_dst_size_check_encodeSnappyBlockAsm12B:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm12B
+ MOVL DI, R8
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R9
+ SUBL SI, R8
+ LEAL -1(R8), SI
+ CMPL SI, $0x3c
+ JB one_byte_repeat_emit_encodeSnappyBlockAsm12B
+ CMPL SI, $0x00000100
+ JB two_bytes_repeat_emit_encodeSnappyBlockAsm12B
+ JB three_bytes_repeat_emit_encodeSnappyBlockAsm12B
+
+three_bytes_repeat_emit_encodeSnappyBlockAsm12B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_repeat_emit_encodeSnappyBlockAsm12B
+
+two_bytes_repeat_emit_encodeSnappyBlockAsm12B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_repeat_emit_encodeSnappyBlockAsm12B
+ JMP memmove_long_repeat_emit_encodeSnappyBlockAsm12B
+
+one_byte_repeat_emit_encodeSnappyBlockAsm12B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_repeat_emit_encodeSnappyBlockAsm12B:
+ LEAQ (CX)(R8*1), SI
+
+ // genMemMoveShort
+ CMPQ R8, $0x08
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm12B_memmove_move_8
+ CMPQ R8, $0x10
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm12B_memmove_move_8through16
+ CMPQ R8, $0x20
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm12B_memmove_move_17through32
+ JMP emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm12B_memmove_move_33through64
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm12B_memmove_move_8:
+ MOVQ (R9), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm12B
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm12B_memmove_move_8through16:
+ MOVQ (R9), R10
+ MOVQ -8(R9)(R8*1), R9
+ MOVQ R10, (CX)
+ MOVQ R9, -8(CX)(R8*1)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm12B
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm12B_memmove_move_17through32:
+ MOVOU (R9), X0
+ MOVOU -16(R9)(R8*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R8*1)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm12B
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm12B_memmove_move_33through64:
+ MOVOU (R9), X0
+ MOVOU 16(R9), X1
+ MOVOU -32(R9)(R8*1), X2
+ MOVOU -16(R9)(R8*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R8*1)
+ MOVOU X3, -16(CX)(R8*1)
+
+memmove_end_copy_repeat_emit_encodeSnappyBlockAsm12B:
+ MOVQ SI, CX
+ JMP emit_literal_done_repeat_emit_encodeSnappyBlockAsm12B
+
+memmove_long_repeat_emit_encodeSnappyBlockAsm12B:
+ LEAQ (CX)(R8*1), SI
+
+ // genMemMoveLong
+ MOVOU (R9), X0
+ MOVOU 16(R9), X1
+ MOVOU -32(R9)(R8*1), X2
+ MOVOU -16(R9)(R8*1), X3
+ MOVQ R8, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm12Blarge_forward_sse_loop_32
+ LEAQ -32(R9)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm12Blarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm12Blarge_big_loop_back
+
+emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm12Blarge_forward_sse_loop_32:
+ MOVOU -32(R9)(R12*1), X4
+ MOVOU -16(R9)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R8, R12
+ JAE emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm12Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R8*1)
+ MOVOU X3, -16(CX)(R8*1)
+ MOVQ SI, CX
+
+emit_literal_done_repeat_emit_encodeSnappyBlockAsm12B:
+ ADDL $0x05, DX
+ MOVL DX, SI
+ SUBL 16(SP), SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R11, R11
+
+matchlen_loopback_16_repeat_extend_encodeSnappyBlockAsm12B:
+ CMPL R8, $0x10
+ JB matchlen_match8_repeat_extend_encodeSnappyBlockAsm12B
+ MOVQ (R9)(R11*1), R10
+ MOVQ 8(R9)(R11*1), R12
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm12B
+ XORQ 8(SI)(R11*1), R12
+ JNZ matchlen_bsf_16repeat_extend_encodeSnappyBlockAsm12B
+ LEAL -16(R8), R8
+ LEAL 16(R11), R11
+ JMP matchlen_loopback_16_repeat_extend_encodeSnappyBlockAsm12B
+
+matchlen_bsf_16repeat_extend_encodeSnappyBlockAsm12B:
+#ifdef GOAMD64_v3
+ TZCNTQ R12, R12
+
+#else
+ BSFQ R12, R12
+
+#endif
+ SARQ $0x03, R12
+ LEAL 8(R11)(R12*1), R11
+ JMP repeat_extend_forward_end_encodeSnappyBlockAsm12B
+
+matchlen_match8_repeat_extend_encodeSnappyBlockAsm12B:
+ CMPL R8, $0x08
+ JB matchlen_match4_repeat_extend_encodeSnappyBlockAsm12B
+ MOVQ (R9)(R11*1), R10
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm12B
+ LEAL -8(R8), R8
+ LEAL 8(R11), R11
+ JMP matchlen_match4_repeat_extend_encodeSnappyBlockAsm12B
+
+matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm12B:
+#ifdef GOAMD64_v3
+ TZCNTQ R10, R10
+
+#else
+ BSFQ R10, R10
+
+#endif
+ SARQ $0x03, R10
+ LEAL (R11)(R10*1), R11
+ JMP repeat_extend_forward_end_encodeSnappyBlockAsm12B
+
+matchlen_match4_repeat_extend_encodeSnappyBlockAsm12B:
+ CMPL R8, $0x04
+ JB matchlen_match2_repeat_extend_encodeSnappyBlockAsm12B
+ MOVL (R9)(R11*1), R10
+ CMPL (SI)(R11*1), R10
+ JNE matchlen_match2_repeat_extend_encodeSnappyBlockAsm12B
+ LEAL -4(R8), R8
+ LEAL 4(R11), R11
+
+matchlen_match2_repeat_extend_encodeSnappyBlockAsm12B:
+ CMPL R8, $0x01
+ JE matchlen_match1_repeat_extend_encodeSnappyBlockAsm12B
+ JB repeat_extend_forward_end_encodeSnappyBlockAsm12B
+ MOVW (R9)(R11*1), R10
+ CMPW (SI)(R11*1), R10
+ JNE matchlen_match1_repeat_extend_encodeSnappyBlockAsm12B
+ LEAL 2(R11), R11
+ SUBL $0x02, R8
+ JZ repeat_extend_forward_end_encodeSnappyBlockAsm12B
+
+matchlen_match1_repeat_extend_encodeSnappyBlockAsm12B:
+ MOVB (R9)(R11*1), R10
+ CMPB (SI)(R11*1), R10
+ JNE repeat_extend_forward_end_encodeSnappyBlockAsm12B
+ LEAL 1(R11), R11
+
+repeat_extend_forward_end_encodeSnappyBlockAsm12B:
+ ADDL R11, DX
+ MOVL DX, SI
+ SUBL DI, SI
+ MOVL 16(SP), DI
+
+ // emitCopy
+two_byte_offset_repeat_as_copy_encodeSnappyBlockAsm12B:
+ CMPL SI, $0x40
+ JBE two_byte_offset_short_repeat_as_copy_encodeSnappyBlockAsm12B
+ MOVB $0xee, (CX)
+ MOVW DI, 1(CX)
+ LEAL -60(SI), SI
+ ADDQ $0x03, CX
+ JMP two_byte_offset_repeat_as_copy_encodeSnappyBlockAsm12B
+
+two_byte_offset_short_repeat_as_copy_encodeSnappyBlockAsm12B:
+ MOVL SI, R8
+ SHLL $0x02, R8
+ CMPL SI, $0x0c
+ JAE emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm12B
+ CMPL DI, $0x00000800
+ JAE emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm12B
+ LEAL -15(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeSnappyBlockAsm12B
+
+emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm12B:
+ LEAL -2(R8), R8
+ MOVB R8, (CX)
+ MOVW DI, 1(CX)
+ ADDQ $0x03, CX
+
+repeat_end_emit_encodeSnappyBlockAsm12B:
+ MOVL DX, 12(SP)
+ JMP search_loop_encodeSnappyBlockAsm12B
+
+no_repeat_found_encodeSnappyBlockAsm12B:
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeSnappyBlockAsm12B
+ SHRQ $0x08, DI
+ MOVL (AX)(R10*4), SI
+ LEAL 2(DX), R9
+ CMPL (BX)(R8*1), DI
+ JEQ candidate2_match_encodeSnappyBlockAsm12B
+ MOVL R9, (AX)(R10*4)
+ SHRQ $0x08, DI
+ CMPL (BX)(SI*1), DI
+ JEQ candidate3_match_encodeSnappyBlockAsm12B
+ MOVL 20(SP), DX
+ JMP search_loop_encodeSnappyBlockAsm12B
+
+candidate3_match_encodeSnappyBlockAsm12B:
+ ADDL $0x02, DX
+ JMP candidate_match_encodeSnappyBlockAsm12B
+
+candidate2_match_encodeSnappyBlockAsm12B:
+ MOVL R9, (AX)(R10*4)
+ INCL DX
+ MOVL R8, SI
+
+candidate_match_encodeSnappyBlockAsm12B:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeSnappyBlockAsm12B
+
+match_extend_back_loop_encodeSnappyBlockAsm12B:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeSnappyBlockAsm12B
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeSnappyBlockAsm12B
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeSnappyBlockAsm12B
+ JMP match_extend_back_loop_encodeSnappyBlockAsm12B
+
+match_extend_back_end_encodeSnappyBlockAsm12B:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeSnappyBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeSnappyBlockAsm12B:
+ MOVL DX, DI
+ MOVL 12(SP), R8
+ CMPL R8, DI
+ JEQ emit_literal_done_match_emit_encodeSnappyBlockAsm12B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(R8*1), DI
+ SUBL R8, R9
+ LEAL -1(R9), R8
+ CMPL R8, $0x3c
+ JB one_byte_match_emit_encodeSnappyBlockAsm12B
+ CMPL R8, $0x00000100
+ JB two_bytes_match_emit_encodeSnappyBlockAsm12B
+ JB three_bytes_match_emit_encodeSnappyBlockAsm12B
+
+three_bytes_match_emit_encodeSnappyBlockAsm12B:
+ MOVB $0xf4, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeSnappyBlockAsm12B
+
+two_bytes_match_emit_encodeSnappyBlockAsm12B:
+ MOVB $0xf0, (CX)
+ MOVB R8, 1(CX)
+ ADDQ $0x02, CX
+ CMPL R8, $0x40
+ JB memmove_match_emit_encodeSnappyBlockAsm12B
+ JMP memmove_long_match_emit_encodeSnappyBlockAsm12B
+
+one_byte_match_emit_encodeSnappyBlockAsm12B:
+ SHLB $0x02, R8
+ MOVB R8, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeSnappyBlockAsm12B:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm12B_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm12B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm12B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeSnappyBlockAsm12B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm12B_memmove_move_8:
+ MOVQ (DI), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm12B_memmove_move_8through16:
+ MOVQ (DI), R10
+ MOVQ -8(DI)(R9*1), DI
+ MOVQ R10, (CX)
+ MOVQ DI, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm12B_memmove_move_17through32:
+ MOVOU (DI), X0
+ MOVOU -16(DI)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm12B_memmove_move_33through64:
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeSnappyBlockAsm12B:
+ MOVQ R8, CX
+ JMP emit_literal_done_match_emit_encodeSnappyBlockAsm12B
+
+memmove_long_match_emit_encodeSnappyBlockAsm12B:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveLong
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVQ R9, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm12Blarge_forward_sse_loop_32
+ LEAQ -32(DI)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm12Blarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm12Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm12Blarge_forward_sse_loop_32:
+ MOVOU -32(DI)(R12*1), X4
+ MOVOU -16(DI)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R9, R12
+ JAE emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm12Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ R8, CX
+
+emit_literal_done_match_emit_encodeSnappyBlockAsm12B:
+match_nolit_loop_encodeSnappyBlockAsm12B:
+ MOVL DX, DI
+ SUBL SI, DI
+ MOVL DI, 16(SP)
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), DI
+ SUBL DX, DI
+ LEAQ (BX)(DX*1), R8
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R10, R10
+
+matchlen_loopback_16_match_nolit_encodeSnappyBlockAsm12B:
+ CMPL DI, $0x10
+ JB matchlen_match8_match_nolit_encodeSnappyBlockAsm12B
+ MOVQ (R8)(R10*1), R9
+ MOVQ 8(R8)(R10*1), R11
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm12B
+ XORQ 8(SI)(R10*1), R11
+ JNZ matchlen_bsf_16match_nolit_encodeSnappyBlockAsm12B
+ LEAL -16(DI), DI
+ LEAL 16(R10), R10
+ JMP matchlen_loopback_16_match_nolit_encodeSnappyBlockAsm12B
+
+matchlen_bsf_16match_nolit_encodeSnappyBlockAsm12B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL 8(R10)(R11*1), R10
+ JMP match_nolit_end_encodeSnappyBlockAsm12B
+
+matchlen_match8_match_nolit_encodeSnappyBlockAsm12B:
+ CMPL DI, $0x08
+ JB matchlen_match4_match_nolit_encodeSnappyBlockAsm12B
+ MOVQ (R8)(R10*1), R9
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm12B
+ LEAL -8(DI), DI
+ LEAL 8(R10), R10
+ JMP matchlen_match4_match_nolit_encodeSnappyBlockAsm12B
+
+matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm12B:
+#ifdef GOAMD64_v3
+ TZCNTQ R9, R9
+
+#else
+ BSFQ R9, R9
+
+#endif
+ SARQ $0x03, R9
+ LEAL (R10)(R9*1), R10
+ JMP match_nolit_end_encodeSnappyBlockAsm12B
+
+matchlen_match4_match_nolit_encodeSnappyBlockAsm12B:
+ CMPL DI, $0x04
+ JB matchlen_match2_match_nolit_encodeSnappyBlockAsm12B
+ MOVL (R8)(R10*1), R9
+ CMPL (SI)(R10*1), R9
+ JNE matchlen_match2_match_nolit_encodeSnappyBlockAsm12B
+ LEAL -4(DI), DI
+ LEAL 4(R10), R10
+
+matchlen_match2_match_nolit_encodeSnappyBlockAsm12B:
+ CMPL DI, $0x01
+ JE matchlen_match1_match_nolit_encodeSnappyBlockAsm12B
+ JB match_nolit_end_encodeSnappyBlockAsm12B
+ MOVW (R8)(R10*1), R9
+ CMPW (SI)(R10*1), R9
+ JNE matchlen_match1_match_nolit_encodeSnappyBlockAsm12B
+ LEAL 2(R10), R10
+ SUBL $0x02, DI
+ JZ match_nolit_end_encodeSnappyBlockAsm12B
+
+matchlen_match1_match_nolit_encodeSnappyBlockAsm12B:
+ MOVB (R8)(R10*1), R9
+ CMPB (SI)(R10*1), R9
+ JNE match_nolit_end_encodeSnappyBlockAsm12B
+ LEAL 1(R10), R10
+
+match_nolit_end_encodeSnappyBlockAsm12B:
+ ADDL R10, DX
+ MOVL 16(SP), SI
+ ADDL $0x04, R10
+ MOVL DX, 12(SP)
+
+ // emitCopy
+two_byte_offset_match_nolit_encodeSnappyBlockAsm12B:
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeSnappyBlockAsm12B
+ MOVB $0xee, (CX)
+ MOVW SI, 1(CX)
+ LEAL -60(R10), R10
+ ADDQ $0x03, CX
+ JMP two_byte_offset_match_nolit_encodeSnappyBlockAsm12B
+
+two_byte_offset_short_match_nolit_encodeSnappyBlockAsm12B:
+ MOVL R10, DI
+ SHLL $0x02, DI
+ CMPL R10, $0x0c
+ JAE emit_copy_three_match_nolit_encodeSnappyBlockAsm12B
+ CMPL SI, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeSnappyBlockAsm12B
+ LEAL -15(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeSnappyBlockAsm12B
+
+emit_copy_three_match_nolit_encodeSnappyBlockAsm12B:
+ LEAL -2(DI), DI
+ MOVB DI, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeSnappyBlockAsm12B:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeSnappyBlockAsm12B
+ MOVQ -2(BX)(DX*1), DI
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeSnappyBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeSnappyBlockAsm12B:
+ MOVQ $0x000000cf1bbcdcbb, R9
+ MOVQ DI, R8
+ SHRQ $0x10, DI
+ MOVQ DI, SI
+ SHLQ $0x18, R8
+ IMULQ R9, R8
+ SHRQ $0x34, R8
+ SHLQ $0x18, SI
+ IMULQ R9, SI
+ SHRQ $0x34, SI
+ LEAL -2(DX), R9
+ LEAQ (AX)(SI*4), R10
+ MOVL (R10), SI
+ MOVL R9, (AX)(R8*4)
+ MOVL DX, (R10)
+ CMPL (BX)(SI*1), DI
+ JEQ match_nolit_loop_encodeSnappyBlockAsm12B
+ INCL DX
+ JMP search_loop_encodeSnappyBlockAsm12B
+
+emit_remainder_encodeSnappyBlockAsm12B:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeSnappyBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeSnappyBlockAsm12B:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeSnappyBlockAsm12B
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeSnappyBlockAsm12B
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeSnappyBlockAsm12B
+ JB three_bytes_emit_remainder_encodeSnappyBlockAsm12B
+
+three_bytes_emit_remainder_encodeSnappyBlockAsm12B:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBlockAsm12B
+
+two_bytes_emit_remainder_encodeSnappyBlockAsm12B:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeSnappyBlockAsm12B
+ JMP memmove_long_emit_remainder_encodeSnappyBlockAsm12B
+
+one_byte_emit_remainder_encodeSnappyBlockAsm12B:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeSnappyBlockAsm12B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm12B_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm12B_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm12B_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm12B_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm12B_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm12B_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm12B_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm12B_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm12B_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm12B_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm12B_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm12B_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeSnappyBlockAsm12B:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeSnappyBlockAsm12B
+
+memmove_long_emit_remainder_encodeSnappyBlockAsm12B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm12Blarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm12Blarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm12Blarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm12Blarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm12Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeSnappyBlockAsm12B:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeSnappyBlockAsm10B(dst []byte, src []byte, tmp *[4096]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeSnappyBlockAsm10B(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000020, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeSnappyBlockAsm10B:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeSnappyBlockAsm10B
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL DX, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeSnappyBlockAsm10B:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x05, SI
+ LEAL 4(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeSnappyBlockAsm10B
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x9e3779b1, R9
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHRQ $0x08, R11
+ SHLQ $0x20, R10
+ IMULQ R9, R10
+ SHRQ $0x36, R10
+ SHLQ $0x20, R11
+ IMULQ R9, R11
+ SHRQ $0x36, R11
+ MOVL (AX)(R10*4), SI
+ MOVL (AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ LEAL 1(DX), R10
+ MOVL R10, (AX)(R11*4)
+ MOVQ DI, R10
+ SHRQ $0x10, R10
+ SHLQ $0x20, R10
+ IMULQ R9, R10
+ SHRQ $0x36, R10
+ MOVL DX, R9
+ SUBL 16(SP), R9
+ MOVL 1(BX)(R9*1), R11
+ MOVQ DI, R9
+ SHRQ $0x08, R9
+ CMPL R9, R11
+ JNE no_repeat_found_encodeSnappyBlockAsm10B
+ LEAL 1(DX), DI
+ MOVL 12(SP), SI
+ MOVL DI, R8
+ SUBL 16(SP), R8
+ JZ repeat_extend_back_end_encodeSnappyBlockAsm10B
+
+repeat_extend_back_loop_encodeSnappyBlockAsm10B:
+ CMPL DI, SI
+ JBE repeat_extend_back_end_encodeSnappyBlockAsm10B
+ MOVB -1(BX)(R8*1), R9
+ MOVB -1(BX)(DI*1), R10
+ CMPB R9, R10
+ JNE repeat_extend_back_end_encodeSnappyBlockAsm10B
+ LEAL -1(DI), DI
+ DECL R8
+ JNZ repeat_extend_back_loop_encodeSnappyBlockAsm10B
+
+repeat_extend_back_end_encodeSnappyBlockAsm10B:
+ MOVL DI, SI
+ SUBL 12(SP), SI
+ LEAQ 3(CX)(SI*1), SI
+ CMPQ SI, (SP)
+ JB repeat_dst_size_check_encodeSnappyBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+repeat_dst_size_check_encodeSnappyBlockAsm10B:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm10B
+ MOVL DI, R8
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R9
+ SUBL SI, R8
+ LEAL -1(R8), SI
+ CMPL SI, $0x3c
+ JB one_byte_repeat_emit_encodeSnappyBlockAsm10B
+ CMPL SI, $0x00000100
+ JB two_bytes_repeat_emit_encodeSnappyBlockAsm10B
+ JB three_bytes_repeat_emit_encodeSnappyBlockAsm10B
+
+three_bytes_repeat_emit_encodeSnappyBlockAsm10B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_repeat_emit_encodeSnappyBlockAsm10B
+
+two_bytes_repeat_emit_encodeSnappyBlockAsm10B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_repeat_emit_encodeSnappyBlockAsm10B
+ JMP memmove_long_repeat_emit_encodeSnappyBlockAsm10B
+
+one_byte_repeat_emit_encodeSnappyBlockAsm10B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_repeat_emit_encodeSnappyBlockAsm10B:
+ LEAQ (CX)(R8*1), SI
+
+ // genMemMoveShort
+ CMPQ R8, $0x08
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm10B_memmove_move_8
+ CMPQ R8, $0x10
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm10B_memmove_move_8through16
+ CMPQ R8, $0x20
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm10B_memmove_move_17through32
+ JMP emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm10B_memmove_move_33through64
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm10B_memmove_move_8:
+ MOVQ (R9), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm10B
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm10B_memmove_move_8through16:
+ MOVQ (R9), R10
+ MOVQ -8(R9)(R8*1), R9
+ MOVQ R10, (CX)
+ MOVQ R9, -8(CX)(R8*1)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm10B
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm10B_memmove_move_17through32:
+ MOVOU (R9), X0
+ MOVOU -16(R9)(R8*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R8*1)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm10B
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm10B_memmove_move_33through64:
+ MOVOU (R9), X0
+ MOVOU 16(R9), X1
+ MOVOU -32(R9)(R8*1), X2
+ MOVOU -16(R9)(R8*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R8*1)
+ MOVOU X3, -16(CX)(R8*1)
+
+memmove_end_copy_repeat_emit_encodeSnappyBlockAsm10B:
+ MOVQ SI, CX
+ JMP emit_literal_done_repeat_emit_encodeSnappyBlockAsm10B
+
+memmove_long_repeat_emit_encodeSnappyBlockAsm10B:
+ LEAQ (CX)(R8*1), SI
+
+ // genMemMoveLong
+ MOVOU (R9), X0
+ MOVOU 16(R9), X1
+ MOVOU -32(R9)(R8*1), X2
+ MOVOU -16(R9)(R8*1), X3
+ MOVQ R8, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm10Blarge_forward_sse_loop_32
+ LEAQ -32(R9)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm10Blarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm10Blarge_big_loop_back
+
+emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm10Blarge_forward_sse_loop_32:
+ MOVOU -32(R9)(R12*1), X4
+ MOVOU -16(R9)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R8, R12
+ JAE emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm10Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R8*1)
+ MOVOU X3, -16(CX)(R8*1)
+ MOVQ SI, CX
+
+emit_literal_done_repeat_emit_encodeSnappyBlockAsm10B:
+ ADDL $0x05, DX
+ MOVL DX, SI
+ SUBL 16(SP), SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R11, R11
+
+matchlen_loopback_16_repeat_extend_encodeSnappyBlockAsm10B:
+ CMPL R8, $0x10
+ JB matchlen_match8_repeat_extend_encodeSnappyBlockAsm10B
+ MOVQ (R9)(R11*1), R10
+ MOVQ 8(R9)(R11*1), R12
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm10B
+ XORQ 8(SI)(R11*1), R12
+ JNZ matchlen_bsf_16repeat_extend_encodeSnappyBlockAsm10B
+ LEAL -16(R8), R8
+ LEAL 16(R11), R11
+ JMP matchlen_loopback_16_repeat_extend_encodeSnappyBlockAsm10B
+
+matchlen_bsf_16repeat_extend_encodeSnappyBlockAsm10B:
+#ifdef GOAMD64_v3
+ TZCNTQ R12, R12
+
+#else
+ BSFQ R12, R12
+
+#endif
+ SARQ $0x03, R12
+ LEAL 8(R11)(R12*1), R11
+ JMP repeat_extend_forward_end_encodeSnappyBlockAsm10B
+
+matchlen_match8_repeat_extend_encodeSnappyBlockAsm10B:
+ CMPL R8, $0x08
+ JB matchlen_match4_repeat_extend_encodeSnappyBlockAsm10B
+ MOVQ (R9)(R11*1), R10
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm10B
+ LEAL -8(R8), R8
+ LEAL 8(R11), R11
+ JMP matchlen_match4_repeat_extend_encodeSnappyBlockAsm10B
+
+matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm10B:
+#ifdef GOAMD64_v3
+ TZCNTQ R10, R10
+
+#else
+ BSFQ R10, R10
+
+#endif
+ SARQ $0x03, R10
+ LEAL (R11)(R10*1), R11
+ JMP repeat_extend_forward_end_encodeSnappyBlockAsm10B
+
+matchlen_match4_repeat_extend_encodeSnappyBlockAsm10B:
+ CMPL R8, $0x04
+ JB matchlen_match2_repeat_extend_encodeSnappyBlockAsm10B
+ MOVL (R9)(R11*1), R10
+ CMPL (SI)(R11*1), R10
+ JNE matchlen_match2_repeat_extend_encodeSnappyBlockAsm10B
+ LEAL -4(R8), R8
+ LEAL 4(R11), R11
+
+matchlen_match2_repeat_extend_encodeSnappyBlockAsm10B:
+ CMPL R8, $0x01
+ JE matchlen_match1_repeat_extend_encodeSnappyBlockAsm10B
+ JB repeat_extend_forward_end_encodeSnappyBlockAsm10B
+ MOVW (R9)(R11*1), R10
+ CMPW (SI)(R11*1), R10
+ JNE matchlen_match1_repeat_extend_encodeSnappyBlockAsm10B
+ LEAL 2(R11), R11
+ SUBL $0x02, R8
+ JZ repeat_extend_forward_end_encodeSnappyBlockAsm10B
+
+matchlen_match1_repeat_extend_encodeSnappyBlockAsm10B:
+ MOVB (R9)(R11*1), R10
+ CMPB (SI)(R11*1), R10
+ JNE repeat_extend_forward_end_encodeSnappyBlockAsm10B
+ LEAL 1(R11), R11
+
+repeat_extend_forward_end_encodeSnappyBlockAsm10B:
+ ADDL R11, DX
+ MOVL DX, SI
+ SUBL DI, SI
+ MOVL 16(SP), DI
+
+ // emitCopy
+two_byte_offset_repeat_as_copy_encodeSnappyBlockAsm10B:
+ CMPL SI, $0x40
+ JBE two_byte_offset_short_repeat_as_copy_encodeSnappyBlockAsm10B
+ MOVB $0xee, (CX)
+ MOVW DI, 1(CX)
+ LEAL -60(SI), SI
+ ADDQ $0x03, CX
+ JMP two_byte_offset_repeat_as_copy_encodeSnappyBlockAsm10B
+
+two_byte_offset_short_repeat_as_copy_encodeSnappyBlockAsm10B:
+ MOVL SI, R8
+ SHLL $0x02, R8
+ CMPL SI, $0x0c
+ JAE emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm10B
+ CMPL DI, $0x00000800
+ JAE emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm10B
+ LEAL -15(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeSnappyBlockAsm10B
+
+emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm10B:
+ LEAL -2(R8), R8
+ MOVB R8, (CX)
+ MOVW DI, 1(CX)
+ ADDQ $0x03, CX
+
+repeat_end_emit_encodeSnappyBlockAsm10B:
+ MOVL DX, 12(SP)
+ JMP search_loop_encodeSnappyBlockAsm10B
+
+no_repeat_found_encodeSnappyBlockAsm10B:
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeSnappyBlockAsm10B
+ SHRQ $0x08, DI
+ MOVL (AX)(R10*4), SI
+ LEAL 2(DX), R9
+ CMPL (BX)(R8*1), DI
+ JEQ candidate2_match_encodeSnappyBlockAsm10B
+ MOVL R9, (AX)(R10*4)
+ SHRQ $0x08, DI
+ CMPL (BX)(SI*1), DI
+ JEQ candidate3_match_encodeSnappyBlockAsm10B
+ MOVL 20(SP), DX
+ JMP search_loop_encodeSnappyBlockAsm10B
+
+candidate3_match_encodeSnappyBlockAsm10B:
+ ADDL $0x02, DX
+ JMP candidate_match_encodeSnappyBlockAsm10B
+
+candidate2_match_encodeSnappyBlockAsm10B:
+ MOVL R9, (AX)(R10*4)
+ INCL DX
+ MOVL R8, SI
+
+candidate_match_encodeSnappyBlockAsm10B:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeSnappyBlockAsm10B
+
+match_extend_back_loop_encodeSnappyBlockAsm10B:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeSnappyBlockAsm10B
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeSnappyBlockAsm10B
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeSnappyBlockAsm10B
+ JMP match_extend_back_loop_encodeSnappyBlockAsm10B
+
+match_extend_back_end_encodeSnappyBlockAsm10B:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeSnappyBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeSnappyBlockAsm10B:
+ MOVL DX, DI
+ MOVL 12(SP), R8
+ CMPL R8, DI
+ JEQ emit_literal_done_match_emit_encodeSnappyBlockAsm10B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(R8*1), DI
+ SUBL R8, R9
+ LEAL -1(R9), R8
+ CMPL R8, $0x3c
+ JB one_byte_match_emit_encodeSnappyBlockAsm10B
+ CMPL R8, $0x00000100
+ JB two_bytes_match_emit_encodeSnappyBlockAsm10B
+ JB three_bytes_match_emit_encodeSnappyBlockAsm10B
+
+three_bytes_match_emit_encodeSnappyBlockAsm10B:
+ MOVB $0xf4, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeSnappyBlockAsm10B
+
+two_bytes_match_emit_encodeSnappyBlockAsm10B:
+ MOVB $0xf0, (CX)
+ MOVB R8, 1(CX)
+ ADDQ $0x02, CX
+ CMPL R8, $0x40
+ JB memmove_match_emit_encodeSnappyBlockAsm10B
+ JMP memmove_long_match_emit_encodeSnappyBlockAsm10B
+
+one_byte_match_emit_encodeSnappyBlockAsm10B:
+ SHLB $0x02, R8
+ MOVB R8, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeSnappyBlockAsm10B:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm10B_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm10B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm10B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeSnappyBlockAsm10B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm10B_memmove_move_8:
+ MOVQ (DI), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm10B_memmove_move_8through16:
+ MOVQ (DI), R10
+ MOVQ -8(DI)(R9*1), DI
+ MOVQ R10, (CX)
+ MOVQ DI, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm10B_memmove_move_17through32:
+ MOVOU (DI), X0
+ MOVOU -16(DI)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm10B_memmove_move_33through64:
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeSnappyBlockAsm10B:
+ MOVQ R8, CX
+ JMP emit_literal_done_match_emit_encodeSnappyBlockAsm10B
+
+memmove_long_match_emit_encodeSnappyBlockAsm10B:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveLong
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVQ R9, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm10Blarge_forward_sse_loop_32
+ LEAQ -32(DI)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm10Blarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm10Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm10Blarge_forward_sse_loop_32:
+ MOVOU -32(DI)(R12*1), X4
+ MOVOU -16(DI)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R9, R12
+ JAE emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm10Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ R8, CX
+
+emit_literal_done_match_emit_encodeSnappyBlockAsm10B:
+match_nolit_loop_encodeSnappyBlockAsm10B:
+ MOVL DX, DI
+ SUBL SI, DI
+ MOVL DI, 16(SP)
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), DI
+ SUBL DX, DI
+ LEAQ (BX)(DX*1), R8
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R10, R10
+
+matchlen_loopback_16_match_nolit_encodeSnappyBlockAsm10B:
+ CMPL DI, $0x10
+ JB matchlen_match8_match_nolit_encodeSnappyBlockAsm10B
+ MOVQ (R8)(R10*1), R9
+ MOVQ 8(R8)(R10*1), R11
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm10B
+ XORQ 8(SI)(R10*1), R11
+ JNZ matchlen_bsf_16match_nolit_encodeSnappyBlockAsm10B
+ LEAL -16(DI), DI
+ LEAL 16(R10), R10
+ JMP matchlen_loopback_16_match_nolit_encodeSnappyBlockAsm10B
+
+matchlen_bsf_16match_nolit_encodeSnappyBlockAsm10B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL 8(R10)(R11*1), R10
+ JMP match_nolit_end_encodeSnappyBlockAsm10B
+
+matchlen_match8_match_nolit_encodeSnappyBlockAsm10B:
+ CMPL DI, $0x08
+ JB matchlen_match4_match_nolit_encodeSnappyBlockAsm10B
+ MOVQ (R8)(R10*1), R9
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm10B
+ LEAL -8(DI), DI
+ LEAL 8(R10), R10
+ JMP matchlen_match4_match_nolit_encodeSnappyBlockAsm10B
+
+matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm10B:
+#ifdef GOAMD64_v3
+ TZCNTQ R9, R9
+
+#else
+ BSFQ R9, R9
+
+#endif
+ SARQ $0x03, R9
+ LEAL (R10)(R9*1), R10
+ JMP match_nolit_end_encodeSnappyBlockAsm10B
+
+matchlen_match4_match_nolit_encodeSnappyBlockAsm10B:
+ CMPL DI, $0x04
+ JB matchlen_match2_match_nolit_encodeSnappyBlockAsm10B
+ MOVL (R8)(R10*1), R9
+ CMPL (SI)(R10*1), R9
+ JNE matchlen_match2_match_nolit_encodeSnappyBlockAsm10B
+ LEAL -4(DI), DI
+ LEAL 4(R10), R10
+
+matchlen_match2_match_nolit_encodeSnappyBlockAsm10B:
+ CMPL DI, $0x01
+ JE matchlen_match1_match_nolit_encodeSnappyBlockAsm10B
+ JB match_nolit_end_encodeSnappyBlockAsm10B
+ MOVW (R8)(R10*1), R9
+ CMPW (SI)(R10*1), R9
+ JNE matchlen_match1_match_nolit_encodeSnappyBlockAsm10B
+ LEAL 2(R10), R10
+ SUBL $0x02, DI
+ JZ match_nolit_end_encodeSnappyBlockAsm10B
+
+matchlen_match1_match_nolit_encodeSnappyBlockAsm10B:
+ MOVB (R8)(R10*1), R9
+ CMPB (SI)(R10*1), R9
+ JNE match_nolit_end_encodeSnappyBlockAsm10B
+ LEAL 1(R10), R10
+
+match_nolit_end_encodeSnappyBlockAsm10B:
+ ADDL R10, DX
+ MOVL 16(SP), SI
+ ADDL $0x04, R10
+ MOVL DX, 12(SP)
+
+ // emitCopy
+two_byte_offset_match_nolit_encodeSnappyBlockAsm10B:
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeSnappyBlockAsm10B
+ MOVB $0xee, (CX)
+ MOVW SI, 1(CX)
+ LEAL -60(R10), R10
+ ADDQ $0x03, CX
+ JMP two_byte_offset_match_nolit_encodeSnappyBlockAsm10B
+
+two_byte_offset_short_match_nolit_encodeSnappyBlockAsm10B:
+ MOVL R10, DI
+ SHLL $0x02, DI
+ CMPL R10, $0x0c
+ JAE emit_copy_three_match_nolit_encodeSnappyBlockAsm10B
+ CMPL SI, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeSnappyBlockAsm10B
+ LEAL -15(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeSnappyBlockAsm10B
+
+emit_copy_three_match_nolit_encodeSnappyBlockAsm10B:
+ LEAL -2(DI), DI
+ MOVB DI, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeSnappyBlockAsm10B:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeSnappyBlockAsm10B
+ MOVQ -2(BX)(DX*1), DI
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeSnappyBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeSnappyBlockAsm10B:
+ MOVQ $0x9e3779b1, R9
+ MOVQ DI, R8
+ SHRQ $0x10, DI
+ MOVQ DI, SI
+ SHLQ $0x20, R8
+ IMULQ R9, R8
+ SHRQ $0x36, R8
+ SHLQ $0x20, SI
+ IMULQ R9, SI
+ SHRQ $0x36, SI
+ LEAL -2(DX), R9
+ LEAQ (AX)(SI*4), R10
+ MOVL (R10), SI
+ MOVL R9, (AX)(R8*4)
+ MOVL DX, (R10)
+ CMPL (BX)(SI*1), DI
+ JEQ match_nolit_loop_encodeSnappyBlockAsm10B
+ INCL DX
+ JMP search_loop_encodeSnappyBlockAsm10B
+
+emit_remainder_encodeSnappyBlockAsm10B:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeSnappyBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeSnappyBlockAsm10B:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeSnappyBlockAsm10B
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeSnappyBlockAsm10B
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeSnappyBlockAsm10B
+ JB three_bytes_emit_remainder_encodeSnappyBlockAsm10B
+
+three_bytes_emit_remainder_encodeSnappyBlockAsm10B:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBlockAsm10B
+
+two_bytes_emit_remainder_encodeSnappyBlockAsm10B:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeSnappyBlockAsm10B
+ JMP memmove_long_emit_remainder_encodeSnappyBlockAsm10B
+
+one_byte_emit_remainder_encodeSnappyBlockAsm10B:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeSnappyBlockAsm10B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm10B_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm10B_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm10B_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm10B_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm10B_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm10B_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm10B_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm10B_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm10B_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm10B_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm10B_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm10B_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeSnappyBlockAsm10B:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeSnappyBlockAsm10B
+
+memmove_long_emit_remainder_encodeSnappyBlockAsm10B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm10Blarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm10Blarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm10Blarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm10Blarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm10Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeSnappyBlockAsm10B:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeSnappyBlockAsm8B(dst []byte, src []byte, tmp *[1024]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeSnappyBlockAsm8B(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000008, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeSnappyBlockAsm8B:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeSnappyBlockAsm8B
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL DX, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeSnappyBlockAsm8B:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x04, SI
+ LEAL 4(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeSnappyBlockAsm8B
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x9e3779b1, R9
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHRQ $0x08, R11
+ SHLQ $0x20, R10
+ IMULQ R9, R10
+ SHRQ $0x38, R10
+ SHLQ $0x20, R11
+ IMULQ R9, R11
+ SHRQ $0x38, R11
+ MOVL (AX)(R10*4), SI
+ MOVL (AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ LEAL 1(DX), R10
+ MOVL R10, (AX)(R11*4)
+ MOVQ DI, R10
+ SHRQ $0x10, R10
+ SHLQ $0x20, R10
+ IMULQ R9, R10
+ SHRQ $0x38, R10
+ MOVL DX, R9
+ SUBL 16(SP), R9
+ MOVL 1(BX)(R9*1), R11
+ MOVQ DI, R9
+ SHRQ $0x08, R9
+ CMPL R9, R11
+ JNE no_repeat_found_encodeSnappyBlockAsm8B
+ LEAL 1(DX), DI
+ MOVL 12(SP), SI
+ MOVL DI, R8
+ SUBL 16(SP), R8
+ JZ repeat_extend_back_end_encodeSnappyBlockAsm8B
+
+repeat_extend_back_loop_encodeSnappyBlockAsm8B:
+ CMPL DI, SI
+ JBE repeat_extend_back_end_encodeSnappyBlockAsm8B
+ MOVB -1(BX)(R8*1), R9
+ MOVB -1(BX)(DI*1), R10
+ CMPB R9, R10
+ JNE repeat_extend_back_end_encodeSnappyBlockAsm8B
+ LEAL -1(DI), DI
+ DECL R8
+ JNZ repeat_extend_back_loop_encodeSnappyBlockAsm8B
+
+repeat_extend_back_end_encodeSnappyBlockAsm8B:
+ MOVL DI, SI
+ SUBL 12(SP), SI
+ LEAQ 3(CX)(SI*1), SI
+ CMPQ SI, (SP)
+ JB repeat_dst_size_check_encodeSnappyBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+repeat_dst_size_check_encodeSnappyBlockAsm8B:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm8B
+ MOVL DI, R8
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R9
+ SUBL SI, R8
+ LEAL -1(R8), SI
+ CMPL SI, $0x3c
+ JB one_byte_repeat_emit_encodeSnappyBlockAsm8B
+ CMPL SI, $0x00000100
+ JB two_bytes_repeat_emit_encodeSnappyBlockAsm8B
+ JB three_bytes_repeat_emit_encodeSnappyBlockAsm8B
+
+three_bytes_repeat_emit_encodeSnappyBlockAsm8B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_repeat_emit_encodeSnappyBlockAsm8B
+
+two_bytes_repeat_emit_encodeSnappyBlockAsm8B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_repeat_emit_encodeSnappyBlockAsm8B
+ JMP memmove_long_repeat_emit_encodeSnappyBlockAsm8B
+
+one_byte_repeat_emit_encodeSnappyBlockAsm8B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_repeat_emit_encodeSnappyBlockAsm8B:
+ LEAQ (CX)(R8*1), SI
+
+ // genMemMoveShort
+ CMPQ R8, $0x08
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm8B_memmove_move_8
+ CMPQ R8, $0x10
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm8B_memmove_move_8through16
+ CMPQ R8, $0x20
+ JBE emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm8B_memmove_move_17through32
+ JMP emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm8B_memmove_move_33through64
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm8B_memmove_move_8:
+ MOVQ (R9), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm8B
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm8B_memmove_move_8through16:
+ MOVQ (R9), R10
+ MOVQ -8(R9)(R8*1), R9
+ MOVQ R10, (CX)
+ MOVQ R9, -8(CX)(R8*1)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm8B
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm8B_memmove_move_17through32:
+ MOVOU (R9), X0
+ MOVOU -16(R9)(R8*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R8*1)
+ JMP memmove_end_copy_repeat_emit_encodeSnappyBlockAsm8B
+
+emit_lit_memmove_repeat_emit_encodeSnappyBlockAsm8B_memmove_move_33through64:
+ MOVOU (R9), X0
+ MOVOU 16(R9), X1
+ MOVOU -32(R9)(R8*1), X2
+ MOVOU -16(R9)(R8*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R8*1)
+ MOVOU X3, -16(CX)(R8*1)
+
+memmove_end_copy_repeat_emit_encodeSnappyBlockAsm8B:
+ MOVQ SI, CX
+ JMP emit_literal_done_repeat_emit_encodeSnappyBlockAsm8B
+
+memmove_long_repeat_emit_encodeSnappyBlockAsm8B:
+ LEAQ (CX)(R8*1), SI
+
+ // genMemMoveLong
+ MOVOU (R9), X0
+ MOVOU 16(R9), X1
+ MOVOU -32(R9)(R8*1), X2
+ MOVOU -16(R9)(R8*1), X3
+ MOVQ R8, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm8Blarge_forward_sse_loop_32
+ LEAQ -32(R9)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm8Blarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm8Blarge_big_loop_back
+
+emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm8Blarge_forward_sse_loop_32:
+ MOVOU -32(R9)(R12*1), X4
+ MOVOU -16(R9)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R8, R12
+ JAE emit_lit_memmove_long_repeat_emit_encodeSnappyBlockAsm8Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R8*1)
+ MOVOU X3, -16(CX)(R8*1)
+ MOVQ SI, CX
+
+emit_literal_done_repeat_emit_encodeSnappyBlockAsm8B:
+ ADDL $0x05, DX
+ MOVL DX, SI
+ SUBL 16(SP), SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R11, R11
+
+matchlen_loopback_16_repeat_extend_encodeSnappyBlockAsm8B:
+ CMPL R8, $0x10
+ JB matchlen_match8_repeat_extend_encodeSnappyBlockAsm8B
+ MOVQ (R9)(R11*1), R10
+ MOVQ 8(R9)(R11*1), R12
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm8B
+ XORQ 8(SI)(R11*1), R12
+ JNZ matchlen_bsf_16repeat_extend_encodeSnappyBlockAsm8B
+ LEAL -16(R8), R8
+ LEAL 16(R11), R11
+ JMP matchlen_loopback_16_repeat_extend_encodeSnappyBlockAsm8B
+
+matchlen_bsf_16repeat_extend_encodeSnappyBlockAsm8B:
+#ifdef GOAMD64_v3
+ TZCNTQ R12, R12
+
+#else
+ BSFQ R12, R12
+
+#endif
+ SARQ $0x03, R12
+ LEAL 8(R11)(R12*1), R11
+ JMP repeat_extend_forward_end_encodeSnappyBlockAsm8B
+
+matchlen_match8_repeat_extend_encodeSnappyBlockAsm8B:
+ CMPL R8, $0x08
+ JB matchlen_match4_repeat_extend_encodeSnappyBlockAsm8B
+ MOVQ (R9)(R11*1), R10
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm8B
+ LEAL -8(R8), R8
+ LEAL 8(R11), R11
+ JMP matchlen_match4_repeat_extend_encodeSnappyBlockAsm8B
+
+matchlen_bsf_8_repeat_extend_encodeSnappyBlockAsm8B:
+#ifdef GOAMD64_v3
+ TZCNTQ R10, R10
+
+#else
+ BSFQ R10, R10
+
+#endif
+ SARQ $0x03, R10
+ LEAL (R11)(R10*1), R11
+ JMP repeat_extend_forward_end_encodeSnappyBlockAsm8B
+
+matchlen_match4_repeat_extend_encodeSnappyBlockAsm8B:
+ CMPL R8, $0x04
+ JB matchlen_match2_repeat_extend_encodeSnappyBlockAsm8B
+ MOVL (R9)(R11*1), R10
+ CMPL (SI)(R11*1), R10
+ JNE matchlen_match2_repeat_extend_encodeSnappyBlockAsm8B
+ LEAL -4(R8), R8
+ LEAL 4(R11), R11
+
+matchlen_match2_repeat_extend_encodeSnappyBlockAsm8B:
+ CMPL R8, $0x01
+ JE matchlen_match1_repeat_extend_encodeSnappyBlockAsm8B
+ JB repeat_extend_forward_end_encodeSnappyBlockAsm8B
+ MOVW (R9)(R11*1), R10
+ CMPW (SI)(R11*1), R10
+ JNE matchlen_match1_repeat_extend_encodeSnappyBlockAsm8B
+ LEAL 2(R11), R11
+ SUBL $0x02, R8
+ JZ repeat_extend_forward_end_encodeSnappyBlockAsm8B
+
+matchlen_match1_repeat_extend_encodeSnappyBlockAsm8B:
+ MOVB (R9)(R11*1), R10
+ CMPB (SI)(R11*1), R10
+ JNE repeat_extend_forward_end_encodeSnappyBlockAsm8B
+ LEAL 1(R11), R11
+
+repeat_extend_forward_end_encodeSnappyBlockAsm8B:
+ ADDL R11, DX
+ MOVL DX, SI
+ SUBL DI, SI
+ MOVL 16(SP), DI
+
+ // emitCopy
+two_byte_offset_repeat_as_copy_encodeSnappyBlockAsm8B:
+ CMPL SI, $0x40
+ JBE two_byte_offset_short_repeat_as_copy_encodeSnappyBlockAsm8B
+ MOVB $0xee, (CX)
+ MOVW DI, 1(CX)
+ LEAL -60(SI), SI
+ ADDQ $0x03, CX
+ JMP two_byte_offset_repeat_as_copy_encodeSnappyBlockAsm8B
+
+two_byte_offset_short_repeat_as_copy_encodeSnappyBlockAsm8B:
+ MOVL SI, R8
+ SHLL $0x02, R8
+ CMPL SI, $0x0c
+ JAE emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm8B
+ LEAL -15(R8), R8
+ MOVB DI, 1(CX)
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, R8
+ MOVB R8, (CX)
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_encodeSnappyBlockAsm8B
+
+emit_copy_three_repeat_as_copy_encodeSnappyBlockAsm8B:
+ LEAL -2(R8), R8
+ MOVB R8, (CX)
+ MOVW DI, 1(CX)
+ ADDQ $0x03, CX
+
+repeat_end_emit_encodeSnappyBlockAsm8B:
+ MOVL DX, 12(SP)
+ JMP search_loop_encodeSnappyBlockAsm8B
+
+no_repeat_found_encodeSnappyBlockAsm8B:
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeSnappyBlockAsm8B
+ SHRQ $0x08, DI
+ MOVL (AX)(R10*4), SI
+ LEAL 2(DX), R9
+ CMPL (BX)(R8*1), DI
+ JEQ candidate2_match_encodeSnappyBlockAsm8B
+ MOVL R9, (AX)(R10*4)
+ SHRQ $0x08, DI
+ CMPL (BX)(SI*1), DI
+ JEQ candidate3_match_encodeSnappyBlockAsm8B
+ MOVL 20(SP), DX
+ JMP search_loop_encodeSnappyBlockAsm8B
+
+candidate3_match_encodeSnappyBlockAsm8B:
+ ADDL $0x02, DX
+ JMP candidate_match_encodeSnappyBlockAsm8B
+
+candidate2_match_encodeSnappyBlockAsm8B:
+ MOVL R9, (AX)(R10*4)
+ INCL DX
+ MOVL R8, SI
+
+candidate_match_encodeSnappyBlockAsm8B:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeSnappyBlockAsm8B
+
+match_extend_back_loop_encodeSnappyBlockAsm8B:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeSnappyBlockAsm8B
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeSnappyBlockAsm8B
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeSnappyBlockAsm8B
+ JMP match_extend_back_loop_encodeSnappyBlockAsm8B
+
+match_extend_back_end_encodeSnappyBlockAsm8B:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeSnappyBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeSnappyBlockAsm8B:
+ MOVL DX, DI
+ MOVL 12(SP), R8
+ CMPL R8, DI
+ JEQ emit_literal_done_match_emit_encodeSnappyBlockAsm8B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(R8*1), DI
+ SUBL R8, R9
+ LEAL -1(R9), R8
+ CMPL R8, $0x3c
+ JB one_byte_match_emit_encodeSnappyBlockAsm8B
+ CMPL R8, $0x00000100
+ JB two_bytes_match_emit_encodeSnappyBlockAsm8B
+ JB three_bytes_match_emit_encodeSnappyBlockAsm8B
+
+three_bytes_match_emit_encodeSnappyBlockAsm8B:
+ MOVB $0xf4, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeSnappyBlockAsm8B
+
+two_bytes_match_emit_encodeSnappyBlockAsm8B:
+ MOVB $0xf0, (CX)
+ MOVB R8, 1(CX)
+ ADDQ $0x02, CX
+ CMPL R8, $0x40
+ JB memmove_match_emit_encodeSnappyBlockAsm8B
+ JMP memmove_long_match_emit_encodeSnappyBlockAsm8B
+
+one_byte_match_emit_encodeSnappyBlockAsm8B:
+ SHLB $0x02, R8
+ MOVB R8, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeSnappyBlockAsm8B:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm8B_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm8B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeSnappyBlockAsm8B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeSnappyBlockAsm8B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm8B_memmove_move_8:
+ MOVQ (DI), R10
+ MOVQ R10, (CX)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm8B_memmove_move_8through16:
+ MOVQ (DI), R10
+ MOVQ -8(DI)(R9*1), DI
+ MOVQ R10, (CX)
+ MOVQ DI, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm8B_memmove_move_17through32:
+ MOVOU (DI), X0
+ MOVOU -16(DI)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeSnappyBlockAsm8B_memmove_move_33through64:
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeSnappyBlockAsm8B:
+ MOVQ R8, CX
+ JMP emit_literal_done_match_emit_encodeSnappyBlockAsm8B
+
+memmove_long_match_emit_encodeSnappyBlockAsm8B:
+ LEAQ (CX)(R9*1), R8
+
+ // genMemMoveLong
+ MOVOU (DI), X0
+ MOVOU 16(DI), X1
+ MOVOU -32(DI)(R9*1), X2
+ MOVOU -16(DI)(R9*1), X3
+ MOVQ R9, R11
+ SHRQ $0x05, R11
+ MOVQ CX, R10
+ ANDL $0x0000001f, R10
+ MOVQ $0x00000040, R12
+ SUBQ R10, R12
+ DECQ R11
+ JA emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm8Blarge_forward_sse_loop_32
+ LEAQ -32(DI)(R12*1), R10
+ LEAQ -32(CX)(R12*1), R13
+
+emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm8Blarge_big_loop_back:
+ MOVOU (R10), X4
+ MOVOU 16(R10), X5
+ MOVOA X4, (R13)
+ MOVOA X5, 16(R13)
+ ADDQ $0x20, R13
+ ADDQ $0x20, R10
+ ADDQ $0x20, R12
+ DECQ R11
+ JNA emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm8Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm8Blarge_forward_sse_loop_32:
+ MOVOU -32(DI)(R12*1), X4
+ MOVOU -16(DI)(R12*1), X5
+ MOVOA X4, -32(CX)(R12*1)
+ MOVOA X5, -16(CX)(R12*1)
+ ADDQ $0x20, R12
+ CMPQ R9, R12
+ JAE emit_lit_memmove_long_match_emit_encodeSnappyBlockAsm8Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ R8, CX
+
+emit_literal_done_match_emit_encodeSnappyBlockAsm8B:
+match_nolit_loop_encodeSnappyBlockAsm8B:
+ MOVL DX, DI
+ SUBL SI, DI
+ MOVL DI, 16(SP)
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), DI
+ SUBL DX, DI
+ LEAQ (BX)(DX*1), R8
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R10, R10
+
+matchlen_loopback_16_match_nolit_encodeSnappyBlockAsm8B:
+ CMPL DI, $0x10
+ JB matchlen_match8_match_nolit_encodeSnappyBlockAsm8B
+ MOVQ (R8)(R10*1), R9
+ MOVQ 8(R8)(R10*1), R11
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm8B
+ XORQ 8(SI)(R10*1), R11
+ JNZ matchlen_bsf_16match_nolit_encodeSnappyBlockAsm8B
+ LEAL -16(DI), DI
+ LEAL 16(R10), R10
+ JMP matchlen_loopback_16_match_nolit_encodeSnappyBlockAsm8B
+
+matchlen_bsf_16match_nolit_encodeSnappyBlockAsm8B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL 8(R10)(R11*1), R10
+ JMP match_nolit_end_encodeSnappyBlockAsm8B
+
+matchlen_match8_match_nolit_encodeSnappyBlockAsm8B:
+ CMPL DI, $0x08
+ JB matchlen_match4_match_nolit_encodeSnappyBlockAsm8B
+ MOVQ (R8)(R10*1), R9
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm8B
+ LEAL -8(DI), DI
+ LEAL 8(R10), R10
+ JMP matchlen_match4_match_nolit_encodeSnappyBlockAsm8B
+
+matchlen_bsf_8_match_nolit_encodeSnappyBlockAsm8B:
+#ifdef GOAMD64_v3
+ TZCNTQ R9, R9
+
+#else
+ BSFQ R9, R9
+
+#endif
+ SARQ $0x03, R9
+ LEAL (R10)(R9*1), R10
+ JMP match_nolit_end_encodeSnappyBlockAsm8B
+
+matchlen_match4_match_nolit_encodeSnappyBlockAsm8B:
+ CMPL DI, $0x04
+ JB matchlen_match2_match_nolit_encodeSnappyBlockAsm8B
+ MOVL (R8)(R10*1), R9
+ CMPL (SI)(R10*1), R9
+ JNE matchlen_match2_match_nolit_encodeSnappyBlockAsm8B
+ LEAL -4(DI), DI
+ LEAL 4(R10), R10
+
+matchlen_match2_match_nolit_encodeSnappyBlockAsm8B:
+ CMPL DI, $0x01
+ JE matchlen_match1_match_nolit_encodeSnappyBlockAsm8B
+ JB match_nolit_end_encodeSnappyBlockAsm8B
+ MOVW (R8)(R10*1), R9
+ CMPW (SI)(R10*1), R9
+ JNE matchlen_match1_match_nolit_encodeSnappyBlockAsm8B
+ LEAL 2(R10), R10
+ SUBL $0x02, DI
+ JZ match_nolit_end_encodeSnappyBlockAsm8B
+
+matchlen_match1_match_nolit_encodeSnappyBlockAsm8B:
+ MOVB (R8)(R10*1), R9
+ CMPB (SI)(R10*1), R9
+ JNE match_nolit_end_encodeSnappyBlockAsm8B
+ LEAL 1(R10), R10
+
+match_nolit_end_encodeSnappyBlockAsm8B:
+ ADDL R10, DX
+ MOVL 16(SP), SI
+ ADDL $0x04, R10
+ MOVL DX, 12(SP)
+
+ // emitCopy
+two_byte_offset_match_nolit_encodeSnappyBlockAsm8B:
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeSnappyBlockAsm8B
+ MOVB $0xee, (CX)
+ MOVW SI, 1(CX)
+ LEAL -60(R10), R10
+ ADDQ $0x03, CX
+ JMP two_byte_offset_match_nolit_encodeSnappyBlockAsm8B
+
+two_byte_offset_short_match_nolit_encodeSnappyBlockAsm8B:
+ MOVL R10, DI
+ SHLL $0x02, DI
+ CMPL R10, $0x0c
+ JAE emit_copy_three_match_nolit_encodeSnappyBlockAsm8B
+ LEAL -15(DI), DI
+ MOVB SI, 1(CX)
+ SHRL $0x08, SI
+ SHLL $0x05, SI
+ ORL SI, DI
+ MOVB DI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeSnappyBlockAsm8B
+
+emit_copy_three_match_nolit_encodeSnappyBlockAsm8B:
+ LEAL -2(DI), DI
+ MOVB DI, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeSnappyBlockAsm8B:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeSnappyBlockAsm8B
+ MOVQ -2(BX)(DX*1), DI
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeSnappyBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeSnappyBlockAsm8B:
+ MOVQ $0x9e3779b1, R9
+ MOVQ DI, R8
+ SHRQ $0x10, DI
+ MOVQ DI, SI
+ SHLQ $0x20, R8
+ IMULQ R9, R8
+ SHRQ $0x38, R8
+ SHLQ $0x20, SI
+ IMULQ R9, SI
+ SHRQ $0x38, SI
+ LEAL -2(DX), R9
+ LEAQ (AX)(SI*4), R10
+ MOVL (R10), SI
+ MOVL R9, (AX)(R8*4)
+ MOVL DX, (R10)
+ CMPL (BX)(SI*1), DI
+ JEQ match_nolit_loop_encodeSnappyBlockAsm8B
+ INCL DX
+ JMP search_loop_encodeSnappyBlockAsm8B
+
+emit_remainder_encodeSnappyBlockAsm8B:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeSnappyBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeSnappyBlockAsm8B:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeSnappyBlockAsm8B
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeSnappyBlockAsm8B
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeSnappyBlockAsm8B
+ JB three_bytes_emit_remainder_encodeSnappyBlockAsm8B
+
+three_bytes_emit_remainder_encodeSnappyBlockAsm8B:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBlockAsm8B
+
+two_bytes_emit_remainder_encodeSnappyBlockAsm8B:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeSnappyBlockAsm8B
+ JMP memmove_long_emit_remainder_encodeSnappyBlockAsm8B
+
+one_byte_emit_remainder_encodeSnappyBlockAsm8B:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeSnappyBlockAsm8B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm8B_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm8B_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm8B_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm8B_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm8B_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm8B_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm8B_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm8B_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm8B_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm8B_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm8B_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBlockAsm8B_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeSnappyBlockAsm8B:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeSnappyBlockAsm8B
+
+memmove_long_emit_remainder_encodeSnappyBlockAsm8B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm8Blarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm8Blarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm8Blarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm8Blarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeSnappyBlockAsm8Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeSnappyBlockAsm8B:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeSnappyBetterBlockAsm(dst []byte, src []byte, tmp *[589824]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeSnappyBetterBlockAsm(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00001200, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeSnappyBetterBlockAsm:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeSnappyBetterBlockAsm
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL $0x00000000, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeSnappyBetterBlockAsm:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x07, SI
+ CMPL SI, $0x63
+ JBE check_maxskip_ok_encodeSnappyBetterBlockAsm
+ LEAL 100(DX), SI
+ JMP check_maxskip_cont_encodeSnappyBetterBlockAsm
+
+check_maxskip_ok_encodeSnappyBetterBlockAsm:
+ LEAL 1(DX)(SI*1), SI
+
+check_maxskip_cont_encodeSnappyBetterBlockAsm:
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeSnappyBetterBlockAsm
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x00cf1bbcdcbfa563, R9
+ MOVQ $0x9e3779b1, SI
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHLQ $0x08, R10
+ IMULQ R9, R10
+ SHRQ $0x2f, R10
+ SHLQ $0x20, R11
+ IMULQ SI, R11
+ SHRQ $0x32, R11
+ MOVL (AX)(R10*4), SI
+ MOVL 524288(AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ MOVL DX, 524288(AX)(R11*4)
+ MOVQ (BX)(SI*1), R10
+ MOVQ (BX)(R8*1), R11
+ CMPQ R10, DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm
+ CMPQ R11, DI
+ JNE no_short_found_encodeSnappyBetterBlockAsm
+ MOVL R8, SI
+ JMP candidate_match_encodeSnappyBetterBlockAsm
+
+no_short_found_encodeSnappyBetterBlockAsm:
+ CMPL R10, DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm
+ CMPL R11, DI
+ JEQ candidateS_match_encodeSnappyBetterBlockAsm
+ MOVL 20(SP), DX
+ JMP search_loop_encodeSnappyBetterBlockAsm
+
+candidateS_match_encodeSnappyBetterBlockAsm:
+ SHRQ $0x08, DI
+ MOVQ DI, R10
+ SHLQ $0x08, R10
+ IMULQ R9, R10
+ SHRQ $0x2f, R10
+ MOVL (AX)(R10*4), SI
+ INCL DX
+ MOVL DX, (AX)(R10*4)
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm
+ DECL DX
+ MOVL R8, SI
+
+candidate_match_encodeSnappyBetterBlockAsm:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeSnappyBetterBlockAsm
+
+match_extend_back_loop_encodeSnappyBetterBlockAsm:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeSnappyBetterBlockAsm
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeSnappyBetterBlockAsm
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeSnappyBetterBlockAsm
+ JMP match_extend_back_loop_encodeSnappyBetterBlockAsm
+
+match_extend_back_end_encodeSnappyBetterBlockAsm:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 5(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeSnappyBetterBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeSnappyBetterBlockAsm:
+ MOVL DX, DI
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), R10
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_match_nolit_encodeSnappyBetterBlockAsm:
+ CMPL R8, $0x10
+ JB matchlen_match8_match_nolit_encodeSnappyBetterBlockAsm
+ MOVQ (R9)(R12*1), R11
+ MOVQ 8(R9)(R12*1), R13
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm
+ XORQ 8(R10)(R12*1), R13
+ JNZ matchlen_bsf_16match_nolit_encodeSnappyBetterBlockAsm
+ LEAL -16(R8), R8
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_match_nolit_encodeSnappyBetterBlockAsm
+
+matchlen_bsf_16match_nolit_encodeSnappyBetterBlockAsm:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP match_nolit_end_encodeSnappyBetterBlockAsm
+
+matchlen_match8_match_nolit_encodeSnappyBetterBlockAsm:
+ CMPL R8, $0x08
+ JB matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm
+ MOVQ (R9)(R12*1), R11
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm
+ LEAL -8(R8), R8
+ LEAL 8(R12), R12
+ JMP matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm
+
+matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP match_nolit_end_encodeSnappyBetterBlockAsm
+
+matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm:
+ CMPL R8, $0x04
+ JB matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm
+ MOVL (R9)(R12*1), R11
+ CMPL (R10)(R12*1), R11
+ JNE matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm
+ LEAL -4(R8), R8
+ LEAL 4(R12), R12
+
+matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm:
+ CMPL R8, $0x01
+ JE matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm
+ JB match_nolit_end_encodeSnappyBetterBlockAsm
+ MOVW (R9)(R12*1), R11
+ CMPW (R10)(R12*1), R11
+ JNE matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm
+ LEAL 2(R12), R12
+ SUBL $0x02, R8
+ JZ match_nolit_end_encodeSnappyBetterBlockAsm
+
+matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm:
+ MOVB (R9)(R12*1), R11
+ CMPB (R10)(R12*1), R11
+ JNE match_nolit_end_encodeSnappyBetterBlockAsm
+ LEAL 1(R12), R12
+
+match_nolit_end_encodeSnappyBetterBlockAsm:
+ MOVL DX, R8
+ SUBL SI, R8
+
+ // Check if repeat
+ CMPL R12, $0x01
+ JA match_length_ok_encodeSnappyBetterBlockAsm
+ CMPL R8, $0x0000ffff
+ JBE match_length_ok_encodeSnappyBetterBlockAsm
+ MOVL 20(SP), DX
+ INCL DX
+ JMP search_loop_encodeSnappyBetterBlockAsm
+
+match_length_ok_encodeSnappyBetterBlockAsm:
+ MOVL R8, 16(SP)
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_encodeSnappyBetterBlockAsm
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_encodeSnappyBetterBlockAsm
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_encodeSnappyBetterBlockAsm
+ CMPL SI, $0x00010000
+ JB three_bytes_match_emit_encodeSnappyBetterBlockAsm
+ CMPL SI, $0x01000000
+ JB four_bytes_match_emit_encodeSnappyBetterBlockAsm
+ MOVB $0xfc, (CX)
+ MOVL SI, 1(CX)
+ ADDQ $0x05, CX
+ JMP memmove_long_match_emit_encodeSnappyBetterBlockAsm
+
+four_bytes_match_emit_encodeSnappyBetterBlockAsm:
+ MOVL SI, R11
+ SHRL $0x10, R11
+ MOVB $0xf8, (CX)
+ MOVW SI, 1(CX)
+ MOVB R11, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_match_emit_encodeSnappyBetterBlockAsm
+
+three_bytes_match_emit_encodeSnappyBetterBlockAsm:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeSnappyBetterBlockAsm
+
+two_bytes_match_emit_encodeSnappyBetterBlockAsm:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_encodeSnappyBetterBlockAsm
+ JMP memmove_long_match_emit_encodeSnappyBetterBlockAsm
+
+one_byte_match_emit_encodeSnappyBetterBlockAsm:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeSnappyBetterBlockAsm:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm_memmove_move_8:
+ MOVQ (R10), R11
+ MOVQ R11, (CX)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_encodeSnappyBetterBlockAsm
+
+memmove_long_match_emit_encodeSnappyBetterBlockAsm:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsmlarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsmlarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsmlarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsmlarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsmlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_encodeSnappyBetterBlockAsm:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL R8, $0x00010000
+ JB two_byte_offset_match_nolit_encodeSnappyBetterBlockAsm
+
+four_bytes_loop_back_match_nolit_encodeSnappyBetterBlockAsm:
+ CMPL R12, $0x40
+ JBE four_bytes_remain_match_nolit_encodeSnappyBetterBlockAsm
+ MOVB $0xff, (CX)
+ MOVL R8, 1(CX)
+ LEAL -64(R12), R12
+ ADDQ $0x05, CX
+ CMPL R12, $0x04
+ JB four_bytes_remain_match_nolit_encodeSnappyBetterBlockAsm
+ JMP four_bytes_loop_back_match_nolit_encodeSnappyBetterBlockAsm
+
+four_bytes_remain_match_nolit_encodeSnappyBetterBlockAsm:
+ TESTL R12, R12
+ JZ match_nolit_emitcopy_end_encodeSnappyBetterBlockAsm
+ XORL SI, SI
+ LEAL -1(SI)(R12*4), R12
+ MOVB R12, (CX)
+ MOVL R8, 1(CX)
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_encodeSnappyBetterBlockAsm
+
+two_byte_offset_match_nolit_encodeSnappyBetterBlockAsm:
+ CMPL R12, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeSnappyBetterBlockAsm
+ MOVB $0xee, (CX)
+ MOVW R8, 1(CX)
+ LEAL -60(R12), R12
+ ADDQ $0x03, CX
+ JMP two_byte_offset_match_nolit_encodeSnappyBetterBlockAsm
+
+two_byte_offset_short_match_nolit_encodeSnappyBetterBlockAsm:
+ MOVL R12, SI
+ SHLL $0x02, SI
+ CMPL R12, $0x0c
+ JAE emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm
+ CMPL R8, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm
+ LEAL -15(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeSnappyBetterBlockAsm
+
+emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm:
+ LEAL -2(SI), SI
+ MOVB SI, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeSnappyBetterBlockAsm:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeSnappyBetterBlockAsm
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeSnappyBetterBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeSnappyBetterBlockAsm:
+ MOVQ $0x00cf1bbcdcbfa563, SI
+ MOVQ $0x9e3779b1, R8
+ LEAQ 1(DI), DI
+ LEAQ -2(DX), R9
+ MOVQ (BX)(DI*1), R10
+ MOVQ 1(BX)(DI*1), R11
+ MOVQ (BX)(R9*1), R12
+ MOVQ 1(BX)(R9*1), R13
+ SHLQ $0x08, R10
+ IMULQ SI, R10
+ SHRQ $0x2f, R10
+ SHLQ $0x20, R11
+ IMULQ R8, R11
+ SHRQ $0x32, R11
+ SHLQ $0x08, R12
+ IMULQ SI, R12
+ SHRQ $0x2f, R12
+ SHLQ $0x20, R13
+ IMULQ R8, R13
+ SHRQ $0x32, R13
+ LEAQ 1(DI), R8
+ LEAQ 1(R9), R14
+ MOVL DI, (AX)(R10*4)
+ MOVL R9, (AX)(R12*4)
+ MOVL R8, 524288(AX)(R11*4)
+ MOVL R14, 524288(AX)(R13*4)
+ LEAQ 1(R9)(DI*1), R8
+ SHRQ $0x01, R8
+ ADDQ $0x01, DI
+ SUBQ $0x01, R9
+
+index_loop_encodeSnappyBetterBlockAsm:
+ CMPQ R8, R9
+ JAE search_loop_encodeSnappyBetterBlockAsm
+ MOVQ (BX)(DI*1), R10
+ MOVQ (BX)(R8*1), R11
+ SHLQ $0x08, R10
+ IMULQ SI, R10
+ SHRQ $0x2f, R10
+ SHLQ $0x08, R11
+ IMULQ SI, R11
+ SHRQ $0x2f, R11
+ MOVL DI, (AX)(R10*4)
+ MOVL R8, (AX)(R11*4)
+ ADDQ $0x02, DI
+ ADDQ $0x02, R8
+ JMP index_loop_encodeSnappyBetterBlockAsm
+
+emit_remainder_encodeSnappyBetterBlockAsm:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 5(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeSnappyBetterBlockAsm
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeSnappyBetterBlockAsm:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeSnappyBetterBlockAsm
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeSnappyBetterBlockAsm
+ CMPL DX, $0x00010000
+ JB three_bytes_emit_remainder_encodeSnappyBetterBlockAsm
+ CMPL DX, $0x01000000
+ JB four_bytes_emit_remainder_encodeSnappyBetterBlockAsm
+ MOVB $0xfc, (CX)
+ MOVL DX, 1(CX)
+ ADDQ $0x05, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBetterBlockAsm
+
+four_bytes_emit_remainder_encodeSnappyBetterBlockAsm:
+ MOVL DX, BX
+ SHRL $0x10, BX
+ MOVB $0xf8, (CX)
+ MOVW DX, 1(CX)
+ MOVB BL, 3(CX)
+ ADDQ $0x04, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBetterBlockAsm
+
+three_bytes_emit_remainder_encodeSnappyBetterBlockAsm:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBetterBlockAsm
+
+two_bytes_emit_remainder_encodeSnappyBetterBlockAsm:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeSnappyBetterBlockAsm
+ JMP memmove_long_emit_remainder_encodeSnappyBetterBlockAsm
+
+one_byte_emit_remainder_encodeSnappyBetterBlockAsm:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeSnappyBetterBlockAsm:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm
+
+memmove_long_emit_remainder_encodeSnappyBetterBlockAsm:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsmlarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsmlarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsmlarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsmlarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsmlarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeSnappyBetterBlockAsm64K(dst []byte, src []byte, tmp *[294912]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeSnappyBetterBlockAsm64K(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000900, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeSnappyBetterBlockAsm64K:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeSnappyBetterBlockAsm64K
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL $0x00000000, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeSnappyBetterBlockAsm64K:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x07, SI
+ LEAL 1(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeSnappyBetterBlockAsm64K
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x00cf1bbcdcbfa563, R9
+ MOVQ $0x9e3779b1, SI
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHLQ $0x08, R10
+ IMULQ R9, R10
+ SHRQ $0x30, R10
+ SHLQ $0x20, R11
+ IMULQ SI, R11
+ SHRQ $0x33, R11
+ MOVL (AX)(R10*4), SI
+ MOVL 262144(AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ MOVL DX, 262144(AX)(R11*4)
+ MOVQ (BX)(SI*1), R10
+ MOVQ (BX)(R8*1), R11
+ CMPQ R10, DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm64K
+ CMPQ R11, DI
+ JNE no_short_found_encodeSnappyBetterBlockAsm64K
+ MOVL R8, SI
+ JMP candidate_match_encodeSnappyBetterBlockAsm64K
+
+no_short_found_encodeSnappyBetterBlockAsm64K:
+ CMPL R10, DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm64K
+ CMPL R11, DI
+ JEQ candidateS_match_encodeSnappyBetterBlockAsm64K
+ MOVL 20(SP), DX
+ JMP search_loop_encodeSnappyBetterBlockAsm64K
+
+candidateS_match_encodeSnappyBetterBlockAsm64K:
+ SHRQ $0x08, DI
+ MOVQ DI, R10
+ SHLQ $0x08, R10
+ IMULQ R9, R10
+ SHRQ $0x30, R10
+ MOVL (AX)(R10*4), SI
+ INCL DX
+ MOVL DX, (AX)(R10*4)
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm64K
+ DECL DX
+ MOVL R8, SI
+
+candidate_match_encodeSnappyBetterBlockAsm64K:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeSnappyBetterBlockAsm64K
+
+match_extend_back_loop_encodeSnappyBetterBlockAsm64K:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeSnappyBetterBlockAsm64K
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeSnappyBetterBlockAsm64K
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeSnappyBetterBlockAsm64K
+ JMP match_extend_back_loop_encodeSnappyBetterBlockAsm64K
+
+match_extend_back_end_encodeSnappyBetterBlockAsm64K:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeSnappyBetterBlockAsm64K
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeSnappyBetterBlockAsm64K:
+ MOVL DX, DI
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), R10
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_match_nolit_encodeSnappyBetterBlockAsm64K:
+ CMPL R8, $0x10
+ JB matchlen_match8_match_nolit_encodeSnappyBetterBlockAsm64K
+ MOVQ (R9)(R12*1), R11
+ MOVQ 8(R9)(R12*1), R13
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm64K
+ XORQ 8(R10)(R12*1), R13
+ JNZ matchlen_bsf_16match_nolit_encodeSnappyBetterBlockAsm64K
+ LEAL -16(R8), R8
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_match_nolit_encodeSnappyBetterBlockAsm64K
+
+matchlen_bsf_16match_nolit_encodeSnappyBetterBlockAsm64K:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP match_nolit_end_encodeSnappyBetterBlockAsm64K
+
+matchlen_match8_match_nolit_encodeSnappyBetterBlockAsm64K:
+ CMPL R8, $0x08
+ JB matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm64K
+ MOVQ (R9)(R12*1), R11
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm64K
+ LEAL -8(R8), R8
+ LEAL 8(R12), R12
+ JMP matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm64K
+
+matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm64K:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP match_nolit_end_encodeSnappyBetterBlockAsm64K
+
+matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm64K:
+ CMPL R8, $0x04
+ JB matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm64K
+ MOVL (R9)(R12*1), R11
+ CMPL (R10)(R12*1), R11
+ JNE matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm64K
+ LEAL -4(R8), R8
+ LEAL 4(R12), R12
+
+matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm64K:
+ CMPL R8, $0x01
+ JE matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm64K
+ JB match_nolit_end_encodeSnappyBetterBlockAsm64K
+ MOVW (R9)(R12*1), R11
+ CMPW (R10)(R12*1), R11
+ JNE matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm64K
+ LEAL 2(R12), R12
+ SUBL $0x02, R8
+ JZ match_nolit_end_encodeSnappyBetterBlockAsm64K
+
+matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm64K:
+ MOVB (R9)(R12*1), R11
+ CMPB (R10)(R12*1), R11
+ JNE match_nolit_end_encodeSnappyBetterBlockAsm64K
+ LEAL 1(R12), R12
+
+match_nolit_end_encodeSnappyBetterBlockAsm64K:
+ MOVL DX, R8
+ SUBL SI, R8
+
+ // Check if repeat
+ MOVL R8, 16(SP)
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_encodeSnappyBetterBlockAsm64K
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_encodeSnappyBetterBlockAsm64K
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_encodeSnappyBetterBlockAsm64K
+ JB three_bytes_match_emit_encodeSnappyBetterBlockAsm64K
+
+three_bytes_match_emit_encodeSnappyBetterBlockAsm64K:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeSnappyBetterBlockAsm64K
+
+two_bytes_match_emit_encodeSnappyBetterBlockAsm64K:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_encodeSnappyBetterBlockAsm64K
+ JMP memmove_long_match_emit_encodeSnappyBetterBlockAsm64K
+
+one_byte_match_emit_encodeSnappyBetterBlockAsm64K:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeSnappyBetterBlockAsm64K:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm64K_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm64K_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm64K_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm64K_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm64K_memmove_move_8:
+ MOVQ (R10), R11
+ MOVQ R11, (CX)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm64K
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm64K_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm64K
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm64K_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm64K
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm64K_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm64K:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_encodeSnappyBetterBlockAsm64K
+
+memmove_long_match_emit_encodeSnappyBetterBlockAsm64K:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm64Klarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm64Klarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm64Klarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm64Klarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm64Klarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_encodeSnappyBetterBlockAsm64K:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitCopy
+two_byte_offset_match_nolit_encodeSnappyBetterBlockAsm64K:
+ CMPL R12, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeSnappyBetterBlockAsm64K
+ MOVB $0xee, (CX)
+ MOVW R8, 1(CX)
+ LEAL -60(R12), R12
+ ADDQ $0x03, CX
+ JMP two_byte_offset_match_nolit_encodeSnappyBetterBlockAsm64K
+
+two_byte_offset_short_match_nolit_encodeSnappyBetterBlockAsm64K:
+ MOVL R12, SI
+ SHLL $0x02, SI
+ CMPL R12, $0x0c
+ JAE emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm64K
+ CMPL R8, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm64K
+ LEAL -15(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeSnappyBetterBlockAsm64K
+
+emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm64K:
+ LEAL -2(SI), SI
+ MOVB SI, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeSnappyBetterBlockAsm64K:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeSnappyBetterBlockAsm64K
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeSnappyBetterBlockAsm64K
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeSnappyBetterBlockAsm64K:
+ MOVQ $0x00cf1bbcdcbfa563, SI
+ MOVQ $0x9e3779b1, R8
+ LEAQ 1(DI), DI
+ LEAQ -2(DX), R9
+ MOVQ (BX)(DI*1), R10
+ MOVQ 1(BX)(DI*1), R11
+ MOVQ (BX)(R9*1), R12
+ MOVQ 1(BX)(R9*1), R13
+ SHLQ $0x08, R10
+ IMULQ SI, R10
+ SHRQ $0x30, R10
+ SHLQ $0x20, R11
+ IMULQ R8, R11
+ SHRQ $0x33, R11
+ SHLQ $0x08, R12
+ IMULQ SI, R12
+ SHRQ $0x30, R12
+ SHLQ $0x20, R13
+ IMULQ R8, R13
+ SHRQ $0x33, R13
+ LEAQ 1(DI), R8
+ LEAQ 1(R9), R14
+ MOVL DI, (AX)(R10*4)
+ MOVL R9, (AX)(R12*4)
+ MOVL R8, 262144(AX)(R11*4)
+ MOVL R14, 262144(AX)(R13*4)
+ LEAQ 1(R9)(DI*1), R8
+ SHRQ $0x01, R8
+ ADDQ $0x01, DI
+ SUBQ $0x01, R9
+
+index_loop_encodeSnappyBetterBlockAsm64K:
+ CMPQ R8, R9
+ JAE search_loop_encodeSnappyBetterBlockAsm64K
+ MOVQ (BX)(DI*1), R10
+ MOVQ (BX)(R8*1), R11
+ SHLQ $0x08, R10
+ IMULQ SI, R10
+ SHRQ $0x30, R10
+ SHLQ $0x08, R11
+ IMULQ SI, R11
+ SHRQ $0x30, R11
+ MOVL DI, (AX)(R10*4)
+ MOVL R8, (AX)(R11*4)
+ ADDQ $0x02, DI
+ ADDQ $0x02, R8
+ JMP index_loop_encodeSnappyBetterBlockAsm64K
+
+emit_remainder_encodeSnappyBetterBlockAsm64K:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeSnappyBetterBlockAsm64K
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeSnappyBetterBlockAsm64K:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm64K
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeSnappyBetterBlockAsm64K
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeSnappyBetterBlockAsm64K
+ JB three_bytes_emit_remainder_encodeSnappyBetterBlockAsm64K
+
+three_bytes_emit_remainder_encodeSnappyBetterBlockAsm64K:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBetterBlockAsm64K
+
+two_bytes_emit_remainder_encodeSnappyBetterBlockAsm64K:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeSnappyBetterBlockAsm64K
+ JMP memmove_long_emit_remainder_encodeSnappyBetterBlockAsm64K
+
+one_byte_emit_remainder_encodeSnappyBetterBlockAsm64K:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeSnappyBetterBlockAsm64K:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm64K_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm64K_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm64K_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm64K_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm64K_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm64K_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm64K_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm64K
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm64K_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm64K
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm64K_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm64K
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm64K_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm64K
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm64K_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm64K
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm64K_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm64K:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm64K
+
+memmove_long_emit_remainder_encodeSnappyBetterBlockAsm64K:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm64Klarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm64Klarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm64Klarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm64Klarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm64Klarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm64K:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeSnappyBetterBlockAsm12B(dst []byte, src []byte, tmp *[81920]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeSnappyBetterBlockAsm12B(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000280, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeSnappyBetterBlockAsm12B:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeSnappyBetterBlockAsm12B
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL $0x00000000, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeSnappyBetterBlockAsm12B:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x06, SI
+ LEAL 1(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeSnappyBetterBlockAsm12B
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ $0x9e3779b1, SI
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x32, R10
+ SHLQ $0x20, R11
+ IMULQ SI, R11
+ SHRQ $0x34, R11
+ MOVL (AX)(R10*4), SI
+ MOVL 65536(AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ MOVL DX, 65536(AX)(R11*4)
+ MOVQ (BX)(SI*1), R10
+ MOVQ (BX)(R8*1), R11
+ CMPQ R10, DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm12B
+ CMPQ R11, DI
+ JNE no_short_found_encodeSnappyBetterBlockAsm12B
+ MOVL R8, SI
+ JMP candidate_match_encodeSnappyBetterBlockAsm12B
+
+no_short_found_encodeSnappyBetterBlockAsm12B:
+ CMPL R10, DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm12B
+ CMPL R11, DI
+ JEQ candidateS_match_encodeSnappyBetterBlockAsm12B
+ MOVL 20(SP), DX
+ JMP search_loop_encodeSnappyBetterBlockAsm12B
+
+candidateS_match_encodeSnappyBetterBlockAsm12B:
+ SHRQ $0x08, DI
+ MOVQ DI, R10
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x32, R10
+ MOVL (AX)(R10*4), SI
+ INCL DX
+ MOVL DX, (AX)(R10*4)
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm12B
+ DECL DX
+ MOVL R8, SI
+
+candidate_match_encodeSnappyBetterBlockAsm12B:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeSnappyBetterBlockAsm12B
+
+match_extend_back_loop_encodeSnappyBetterBlockAsm12B:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeSnappyBetterBlockAsm12B
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeSnappyBetterBlockAsm12B
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeSnappyBetterBlockAsm12B
+ JMP match_extend_back_loop_encodeSnappyBetterBlockAsm12B
+
+match_extend_back_end_encodeSnappyBetterBlockAsm12B:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeSnappyBetterBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeSnappyBetterBlockAsm12B:
+ MOVL DX, DI
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), R10
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_match_nolit_encodeSnappyBetterBlockAsm12B:
+ CMPL R8, $0x10
+ JB matchlen_match8_match_nolit_encodeSnappyBetterBlockAsm12B
+ MOVQ (R9)(R12*1), R11
+ MOVQ 8(R9)(R12*1), R13
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm12B
+ XORQ 8(R10)(R12*1), R13
+ JNZ matchlen_bsf_16match_nolit_encodeSnappyBetterBlockAsm12B
+ LEAL -16(R8), R8
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_match_nolit_encodeSnappyBetterBlockAsm12B
+
+matchlen_bsf_16match_nolit_encodeSnappyBetterBlockAsm12B:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP match_nolit_end_encodeSnappyBetterBlockAsm12B
+
+matchlen_match8_match_nolit_encodeSnappyBetterBlockAsm12B:
+ CMPL R8, $0x08
+ JB matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm12B
+ MOVQ (R9)(R12*1), R11
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm12B
+ LEAL -8(R8), R8
+ LEAL 8(R12), R12
+ JMP matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm12B
+
+matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm12B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP match_nolit_end_encodeSnappyBetterBlockAsm12B
+
+matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm12B:
+ CMPL R8, $0x04
+ JB matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm12B
+ MOVL (R9)(R12*1), R11
+ CMPL (R10)(R12*1), R11
+ JNE matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm12B
+ LEAL -4(R8), R8
+ LEAL 4(R12), R12
+
+matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm12B:
+ CMPL R8, $0x01
+ JE matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm12B
+ JB match_nolit_end_encodeSnappyBetterBlockAsm12B
+ MOVW (R9)(R12*1), R11
+ CMPW (R10)(R12*1), R11
+ JNE matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm12B
+ LEAL 2(R12), R12
+ SUBL $0x02, R8
+ JZ match_nolit_end_encodeSnappyBetterBlockAsm12B
+
+matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm12B:
+ MOVB (R9)(R12*1), R11
+ CMPB (R10)(R12*1), R11
+ JNE match_nolit_end_encodeSnappyBetterBlockAsm12B
+ LEAL 1(R12), R12
+
+match_nolit_end_encodeSnappyBetterBlockAsm12B:
+ MOVL DX, R8
+ SUBL SI, R8
+
+ // Check if repeat
+ MOVL R8, 16(SP)
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_encodeSnappyBetterBlockAsm12B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_encodeSnappyBetterBlockAsm12B
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_encodeSnappyBetterBlockAsm12B
+ JB three_bytes_match_emit_encodeSnappyBetterBlockAsm12B
+
+three_bytes_match_emit_encodeSnappyBetterBlockAsm12B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeSnappyBetterBlockAsm12B
+
+two_bytes_match_emit_encodeSnappyBetterBlockAsm12B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_encodeSnappyBetterBlockAsm12B
+ JMP memmove_long_match_emit_encodeSnappyBetterBlockAsm12B
+
+one_byte_match_emit_encodeSnappyBetterBlockAsm12B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeSnappyBetterBlockAsm12B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm12B_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm12B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm12B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm12B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm12B_memmove_move_8:
+ MOVQ (R10), R11
+ MOVQ R11, (CX)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm12B_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm12B_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm12B
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm12B_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm12B:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_encodeSnappyBetterBlockAsm12B
+
+memmove_long_match_emit_encodeSnappyBetterBlockAsm12B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm12Blarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm12Blarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm12Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm12Blarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm12Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_encodeSnappyBetterBlockAsm12B:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitCopy
+two_byte_offset_match_nolit_encodeSnappyBetterBlockAsm12B:
+ CMPL R12, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeSnappyBetterBlockAsm12B
+ MOVB $0xee, (CX)
+ MOVW R8, 1(CX)
+ LEAL -60(R12), R12
+ ADDQ $0x03, CX
+ JMP two_byte_offset_match_nolit_encodeSnappyBetterBlockAsm12B
+
+two_byte_offset_short_match_nolit_encodeSnappyBetterBlockAsm12B:
+ MOVL R12, SI
+ SHLL $0x02, SI
+ CMPL R12, $0x0c
+ JAE emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm12B
+ CMPL R8, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm12B
+ LEAL -15(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeSnappyBetterBlockAsm12B
+
+emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm12B:
+ LEAL -2(SI), SI
+ MOVB SI, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeSnappyBetterBlockAsm12B:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeSnappyBetterBlockAsm12B
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeSnappyBetterBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeSnappyBetterBlockAsm12B:
+ MOVQ $0x0000cf1bbcdcbf9b, SI
+ MOVQ $0x9e3779b1, R8
+ LEAQ 1(DI), DI
+ LEAQ -2(DX), R9
+ MOVQ (BX)(DI*1), R10
+ MOVQ 1(BX)(DI*1), R11
+ MOVQ (BX)(R9*1), R12
+ MOVQ 1(BX)(R9*1), R13
+ SHLQ $0x10, R10
+ IMULQ SI, R10
+ SHRQ $0x32, R10
+ SHLQ $0x20, R11
+ IMULQ R8, R11
+ SHRQ $0x34, R11
+ SHLQ $0x10, R12
+ IMULQ SI, R12
+ SHRQ $0x32, R12
+ SHLQ $0x20, R13
+ IMULQ R8, R13
+ SHRQ $0x34, R13
+ LEAQ 1(DI), R8
+ LEAQ 1(R9), R14
+ MOVL DI, (AX)(R10*4)
+ MOVL R9, (AX)(R12*4)
+ MOVL R8, 65536(AX)(R11*4)
+ MOVL R14, 65536(AX)(R13*4)
+ LEAQ 1(R9)(DI*1), R8
+ SHRQ $0x01, R8
+ ADDQ $0x01, DI
+ SUBQ $0x01, R9
+
+index_loop_encodeSnappyBetterBlockAsm12B:
+ CMPQ R8, R9
+ JAE search_loop_encodeSnappyBetterBlockAsm12B
+ MOVQ (BX)(DI*1), R10
+ MOVQ (BX)(R8*1), R11
+ SHLQ $0x10, R10
+ IMULQ SI, R10
+ SHRQ $0x32, R10
+ SHLQ $0x10, R11
+ IMULQ SI, R11
+ SHRQ $0x32, R11
+ MOVL DI, (AX)(R10*4)
+ MOVL R8, (AX)(R11*4)
+ ADDQ $0x02, DI
+ ADDQ $0x02, R8
+ JMP index_loop_encodeSnappyBetterBlockAsm12B
+
+emit_remainder_encodeSnappyBetterBlockAsm12B:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeSnappyBetterBlockAsm12B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeSnappyBetterBlockAsm12B:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm12B
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeSnappyBetterBlockAsm12B
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeSnappyBetterBlockAsm12B
+ JB three_bytes_emit_remainder_encodeSnappyBetterBlockAsm12B
+
+three_bytes_emit_remainder_encodeSnappyBetterBlockAsm12B:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBetterBlockAsm12B
+
+two_bytes_emit_remainder_encodeSnappyBetterBlockAsm12B:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeSnappyBetterBlockAsm12B
+ JMP memmove_long_emit_remainder_encodeSnappyBetterBlockAsm12B
+
+one_byte_emit_remainder_encodeSnappyBetterBlockAsm12B:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeSnappyBetterBlockAsm12B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm12B_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm12B_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm12B_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm12B_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm12B_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm12B_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm12B_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm12B_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm12B_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm12B_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm12B_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm12B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm12B_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm12B:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm12B
+
+memmove_long_emit_remainder_encodeSnappyBetterBlockAsm12B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm12Blarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm12Blarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm12Blarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm12Blarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm12Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm12B:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeSnappyBetterBlockAsm10B(dst []byte, src []byte, tmp *[20480]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeSnappyBetterBlockAsm10B(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x000000a0, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeSnappyBetterBlockAsm10B:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeSnappyBetterBlockAsm10B
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL $0x00000000, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeSnappyBetterBlockAsm10B:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x05, SI
+ LEAL 1(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeSnappyBetterBlockAsm10B
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ $0x9e3779b1, SI
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x34, R10
+ SHLQ $0x20, R11
+ IMULQ SI, R11
+ SHRQ $0x36, R11
+ MOVL (AX)(R10*4), SI
+ MOVL 16384(AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ MOVL DX, 16384(AX)(R11*4)
+ MOVQ (BX)(SI*1), R10
+ MOVQ (BX)(R8*1), R11
+ CMPQ R10, DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm10B
+ CMPQ R11, DI
+ JNE no_short_found_encodeSnappyBetterBlockAsm10B
+ MOVL R8, SI
+ JMP candidate_match_encodeSnappyBetterBlockAsm10B
+
+no_short_found_encodeSnappyBetterBlockAsm10B:
+ CMPL R10, DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm10B
+ CMPL R11, DI
+ JEQ candidateS_match_encodeSnappyBetterBlockAsm10B
+ MOVL 20(SP), DX
+ JMP search_loop_encodeSnappyBetterBlockAsm10B
+
+candidateS_match_encodeSnappyBetterBlockAsm10B:
+ SHRQ $0x08, DI
+ MOVQ DI, R10
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x34, R10
+ MOVL (AX)(R10*4), SI
+ INCL DX
+ MOVL DX, (AX)(R10*4)
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm10B
+ DECL DX
+ MOVL R8, SI
+
+candidate_match_encodeSnappyBetterBlockAsm10B:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeSnappyBetterBlockAsm10B
+
+match_extend_back_loop_encodeSnappyBetterBlockAsm10B:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeSnappyBetterBlockAsm10B
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeSnappyBetterBlockAsm10B
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeSnappyBetterBlockAsm10B
+ JMP match_extend_back_loop_encodeSnappyBetterBlockAsm10B
+
+match_extend_back_end_encodeSnappyBetterBlockAsm10B:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeSnappyBetterBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeSnappyBetterBlockAsm10B:
+ MOVL DX, DI
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), R10
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_match_nolit_encodeSnappyBetterBlockAsm10B:
+ CMPL R8, $0x10
+ JB matchlen_match8_match_nolit_encodeSnappyBetterBlockAsm10B
+ MOVQ (R9)(R12*1), R11
+ MOVQ 8(R9)(R12*1), R13
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm10B
+ XORQ 8(R10)(R12*1), R13
+ JNZ matchlen_bsf_16match_nolit_encodeSnappyBetterBlockAsm10B
+ LEAL -16(R8), R8
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_match_nolit_encodeSnappyBetterBlockAsm10B
+
+matchlen_bsf_16match_nolit_encodeSnappyBetterBlockAsm10B:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP match_nolit_end_encodeSnappyBetterBlockAsm10B
+
+matchlen_match8_match_nolit_encodeSnappyBetterBlockAsm10B:
+ CMPL R8, $0x08
+ JB matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm10B
+ MOVQ (R9)(R12*1), R11
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm10B
+ LEAL -8(R8), R8
+ LEAL 8(R12), R12
+ JMP matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm10B
+
+matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm10B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP match_nolit_end_encodeSnappyBetterBlockAsm10B
+
+matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm10B:
+ CMPL R8, $0x04
+ JB matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm10B
+ MOVL (R9)(R12*1), R11
+ CMPL (R10)(R12*1), R11
+ JNE matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm10B
+ LEAL -4(R8), R8
+ LEAL 4(R12), R12
+
+matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm10B:
+ CMPL R8, $0x01
+ JE matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm10B
+ JB match_nolit_end_encodeSnappyBetterBlockAsm10B
+ MOVW (R9)(R12*1), R11
+ CMPW (R10)(R12*1), R11
+ JNE matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm10B
+ LEAL 2(R12), R12
+ SUBL $0x02, R8
+ JZ match_nolit_end_encodeSnappyBetterBlockAsm10B
+
+matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm10B:
+ MOVB (R9)(R12*1), R11
+ CMPB (R10)(R12*1), R11
+ JNE match_nolit_end_encodeSnappyBetterBlockAsm10B
+ LEAL 1(R12), R12
+
+match_nolit_end_encodeSnappyBetterBlockAsm10B:
+ MOVL DX, R8
+ SUBL SI, R8
+
+ // Check if repeat
+ MOVL R8, 16(SP)
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_encodeSnappyBetterBlockAsm10B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_encodeSnappyBetterBlockAsm10B
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_encodeSnappyBetterBlockAsm10B
+ JB three_bytes_match_emit_encodeSnappyBetterBlockAsm10B
+
+three_bytes_match_emit_encodeSnappyBetterBlockAsm10B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeSnappyBetterBlockAsm10B
+
+two_bytes_match_emit_encodeSnappyBetterBlockAsm10B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_encodeSnappyBetterBlockAsm10B
+ JMP memmove_long_match_emit_encodeSnappyBetterBlockAsm10B
+
+one_byte_match_emit_encodeSnappyBetterBlockAsm10B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeSnappyBetterBlockAsm10B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm10B_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm10B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm10B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm10B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm10B_memmove_move_8:
+ MOVQ (R10), R11
+ MOVQ R11, (CX)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm10B_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm10B_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm10B
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm10B_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm10B:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_encodeSnappyBetterBlockAsm10B
+
+memmove_long_match_emit_encodeSnappyBetterBlockAsm10B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm10Blarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm10Blarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm10Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm10Blarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm10Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_encodeSnappyBetterBlockAsm10B:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitCopy
+two_byte_offset_match_nolit_encodeSnappyBetterBlockAsm10B:
+ CMPL R12, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeSnappyBetterBlockAsm10B
+ MOVB $0xee, (CX)
+ MOVW R8, 1(CX)
+ LEAL -60(R12), R12
+ ADDQ $0x03, CX
+ JMP two_byte_offset_match_nolit_encodeSnappyBetterBlockAsm10B
+
+two_byte_offset_short_match_nolit_encodeSnappyBetterBlockAsm10B:
+ MOVL R12, SI
+ SHLL $0x02, SI
+ CMPL R12, $0x0c
+ JAE emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm10B
+ CMPL R8, $0x00000800
+ JAE emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm10B
+ LEAL -15(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeSnappyBetterBlockAsm10B
+
+emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm10B:
+ LEAL -2(SI), SI
+ MOVB SI, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeSnappyBetterBlockAsm10B:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeSnappyBetterBlockAsm10B
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeSnappyBetterBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeSnappyBetterBlockAsm10B:
+ MOVQ $0x0000cf1bbcdcbf9b, SI
+ MOVQ $0x9e3779b1, R8
+ LEAQ 1(DI), DI
+ LEAQ -2(DX), R9
+ MOVQ (BX)(DI*1), R10
+ MOVQ 1(BX)(DI*1), R11
+ MOVQ (BX)(R9*1), R12
+ MOVQ 1(BX)(R9*1), R13
+ SHLQ $0x10, R10
+ IMULQ SI, R10
+ SHRQ $0x34, R10
+ SHLQ $0x20, R11
+ IMULQ R8, R11
+ SHRQ $0x36, R11
+ SHLQ $0x10, R12
+ IMULQ SI, R12
+ SHRQ $0x34, R12
+ SHLQ $0x20, R13
+ IMULQ R8, R13
+ SHRQ $0x36, R13
+ LEAQ 1(DI), R8
+ LEAQ 1(R9), R14
+ MOVL DI, (AX)(R10*4)
+ MOVL R9, (AX)(R12*4)
+ MOVL R8, 16384(AX)(R11*4)
+ MOVL R14, 16384(AX)(R13*4)
+ LEAQ 1(R9)(DI*1), R8
+ SHRQ $0x01, R8
+ ADDQ $0x01, DI
+ SUBQ $0x01, R9
+
+index_loop_encodeSnappyBetterBlockAsm10B:
+ CMPQ R8, R9
+ JAE search_loop_encodeSnappyBetterBlockAsm10B
+ MOVQ (BX)(DI*1), R10
+ MOVQ (BX)(R8*1), R11
+ SHLQ $0x10, R10
+ IMULQ SI, R10
+ SHRQ $0x34, R10
+ SHLQ $0x10, R11
+ IMULQ SI, R11
+ SHRQ $0x34, R11
+ MOVL DI, (AX)(R10*4)
+ MOVL R8, (AX)(R11*4)
+ ADDQ $0x02, DI
+ ADDQ $0x02, R8
+ JMP index_loop_encodeSnappyBetterBlockAsm10B
+
+emit_remainder_encodeSnappyBetterBlockAsm10B:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeSnappyBetterBlockAsm10B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeSnappyBetterBlockAsm10B:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm10B
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeSnappyBetterBlockAsm10B
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeSnappyBetterBlockAsm10B
+ JB three_bytes_emit_remainder_encodeSnappyBetterBlockAsm10B
+
+three_bytes_emit_remainder_encodeSnappyBetterBlockAsm10B:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBetterBlockAsm10B
+
+two_bytes_emit_remainder_encodeSnappyBetterBlockAsm10B:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeSnappyBetterBlockAsm10B
+ JMP memmove_long_emit_remainder_encodeSnappyBetterBlockAsm10B
+
+one_byte_emit_remainder_encodeSnappyBetterBlockAsm10B:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeSnappyBetterBlockAsm10B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm10B_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm10B_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm10B_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm10B_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm10B_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm10B_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm10B_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm10B_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm10B_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm10B_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm10B_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm10B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm10B_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm10B:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm10B
+
+memmove_long_emit_remainder_encodeSnappyBetterBlockAsm10B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm10Blarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm10Blarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm10Blarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm10Blarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm10Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm10B:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func encodeSnappyBetterBlockAsm8B(dst []byte, src []byte, tmp *[5120]byte) int
+// Requires: BMI, SSE2
+TEXT ·encodeSnappyBetterBlockAsm8B(SB), $24-64
+ MOVQ tmp+48(FP), AX
+ MOVQ dst_base+0(FP), CX
+ MOVQ $0x00000028, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_encodeSnappyBetterBlockAsm8B:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_encodeSnappyBetterBlockAsm8B
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+32(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL $0x00000000, 16(SP)
+ MOVQ src_base+24(FP), BX
+
+search_loop_encodeSnappyBetterBlockAsm8B:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x04, SI
+ LEAL 1(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_encodeSnappyBetterBlockAsm8B
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ $0x9e3779b1, SI
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x36, R10
+ SHLQ $0x20, R11
+ IMULQ SI, R11
+ SHRQ $0x38, R11
+ MOVL (AX)(R10*4), SI
+ MOVL 4096(AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ MOVL DX, 4096(AX)(R11*4)
+ MOVQ (BX)(SI*1), R10
+ MOVQ (BX)(R8*1), R11
+ CMPQ R10, DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm8B
+ CMPQ R11, DI
+ JNE no_short_found_encodeSnappyBetterBlockAsm8B
+ MOVL R8, SI
+ JMP candidate_match_encodeSnappyBetterBlockAsm8B
+
+no_short_found_encodeSnappyBetterBlockAsm8B:
+ CMPL R10, DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm8B
+ CMPL R11, DI
+ JEQ candidateS_match_encodeSnappyBetterBlockAsm8B
+ MOVL 20(SP), DX
+ JMP search_loop_encodeSnappyBetterBlockAsm8B
+
+candidateS_match_encodeSnappyBetterBlockAsm8B:
+ SHRQ $0x08, DI
+ MOVQ DI, R10
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x36, R10
+ MOVL (AX)(R10*4), SI
+ INCL DX
+ MOVL DX, (AX)(R10*4)
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_encodeSnappyBetterBlockAsm8B
+ DECL DX
+ MOVL R8, SI
+
+candidate_match_encodeSnappyBetterBlockAsm8B:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_encodeSnappyBetterBlockAsm8B
+
+match_extend_back_loop_encodeSnappyBetterBlockAsm8B:
+ CMPL DX, DI
+ JBE match_extend_back_end_encodeSnappyBetterBlockAsm8B
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_encodeSnappyBetterBlockAsm8B
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_encodeSnappyBetterBlockAsm8B
+ JMP match_extend_back_loop_encodeSnappyBetterBlockAsm8B
+
+match_extend_back_end_encodeSnappyBetterBlockAsm8B:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_encodeSnappyBetterBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_dst_size_check_encodeSnappyBetterBlockAsm8B:
+ MOVL DX, DI
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+32(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), R10
+
+ // matchLen
+ XORL R12, R12
+
+matchlen_loopback_16_match_nolit_encodeSnappyBetterBlockAsm8B:
+ CMPL R8, $0x10
+ JB matchlen_match8_match_nolit_encodeSnappyBetterBlockAsm8B
+ MOVQ (R9)(R12*1), R11
+ MOVQ 8(R9)(R12*1), R13
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm8B
+ XORQ 8(R10)(R12*1), R13
+ JNZ matchlen_bsf_16match_nolit_encodeSnappyBetterBlockAsm8B
+ LEAL -16(R8), R8
+ LEAL 16(R12), R12
+ JMP matchlen_loopback_16_match_nolit_encodeSnappyBetterBlockAsm8B
+
+matchlen_bsf_16match_nolit_encodeSnappyBetterBlockAsm8B:
+#ifdef GOAMD64_v3
+ TZCNTQ R13, R13
+
+#else
+ BSFQ R13, R13
+
+#endif
+ SARQ $0x03, R13
+ LEAL 8(R12)(R13*1), R12
+ JMP match_nolit_end_encodeSnappyBetterBlockAsm8B
+
+matchlen_match8_match_nolit_encodeSnappyBetterBlockAsm8B:
+ CMPL R8, $0x08
+ JB matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm8B
+ MOVQ (R9)(R12*1), R11
+ XORQ (R10)(R12*1), R11
+ JNZ matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm8B
+ LEAL -8(R8), R8
+ LEAL 8(R12), R12
+ JMP matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm8B
+
+matchlen_bsf_8_match_nolit_encodeSnappyBetterBlockAsm8B:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL (R12)(R11*1), R12
+ JMP match_nolit_end_encodeSnappyBetterBlockAsm8B
+
+matchlen_match4_match_nolit_encodeSnappyBetterBlockAsm8B:
+ CMPL R8, $0x04
+ JB matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm8B
+ MOVL (R9)(R12*1), R11
+ CMPL (R10)(R12*1), R11
+ JNE matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm8B
+ LEAL -4(R8), R8
+ LEAL 4(R12), R12
+
+matchlen_match2_match_nolit_encodeSnappyBetterBlockAsm8B:
+ CMPL R8, $0x01
+ JE matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm8B
+ JB match_nolit_end_encodeSnappyBetterBlockAsm8B
+ MOVW (R9)(R12*1), R11
+ CMPW (R10)(R12*1), R11
+ JNE matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm8B
+ LEAL 2(R12), R12
+ SUBL $0x02, R8
+ JZ match_nolit_end_encodeSnappyBetterBlockAsm8B
+
+matchlen_match1_match_nolit_encodeSnappyBetterBlockAsm8B:
+ MOVB (R9)(R12*1), R11
+ CMPB (R10)(R12*1), R11
+ JNE match_nolit_end_encodeSnappyBetterBlockAsm8B
+ LEAL 1(R12), R12
+
+match_nolit_end_encodeSnappyBetterBlockAsm8B:
+ MOVL DX, R8
+ SUBL SI, R8
+
+ // Check if repeat
+ MOVL R8, 16(SP)
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_match_emit_encodeSnappyBetterBlockAsm8B
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R10
+ SUBL SI, R9
+ LEAL -1(R9), SI
+ CMPL SI, $0x3c
+ JB one_byte_match_emit_encodeSnappyBetterBlockAsm8B
+ CMPL SI, $0x00000100
+ JB two_bytes_match_emit_encodeSnappyBetterBlockAsm8B
+ JB three_bytes_match_emit_encodeSnappyBetterBlockAsm8B
+
+three_bytes_match_emit_encodeSnappyBetterBlockAsm8B:
+ MOVB $0xf4, (CX)
+ MOVW SI, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_encodeSnappyBetterBlockAsm8B
+
+two_bytes_match_emit_encodeSnappyBetterBlockAsm8B:
+ MOVB $0xf0, (CX)
+ MOVB SI, 1(CX)
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_match_emit_encodeSnappyBetterBlockAsm8B
+ JMP memmove_long_match_emit_encodeSnappyBetterBlockAsm8B
+
+one_byte_match_emit_encodeSnappyBetterBlockAsm8B:
+ SHLB $0x02, SI
+ MOVB SI, (CX)
+ ADDQ $0x01, CX
+
+memmove_match_emit_encodeSnappyBetterBlockAsm8B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm8B_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm8B_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm8B_memmove_move_17through32
+ JMP emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm8B_memmove_move_33through64
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm8B_memmove_move_8:
+ MOVQ (R10), R11
+ MOVQ R11, (CX)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm8B_memmove_move_8through16:
+ MOVQ (R10), R11
+ MOVQ -8(R10)(R9*1), R10
+ MOVQ R11, (CX)
+ MOVQ R10, -8(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm8B_memmove_move_17through32:
+ MOVOU (R10), X0
+ MOVOU -16(R10)(R9*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(R9*1)
+ JMP memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm8B
+
+emit_lit_memmove_match_emit_encodeSnappyBetterBlockAsm8B_memmove_move_33through64:
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+
+memmove_end_copy_match_emit_encodeSnappyBetterBlockAsm8B:
+ MOVQ SI, CX
+ JMP emit_literal_done_match_emit_encodeSnappyBetterBlockAsm8B
+
+memmove_long_match_emit_encodeSnappyBetterBlockAsm8B:
+ LEAQ (CX)(R9*1), SI
+
+ // genMemMoveLong
+ MOVOU (R10), X0
+ MOVOU 16(R10), X1
+ MOVOU -32(R10)(R9*1), X2
+ MOVOU -16(R10)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ CX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R14
+ SUBQ R11, R14
+ DECQ R13
+ JA emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm8Blarge_forward_sse_loop_32
+ LEAQ -32(R10)(R14*1), R11
+ LEAQ -32(CX)(R14*1), R15
+
+emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm8Blarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R11
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm8Blarge_big_loop_back
+
+emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm8Blarge_forward_sse_loop_32:
+ MOVOU -32(R10)(R14*1), X4
+ MOVOU -16(R10)(R14*1), X5
+ MOVOA X4, -32(CX)(R14*1)
+ MOVOA X5, -16(CX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_match_emit_encodeSnappyBetterBlockAsm8Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(R9*1)
+ MOVOU X3, -16(CX)(R9*1)
+ MOVQ SI, CX
+
+emit_literal_done_match_emit_encodeSnappyBetterBlockAsm8B:
+ ADDL R12, DX
+ ADDL $0x04, R12
+ MOVL DX, 12(SP)
+
+ // emitCopy
+two_byte_offset_match_nolit_encodeSnappyBetterBlockAsm8B:
+ CMPL R12, $0x40
+ JBE two_byte_offset_short_match_nolit_encodeSnappyBetterBlockAsm8B
+ MOVB $0xee, (CX)
+ MOVW R8, 1(CX)
+ LEAL -60(R12), R12
+ ADDQ $0x03, CX
+ JMP two_byte_offset_match_nolit_encodeSnappyBetterBlockAsm8B
+
+two_byte_offset_short_match_nolit_encodeSnappyBetterBlockAsm8B:
+ MOVL R12, SI
+ SHLL $0x02, SI
+ CMPL R12, $0x0c
+ JAE emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm8B
+ LEAL -15(SI), SI
+ MOVB R8, 1(CX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, SI
+ MOVB SI, (CX)
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_encodeSnappyBetterBlockAsm8B
+
+emit_copy_three_match_nolit_encodeSnappyBetterBlockAsm8B:
+ LEAL -2(SI), SI
+ MOVB SI, (CX)
+ MOVW R8, 1(CX)
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_encodeSnappyBetterBlockAsm8B:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_encodeSnappyBetterBlockAsm8B
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_encodeSnappyBetterBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+match_nolit_dst_ok_encodeSnappyBetterBlockAsm8B:
+ MOVQ $0x0000cf1bbcdcbf9b, SI
+ MOVQ $0x9e3779b1, R8
+ LEAQ 1(DI), DI
+ LEAQ -2(DX), R9
+ MOVQ (BX)(DI*1), R10
+ MOVQ 1(BX)(DI*1), R11
+ MOVQ (BX)(R9*1), R12
+ MOVQ 1(BX)(R9*1), R13
+ SHLQ $0x10, R10
+ IMULQ SI, R10
+ SHRQ $0x36, R10
+ SHLQ $0x20, R11
+ IMULQ R8, R11
+ SHRQ $0x38, R11
+ SHLQ $0x10, R12
+ IMULQ SI, R12
+ SHRQ $0x36, R12
+ SHLQ $0x20, R13
+ IMULQ R8, R13
+ SHRQ $0x38, R13
+ LEAQ 1(DI), R8
+ LEAQ 1(R9), R14
+ MOVL DI, (AX)(R10*4)
+ MOVL R9, (AX)(R12*4)
+ MOVL R8, 4096(AX)(R11*4)
+ MOVL R14, 4096(AX)(R13*4)
+ LEAQ 1(R9)(DI*1), R8
+ SHRQ $0x01, R8
+ ADDQ $0x01, DI
+ SUBQ $0x01, R9
+
+index_loop_encodeSnappyBetterBlockAsm8B:
+ CMPQ R8, R9
+ JAE search_loop_encodeSnappyBetterBlockAsm8B
+ MOVQ (BX)(DI*1), R10
+ MOVQ (BX)(R8*1), R11
+ SHLQ $0x10, R10
+ IMULQ SI, R10
+ SHRQ $0x36, R10
+ SHLQ $0x10, R11
+ IMULQ SI, R11
+ SHRQ $0x36, R11
+ MOVL DI, (AX)(R10*4)
+ MOVL R8, (AX)(R11*4)
+ ADDQ $0x02, DI
+ ADDQ $0x02, R8
+ JMP index_loop_encodeSnappyBetterBlockAsm8B
+
+emit_remainder_encodeSnappyBetterBlockAsm8B:
+ MOVQ src_len+32(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_encodeSnappyBetterBlockAsm8B
+ MOVQ $0x00000000, ret+56(FP)
+ RET
+
+emit_remainder_ok_encodeSnappyBetterBlockAsm8B:
+ MOVQ src_len+32(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm8B
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), DX
+ CMPL DX, $0x3c
+ JB one_byte_emit_remainder_encodeSnappyBetterBlockAsm8B
+ CMPL DX, $0x00000100
+ JB two_bytes_emit_remainder_encodeSnappyBetterBlockAsm8B
+ JB three_bytes_emit_remainder_encodeSnappyBetterBlockAsm8B
+
+three_bytes_emit_remainder_encodeSnappyBetterBlockAsm8B:
+ MOVB $0xf4, (CX)
+ MOVW DX, 1(CX)
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_encodeSnappyBetterBlockAsm8B
+
+two_bytes_emit_remainder_encodeSnappyBetterBlockAsm8B:
+ MOVB $0xf0, (CX)
+ MOVB DL, 1(CX)
+ ADDQ $0x02, CX
+ CMPL DX, $0x40
+ JB memmove_emit_remainder_encodeSnappyBetterBlockAsm8B
+ JMP memmove_long_emit_remainder_encodeSnappyBetterBlockAsm8B
+
+one_byte_emit_remainder_encodeSnappyBetterBlockAsm8B:
+ SHLB $0x02, DL
+ MOVB DL, (CX)
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_encodeSnappyBetterBlockAsm8B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveShort
+ CMPQ BX, $0x03
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm8B_memmove_move_1or2
+ JE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm8B_memmove_move_3
+ CMPQ BX, $0x08
+ JB emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm8B_memmove_move_4through7
+ CMPQ BX, $0x10
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm8B_memmove_move_8through16
+ CMPQ BX, $0x20
+ JBE emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm8B_memmove_move_17through32
+ JMP emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm8B_memmove_move_33through64
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm8B_memmove_move_1or2:
+ MOVB (AX), SI
+ MOVB -1(AX)(BX*1), AL
+ MOVB SI, (CX)
+ MOVB AL, -1(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm8B_memmove_move_3:
+ MOVW (AX), SI
+ MOVB 2(AX), AL
+ MOVW SI, (CX)
+ MOVB AL, 2(CX)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm8B_memmove_move_4through7:
+ MOVL (AX), SI
+ MOVL -4(AX)(BX*1), AX
+ MOVL SI, (CX)
+ MOVL AX, -4(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm8B_memmove_move_8through16:
+ MOVQ (AX), SI
+ MOVQ -8(AX)(BX*1), AX
+ MOVQ SI, (CX)
+ MOVQ AX, -8(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm8B_memmove_move_17through32:
+ MOVOU (AX), X0
+ MOVOU -16(AX)(BX*1), X1
+ MOVOU X0, (CX)
+ MOVOU X1, -16(CX)(BX*1)
+ JMP memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm8B
+
+emit_lit_memmove_emit_remainder_encodeSnappyBetterBlockAsm8B_memmove_move_33through64:
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+
+memmove_end_copy_emit_remainder_encodeSnappyBetterBlockAsm8B:
+ MOVQ DX, CX
+ JMP emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm8B
+
+memmove_long_emit_remainder_encodeSnappyBetterBlockAsm8B:
+ LEAQ (CX)(SI*1), DX
+ MOVL SI, BX
+
+ // genMemMoveLong
+ MOVOU (AX), X0
+ MOVOU 16(AX), X1
+ MOVOU -32(AX)(BX*1), X2
+ MOVOU -16(AX)(BX*1), X3
+ MOVQ BX, DI
+ SHRQ $0x05, DI
+ MOVQ CX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm8Blarge_forward_sse_loop_32
+ LEAQ -32(AX)(R8*1), SI
+ LEAQ -32(CX)(R8*1), R9
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm8Blarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm8Blarge_big_loop_back
+
+emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm8Blarge_forward_sse_loop_32:
+ MOVOU -32(AX)(R8*1), X4
+ MOVOU -16(AX)(R8*1), X5
+ MOVOA X4, -32(CX)(R8*1)
+ MOVOA X5, -16(CX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ BX, R8
+ JAE emit_lit_memmove_long_emit_remainder_encodeSnappyBetterBlockAsm8Blarge_forward_sse_loop_32
+ MOVOU X0, (CX)
+ MOVOU X1, 16(CX)
+ MOVOU X2, -32(CX)(BX*1)
+ MOVOU X3, -16(CX)(BX*1)
+ MOVQ DX, CX
+
+emit_literal_done_emit_remainder_encodeSnappyBetterBlockAsm8B:
+ MOVQ dst_base+0(FP), AX
+ SUBQ AX, CX
+ MOVQ CX, ret+56(FP)
+ RET
+
+// func calcBlockSize(src []byte, tmp *[32768]byte) int
+// Requires: BMI, SSE2
+TEXT ·calcBlockSize(SB), $24-40
+ MOVQ tmp+24(FP), AX
+ XORQ CX, CX
+ MOVQ $0x00000100, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_calcBlockSize:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_calcBlockSize
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+8(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL DX, 16(SP)
+ MOVQ src_base+0(FP), BX
+
+search_loop_calcBlockSize:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x05, SI
+ LEAL 4(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_calcBlockSize
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHRQ $0x08, R11
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x33, R10
+ SHLQ $0x10, R11
+ IMULQ R9, R11
+ SHRQ $0x33, R11
+ MOVL (AX)(R10*4), SI
+ MOVL (AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ LEAL 1(DX), R10
+ MOVL R10, (AX)(R11*4)
+ MOVQ DI, R10
+ SHRQ $0x10, R10
+ SHLQ $0x10, R10
+ IMULQ R9, R10
+ SHRQ $0x33, R10
+ MOVL DX, R9
+ SUBL 16(SP), R9
+ MOVL 1(BX)(R9*1), R11
+ MOVQ DI, R9
+ SHRQ $0x08, R9
+ CMPL R9, R11
+ JNE no_repeat_found_calcBlockSize
+ LEAL 1(DX), DI
+ MOVL 12(SP), SI
+ MOVL DI, R8
+ SUBL 16(SP), R8
+ JZ repeat_extend_back_end_calcBlockSize
+
+repeat_extend_back_loop_calcBlockSize:
+ CMPL DI, SI
+ JBE repeat_extend_back_end_calcBlockSize
+ MOVB -1(BX)(R8*1), R9
+ MOVB -1(BX)(DI*1), R10
+ CMPB R9, R10
+ JNE repeat_extend_back_end_calcBlockSize
+ LEAL -1(DI), DI
+ DECL R8
+ JNZ repeat_extend_back_loop_calcBlockSize
+
+repeat_extend_back_end_calcBlockSize:
+ MOVL DI, SI
+ SUBL 12(SP), SI
+ LEAQ 5(CX)(SI*1), SI
+ CMPQ SI, (SP)
+ JB repeat_dst_size_check_calcBlockSize
+ MOVQ $0x00000000, ret+32(FP)
+ RET
+
+repeat_dst_size_check_calcBlockSize:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_repeat_emit_calcBlockSize
+ MOVL DI, R8
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R9
+ SUBL SI, R8
+ LEAL -1(R8), SI
+ CMPL SI, $0x3c
+ JB one_byte_repeat_emit_calcBlockSize
+ CMPL SI, $0x00000100
+ JB two_bytes_repeat_emit_calcBlockSize
+ CMPL SI, $0x00010000
+ JB three_bytes_repeat_emit_calcBlockSize
+ CMPL SI, $0x01000000
+ JB four_bytes_repeat_emit_calcBlockSize
+ ADDQ $0x05, CX
+ JMP memmove_long_repeat_emit_calcBlockSize
+
+four_bytes_repeat_emit_calcBlockSize:
+ ADDQ $0x04, CX
+ JMP memmove_long_repeat_emit_calcBlockSize
+
+three_bytes_repeat_emit_calcBlockSize:
+ ADDQ $0x03, CX
+ JMP memmove_long_repeat_emit_calcBlockSize
+
+two_bytes_repeat_emit_calcBlockSize:
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_repeat_emit_calcBlockSize
+ JMP memmove_long_repeat_emit_calcBlockSize
+
+one_byte_repeat_emit_calcBlockSize:
+ ADDQ $0x01, CX
+
+memmove_repeat_emit_calcBlockSize:
+ LEAQ (CX)(R8*1), CX
+ JMP emit_literal_done_repeat_emit_calcBlockSize
+
+memmove_long_repeat_emit_calcBlockSize:
+ LEAQ (CX)(R8*1), CX
+
+emit_literal_done_repeat_emit_calcBlockSize:
+ ADDL $0x05, DX
+ MOVL DX, SI
+ SUBL 16(SP), SI
+ MOVQ src_len+8(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R11, R11
+
+matchlen_loopback_16_repeat_extend_calcBlockSize:
+ CMPL R8, $0x10
+ JB matchlen_match8_repeat_extend_calcBlockSize
+ MOVQ (R9)(R11*1), R10
+ MOVQ 8(R9)(R11*1), R12
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_calcBlockSize
+ XORQ 8(SI)(R11*1), R12
+ JNZ matchlen_bsf_16repeat_extend_calcBlockSize
+ LEAL -16(R8), R8
+ LEAL 16(R11), R11
+ JMP matchlen_loopback_16_repeat_extend_calcBlockSize
+
+matchlen_bsf_16repeat_extend_calcBlockSize:
+#ifdef GOAMD64_v3
+ TZCNTQ R12, R12
+
+#else
+ BSFQ R12, R12
+
+#endif
+ SARQ $0x03, R12
+ LEAL 8(R11)(R12*1), R11
+ JMP repeat_extend_forward_end_calcBlockSize
+
+matchlen_match8_repeat_extend_calcBlockSize:
+ CMPL R8, $0x08
+ JB matchlen_match4_repeat_extend_calcBlockSize
+ MOVQ (R9)(R11*1), R10
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_calcBlockSize
+ LEAL -8(R8), R8
+ LEAL 8(R11), R11
+ JMP matchlen_match4_repeat_extend_calcBlockSize
+
+matchlen_bsf_8_repeat_extend_calcBlockSize:
+#ifdef GOAMD64_v3
+ TZCNTQ R10, R10
+
+#else
+ BSFQ R10, R10
+
+#endif
+ SARQ $0x03, R10
+ LEAL (R11)(R10*1), R11
+ JMP repeat_extend_forward_end_calcBlockSize
+
+matchlen_match4_repeat_extend_calcBlockSize:
+ CMPL R8, $0x04
+ JB matchlen_match2_repeat_extend_calcBlockSize
+ MOVL (R9)(R11*1), R10
+ CMPL (SI)(R11*1), R10
+ JNE matchlen_match2_repeat_extend_calcBlockSize
+ LEAL -4(R8), R8
+ LEAL 4(R11), R11
+
+matchlen_match2_repeat_extend_calcBlockSize:
+ CMPL R8, $0x01
+ JE matchlen_match1_repeat_extend_calcBlockSize
+ JB repeat_extend_forward_end_calcBlockSize
+ MOVW (R9)(R11*1), R10
+ CMPW (SI)(R11*1), R10
+ JNE matchlen_match1_repeat_extend_calcBlockSize
+ LEAL 2(R11), R11
+ SUBL $0x02, R8
+ JZ repeat_extend_forward_end_calcBlockSize
+
+matchlen_match1_repeat_extend_calcBlockSize:
+ MOVB (R9)(R11*1), R10
+ CMPB (SI)(R11*1), R10
+ JNE repeat_extend_forward_end_calcBlockSize
+ LEAL 1(R11), R11
+
+repeat_extend_forward_end_calcBlockSize:
+ ADDL R11, DX
+ MOVL DX, SI
+ SUBL DI, SI
+ MOVL 16(SP), DI
+
+ // emitCopy
+ CMPL DI, $0x00010000
+ JB two_byte_offset_repeat_as_copy_calcBlockSize
+
+four_bytes_loop_back_repeat_as_copy_calcBlockSize:
+ CMPL SI, $0x40
+ JBE four_bytes_remain_repeat_as_copy_calcBlockSize
+ LEAL -64(SI), SI
+ ADDQ $0x05, CX
+ CMPL SI, $0x04
+ JB four_bytes_remain_repeat_as_copy_calcBlockSize
+ JMP four_bytes_loop_back_repeat_as_copy_calcBlockSize
+
+four_bytes_remain_repeat_as_copy_calcBlockSize:
+ TESTL SI, SI
+ JZ repeat_end_emit_calcBlockSize
+ XORL SI, SI
+ ADDQ $0x05, CX
+ JMP repeat_end_emit_calcBlockSize
+
+two_byte_offset_repeat_as_copy_calcBlockSize:
+ CMPL SI, $0x40
+ JBE two_byte_offset_short_repeat_as_copy_calcBlockSize
+ LEAL -60(SI), SI
+ ADDQ $0x03, CX
+ JMP two_byte_offset_repeat_as_copy_calcBlockSize
+
+two_byte_offset_short_repeat_as_copy_calcBlockSize:
+ MOVL SI, R8
+ SHLL $0x02, R8
+ CMPL SI, $0x0c
+ JAE emit_copy_three_repeat_as_copy_calcBlockSize
+ CMPL DI, $0x00000800
+ JAE emit_copy_three_repeat_as_copy_calcBlockSize
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_calcBlockSize
+
+emit_copy_three_repeat_as_copy_calcBlockSize:
+ ADDQ $0x03, CX
+
+repeat_end_emit_calcBlockSize:
+ MOVL DX, 12(SP)
+ JMP search_loop_calcBlockSize
+
+no_repeat_found_calcBlockSize:
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_calcBlockSize
+ SHRQ $0x08, DI
+ MOVL (AX)(R10*4), SI
+ LEAL 2(DX), R9
+ CMPL (BX)(R8*1), DI
+ JEQ candidate2_match_calcBlockSize
+ MOVL R9, (AX)(R10*4)
+ SHRQ $0x08, DI
+ CMPL (BX)(SI*1), DI
+ JEQ candidate3_match_calcBlockSize
+ MOVL 20(SP), DX
+ JMP search_loop_calcBlockSize
+
+candidate3_match_calcBlockSize:
+ ADDL $0x02, DX
+ JMP candidate_match_calcBlockSize
+
+candidate2_match_calcBlockSize:
+ MOVL R9, (AX)(R10*4)
+ INCL DX
+ MOVL R8, SI
+
+candidate_match_calcBlockSize:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_calcBlockSize
+
+match_extend_back_loop_calcBlockSize:
+ CMPL DX, DI
+ JBE match_extend_back_end_calcBlockSize
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_calcBlockSize
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_calcBlockSize
+ JMP match_extend_back_loop_calcBlockSize
+
+match_extend_back_end_calcBlockSize:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 5(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_calcBlockSize
+ MOVQ $0x00000000, ret+32(FP)
+ RET
+
+match_dst_size_check_calcBlockSize:
+ MOVL DX, DI
+ MOVL 12(SP), R8
+ CMPL R8, DI
+ JEQ emit_literal_done_match_emit_calcBlockSize
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(R8*1), DI
+ SUBL R8, R9
+ LEAL -1(R9), DI
+ CMPL DI, $0x3c
+ JB one_byte_match_emit_calcBlockSize
+ CMPL DI, $0x00000100
+ JB two_bytes_match_emit_calcBlockSize
+ CMPL DI, $0x00010000
+ JB three_bytes_match_emit_calcBlockSize
+ CMPL DI, $0x01000000
+ JB four_bytes_match_emit_calcBlockSize
+ ADDQ $0x05, CX
+ JMP memmove_long_match_emit_calcBlockSize
+
+four_bytes_match_emit_calcBlockSize:
+ ADDQ $0x04, CX
+ JMP memmove_long_match_emit_calcBlockSize
+
+three_bytes_match_emit_calcBlockSize:
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_calcBlockSize
+
+two_bytes_match_emit_calcBlockSize:
+ ADDQ $0x02, CX
+ CMPL DI, $0x40
+ JB memmove_match_emit_calcBlockSize
+ JMP memmove_long_match_emit_calcBlockSize
+
+one_byte_match_emit_calcBlockSize:
+ ADDQ $0x01, CX
+
+memmove_match_emit_calcBlockSize:
+ LEAQ (CX)(R9*1), CX
+ JMP emit_literal_done_match_emit_calcBlockSize
+
+memmove_long_match_emit_calcBlockSize:
+ LEAQ (CX)(R9*1), CX
+
+emit_literal_done_match_emit_calcBlockSize:
+match_nolit_loop_calcBlockSize:
+ MOVL DX, DI
+ SUBL SI, DI
+ MOVL DI, 16(SP)
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+8(FP), DI
+ SUBL DX, DI
+ LEAQ (BX)(DX*1), R8
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R10, R10
+
+matchlen_loopback_16_match_nolit_calcBlockSize:
+ CMPL DI, $0x10
+ JB matchlen_match8_match_nolit_calcBlockSize
+ MOVQ (R8)(R10*1), R9
+ MOVQ 8(R8)(R10*1), R11
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_calcBlockSize
+ XORQ 8(SI)(R10*1), R11
+ JNZ matchlen_bsf_16match_nolit_calcBlockSize
+ LEAL -16(DI), DI
+ LEAL 16(R10), R10
+ JMP matchlen_loopback_16_match_nolit_calcBlockSize
+
+matchlen_bsf_16match_nolit_calcBlockSize:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL 8(R10)(R11*1), R10
+ JMP match_nolit_end_calcBlockSize
+
+matchlen_match8_match_nolit_calcBlockSize:
+ CMPL DI, $0x08
+ JB matchlen_match4_match_nolit_calcBlockSize
+ MOVQ (R8)(R10*1), R9
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_calcBlockSize
+ LEAL -8(DI), DI
+ LEAL 8(R10), R10
+ JMP matchlen_match4_match_nolit_calcBlockSize
+
+matchlen_bsf_8_match_nolit_calcBlockSize:
+#ifdef GOAMD64_v3
+ TZCNTQ R9, R9
+
+#else
+ BSFQ R9, R9
+
+#endif
+ SARQ $0x03, R9
+ LEAL (R10)(R9*1), R10
+ JMP match_nolit_end_calcBlockSize
+
+matchlen_match4_match_nolit_calcBlockSize:
+ CMPL DI, $0x04
+ JB matchlen_match2_match_nolit_calcBlockSize
+ MOVL (R8)(R10*1), R9
+ CMPL (SI)(R10*1), R9
+ JNE matchlen_match2_match_nolit_calcBlockSize
+ LEAL -4(DI), DI
+ LEAL 4(R10), R10
+
+matchlen_match2_match_nolit_calcBlockSize:
+ CMPL DI, $0x01
+ JE matchlen_match1_match_nolit_calcBlockSize
+ JB match_nolit_end_calcBlockSize
+ MOVW (R8)(R10*1), R9
+ CMPW (SI)(R10*1), R9
+ JNE matchlen_match1_match_nolit_calcBlockSize
+ LEAL 2(R10), R10
+ SUBL $0x02, DI
+ JZ match_nolit_end_calcBlockSize
+
+matchlen_match1_match_nolit_calcBlockSize:
+ MOVB (R8)(R10*1), R9
+ CMPB (SI)(R10*1), R9
+ JNE match_nolit_end_calcBlockSize
+ LEAL 1(R10), R10
+
+match_nolit_end_calcBlockSize:
+ ADDL R10, DX
+ MOVL 16(SP), SI
+ ADDL $0x04, R10
+ MOVL DX, 12(SP)
+
+ // emitCopy
+ CMPL SI, $0x00010000
+ JB two_byte_offset_match_nolit_calcBlockSize
+
+four_bytes_loop_back_match_nolit_calcBlockSize:
+ CMPL R10, $0x40
+ JBE four_bytes_remain_match_nolit_calcBlockSize
+ LEAL -64(R10), R10
+ ADDQ $0x05, CX
+ CMPL R10, $0x04
+ JB four_bytes_remain_match_nolit_calcBlockSize
+ JMP four_bytes_loop_back_match_nolit_calcBlockSize
+
+four_bytes_remain_match_nolit_calcBlockSize:
+ TESTL R10, R10
+ JZ match_nolit_emitcopy_end_calcBlockSize
+ XORL SI, SI
+ ADDQ $0x05, CX
+ JMP match_nolit_emitcopy_end_calcBlockSize
+
+two_byte_offset_match_nolit_calcBlockSize:
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_match_nolit_calcBlockSize
+ LEAL -60(R10), R10
+ ADDQ $0x03, CX
+ JMP two_byte_offset_match_nolit_calcBlockSize
+
+two_byte_offset_short_match_nolit_calcBlockSize:
+ MOVL R10, DI
+ SHLL $0x02, DI
+ CMPL R10, $0x0c
+ JAE emit_copy_three_match_nolit_calcBlockSize
+ CMPL SI, $0x00000800
+ JAE emit_copy_three_match_nolit_calcBlockSize
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_calcBlockSize
+
+emit_copy_three_match_nolit_calcBlockSize:
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_calcBlockSize:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_calcBlockSize
+ MOVQ -2(BX)(DX*1), DI
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_calcBlockSize
+ MOVQ $0x00000000, ret+32(FP)
+ RET
+
+match_nolit_dst_ok_calcBlockSize:
+ MOVQ $0x0000cf1bbcdcbf9b, R9
+ MOVQ DI, R8
+ SHRQ $0x10, DI
+ MOVQ DI, SI
+ SHLQ $0x10, R8
+ IMULQ R9, R8
+ SHRQ $0x33, R8
+ SHLQ $0x10, SI
+ IMULQ R9, SI
+ SHRQ $0x33, SI
+ LEAL -2(DX), R9
+ LEAQ (AX)(SI*4), R10
+ MOVL (R10), SI
+ MOVL R9, (AX)(R8*4)
+ MOVL DX, (R10)
+ CMPL (BX)(SI*1), DI
+ JEQ match_nolit_loop_calcBlockSize
+ INCL DX
+ JMP search_loop_calcBlockSize
+
+emit_remainder_calcBlockSize:
+ MOVQ src_len+8(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 5(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_calcBlockSize
+ MOVQ $0x00000000, ret+32(FP)
+ RET
+
+emit_remainder_ok_calcBlockSize:
+ MOVQ src_len+8(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_calcBlockSize
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), AX
+ CMPL AX, $0x3c
+ JB one_byte_emit_remainder_calcBlockSize
+ CMPL AX, $0x00000100
+ JB two_bytes_emit_remainder_calcBlockSize
+ CMPL AX, $0x00010000
+ JB three_bytes_emit_remainder_calcBlockSize
+ CMPL AX, $0x01000000
+ JB four_bytes_emit_remainder_calcBlockSize
+ ADDQ $0x05, CX
+ JMP memmove_long_emit_remainder_calcBlockSize
+
+four_bytes_emit_remainder_calcBlockSize:
+ ADDQ $0x04, CX
+ JMP memmove_long_emit_remainder_calcBlockSize
+
+three_bytes_emit_remainder_calcBlockSize:
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_calcBlockSize
+
+two_bytes_emit_remainder_calcBlockSize:
+ ADDQ $0x02, CX
+ CMPL AX, $0x40
+ JB memmove_emit_remainder_calcBlockSize
+ JMP memmove_long_emit_remainder_calcBlockSize
+
+one_byte_emit_remainder_calcBlockSize:
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_calcBlockSize:
+ LEAQ (CX)(SI*1), AX
+ MOVQ AX, CX
+ JMP emit_literal_done_emit_remainder_calcBlockSize
+
+memmove_long_emit_remainder_calcBlockSize:
+ LEAQ (CX)(SI*1), AX
+ MOVQ AX, CX
+
+emit_literal_done_emit_remainder_calcBlockSize:
+ MOVQ CX, ret+32(FP)
+ RET
+
+// func calcBlockSizeSmall(src []byte, tmp *[2048]byte) int
+// Requires: BMI, SSE2
+TEXT ·calcBlockSizeSmall(SB), $24-40
+ MOVQ tmp+24(FP), AX
+ XORQ CX, CX
+ MOVQ $0x00000010, DX
+ MOVQ AX, BX
+ PXOR X0, X0
+
+zero_loop_calcBlockSizeSmall:
+ MOVOU X0, (BX)
+ MOVOU X0, 16(BX)
+ MOVOU X0, 32(BX)
+ MOVOU X0, 48(BX)
+ MOVOU X0, 64(BX)
+ MOVOU X0, 80(BX)
+ MOVOU X0, 96(BX)
+ MOVOU X0, 112(BX)
+ ADDQ $0x80, BX
+ DECQ DX
+ JNZ zero_loop_calcBlockSizeSmall
+ MOVL $0x00000000, 12(SP)
+ MOVQ src_len+8(FP), DX
+ LEAQ -9(DX), BX
+ LEAQ -8(DX), SI
+ MOVL SI, 8(SP)
+ SHRQ $0x05, DX
+ SUBL DX, BX
+ LEAQ (CX)(BX*1), BX
+ MOVQ BX, (SP)
+ MOVL $0x00000001, DX
+ MOVL DX, 16(SP)
+ MOVQ src_base+0(FP), BX
+
+search_loop_calcBlockSizeSmall:
+ MOVL DX, SI
+ SUBL 12(SP), SI
+ SHRL $0x04, SI
+ LEAL 4(DX)(SI*1), SI
+ CMPL SI, 8(SP)
+ JAE emit_remainder_calcBlockSizeSmall
+ MOVQ (BX)(DX*1), DI
+ MOVL SI, 20(SP)
+ MOVQ $0x9e3779b1, R9
+ MOVQ DI, R10
+ MOVQ DI, R11
+ SHRQ $0x08, R11
+ SHLQ $0x20, R10
+ IMULQ R9, R10
+ SHRQ $0x37, R10
+ SHLQ $0x20, R11
+ IMULQ R9, R11
+ SHRQ $0x37, R11
+ MOVL (AX)(R10*4), SI
+ MOVL (AX)(R11*4), R8
+ MOVL DX, (AX)(R10*4)
+ LEAL 1(DX), R10
+ MOVL R10, (AX)(R11*4)
+ MOVQ DI, R10
+ SHRQ $0x10, R10
+ SHLQ $0x20, R10
+ IMULQ R9, R10
+ SHRQ $0x37, R10
+ MOVL DX, R9
+ SUBL 16(SP), R9
+ MOVL 1(BX)(R9*1), R11
+ MOVQ DI, R9
+ SHRQ $0x08, R9
+ CMPL R9, R11
+ JNE no_repeat_found_calcBlockSizeSmall
+ LEAL 1(DX), DI
+ MOVL 12(SP), SI
+ MOVL DI, R8
+ SUBL 16(SP), R8
+ JZ repeat_extend_back_end_calcBlockSizeSmall
+
+repeat_extend_back_loop_calcBlockSizeSmall:
+ CMPL DI, SI
+ JBE repeat_extend_back_end_calcBlockSizeSmall
+ MOVB -1(BX)(R8*1), R9
+ MOVB -1(BX)(DI*1), R10
+ CMPB R9, R10
+ JNE repeat_extend_back_end_calcBlockSizeSmall
+ LEAL -1(DI), DI
+ DECL R8
+ JNZ repeat_extend_back_loop_calcBlockSizeSmall
+
+repeat_extend_back_end_calcBlockSizeSmall:
+ MOVL DI, SI
+ SUBL 12(SP), SI
+ LEAQ 3(CX)(SI*1), SI
+ CMPQ SI, (SP)
+ JB repeat_dst_size_check_calcBlockSizeSmall
+ MOVQ $0x00000000, ret+32(FP)
+ RET
+
+repeat_dst_size_check_calcBlockSizeSmall:
+ MOVL 12(SP), SI
+ CMPL SI, DI
+ JEQ emit_literal_done_repeat_emit_calcBlockSizeSmall
+ MOVL DI, R8
+ MOVL DI, 12(SP)
+ LEAQ (BX)(SI*1), R9
+ SUBL SI, R8
+ LEAL -1(R8), SI
+ CMPL SI, $0x3c
+ JB one_byte_repeat_emit_calcBlockSizeSmall
+ CMPL SI, $0x00000100
+ JB two_bytes_repeat_emit_calcBlockSizeSmall
+ JB three_bytes_repeat_emit_calcBlockSizeSmall
+
+three_bytes_repeat_emit_calcBlockSizeSmall:
+ ADDQ $0x03, CX
+ JMP memmove_long_repeat_emit_calcBlockSizeSmall
+
+two_bytes_repeat_emit_calcBlockSizeSmall:
+ ADDQ $0x02, CX
+ CMPL SI, $0x40
+ JB memmove_repeat_emit_calcBlockSizeSmall
+ JMP memmove_long_repeat_emit_calcBlockSizeSmall
+
+one_byte_repeat_emit_calcBlockSizeSmall:
+ ADDQ $0x01, CX
+
+memmove_repeat_emit_calcBlockSizeSmall:
+ LEAQ (CX)(R8*1), CX
+ JMP emit_literal_done_repeat_emit_calcBlockSizeSmall
+
+memmove_long_repeat_emit_calcBlockSizeSmall:
+ LEAQ (CX)(R8*1), CX
+
+emit_literal_done_repeat_emit_calcBlockSizeSmall:
+ ADDL $0x05, DX
+ MOVL DX, SI
+ SUBL 16(SP), SI
+ MOVQ src_len+8(FP), R8
+ SUBL DX, R8
+ LEAQ (BX)(DX*1), R9
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R11, R11
+
+matchlen_loopback_16_repeat_extend_calcBlockSizeSmall:
+ CMPL R8, $0x10
+ JB matchlen_match8_repeat_extend_calcBlockSizeSmall
+ MOVQ (R9)(R11*1), R10
+ MOVQ 8(R9)(R11*1), R12
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_calcBlockSizeSmall
+ XORQ 8(SI)(R11*1), R12
+ JNZ matchlen_bsf_16repeat_extend_calcBlockSizeSmall
+ LEAL -16(R8), R8
+ LEAL 16(R11), R11
+ JMP matchlen_loopback_16_repeat_extend_calcBlockSizeSmall
+
+matchlen_bsf_16repeat_extend_calcBlockSizeSmall:
+#ifdef GOAMD64_v3
+ TZCNTQ R12, R12
+
+#else
+ BSFQ R12, R12
+
+#endif
+ SARQ $0x03, R12
+ LEAL 8(R11)(R12*1), R11
+ JMP repeat_extend_forward_end_calcBlockSizeSmall
+
+matchlen_match8_repeat_extend_calcBlockSizeSmall:
+ CMPL R8, $0x08
+ JB matchlen_match4_repeat_extend_calcBlockSizeSmall
+ MOVQ (R9)(R11*1), R10
+ XORQ (SI)(R11*1), R10
+ JNZ matchlen_bsf_8_repeat_extend_calcBlockSizeSmall
+ LEAL -8(R8), R8
+ LEAL 8(R11), R11
+ JMP matchlen_match4_repeat_extend_calcBlockSizeSmall
+
+matchlen_bsf_8_repeat_extend_calcBlockSizeSmall:
+#ifdef GOAMD64_v3
+ TZCNTQ R10, R10
+
+#else
+ BSFQ R10, R10
+
+#endif
+ SARQ $0x03, R10
+ LEAL (R11)(R10*1), R11
+ JMP repeat_extend_forward_end_calcBlockSizeSmall
+
+matchlen_match4_repeat_extend_calcBlockSizeSmall:
+ CMPL R8, $0x04
+ JB matchlen_match2_repeat_extend_calcBlockSizeSmall
+ MOVL (R9)(R11*1), R10
+ CMPL (SI)(R11*1), R10
+ JNE matchlen_match2_repeat_extend_calcBlockSizeSmall
+ LEAL -4(R8), R8
+ LEAL 4(R11), R11
+
+matchlen_match2_repeat_extend_calcBlockSizeSmall:
+ CMPL R8, $0x01
+ JE matchlen_match1_repeat_extend_calcBlockSizeSmall
+ JB repeat_extend_forward_end_calcBlockSizeSmall
+ MOVW (R9)(R11*1), R10
+ CMPW (SI)(R11*1), R10
+ JNE matchlen_match1_repeat_extend_calcBlockSizeSmall
+ LEAL 2(R11), R11
+ SUBL $0x02, R8
+ JZ repeat_extend_forward_end_calcBlockSizeSmall
+
+matchlen_match1_repeat_extend_calcBlockSizeSmall:
+ MOVB (R9)(R11*1), R10
+ CMPB (SI)(R11*1), R10
+ JNE repeat_extend_forward_end_calcBlockSizeSmall
+ LEAL 1(R11), R11
+
+repeat_extend_forward_end_calcBlockSizeSmall:
+ ADDL R11, DX
+ MOVL DX, SI
+ SUBL DI, SI
+ MOVL 16(SP), DI
+
+ // emitCopy
+two_byte_offset_repeat_as_copy_calcBlockSizeSmall:
+ CMPL SI, $0x40
+ JBE two_byte_offset_short_repeat_as_copy_calcBlockSizeSmall
+ LEAL -60(SI), SI
+ ADDQ $0x03, CX
+ JMP two_byte_offset_repeat_as_copy_calcBlockSizeSmall
+
+two_byte_offset_short_repeat_as_copy_calcBlockSizeSmall:
+ MOVL SI, DI
+ SHLL $0x02, DI
+ CMPL SI, $0x0c
+ JAE emit_copy_three_repeat_as_copy_calcBlockSizeSmall
+ ADDQ $0x02, CX
+ JMP repeat_end_emit_calcBlockSizeSmall
+
+emit_copy_three_repeat_as_copy_calcBlockSizeSmall:
+ ADDQ $0x03, CX
+
+repeat_end_emit_calcBlockSizeSmall:
+ MOVL DX, 12(SP)
+ JMP search_loop_calcBlockSizeSmall
+
+no_repeat_found_calcBlockSizeSmall:
+ CMPL (BX)(SI*1), DI
+ JEQ candidate_match_calcBlockSizeSmall
+ SHRQ $0x08, DI
+ MOVL (AX)(R10*4), SI
+ LEAL 2(DX), R9
+ CMPL (BX)(R8*1), DI
+ JEQ candidate2_match_calcBlockSizeSmall
+ MOVL R9, (AX)(R10*4)
+ SHRQ $0x08, DI
+ CMPL (BX)(SI*1), DI
+ JEQ candidate3_match_calcBlockSizeSmall
+ MOVL 20(SP), DX
+ JMP search_loop_calcBlockSizeSmall
+
+candidate3_match_calcBlockSizeSmall:
+ ADDL $0x02, DX
+ JMP candidate_match_calcBlockSizeSmall
+
+candidate2_match_calcBlockSizeSmall:
+ MOVL R9, (AX)(R10*4)
+ INCL DX
+ MOVL R8, SI
+
+candidate_match_calcBlockSizeSmall:
+ MOVL 12(SP), DI
+ TESTL SI, SI
+ JZ match_extend_back_end_calcBlockSizeSmall
+
+match_extend_back_loop_calcBlockSizeSmall:
+ CMPL DX, DI
+ JBE match_extend_back_end_calcBlockSizeSmall
+ MOVB -1(BX)(SI*1), R8
+ MOVB -1(BX)(DX*1), R9
+ CMPB R8, R9
+ JNE match_extend_back_end_calcBlockSizeSmall
+ LEAL -1(DX), DX
+ DECL SI
+ JZ match_extend_back_end_calcBlockSizeSmall
+ JMP match_extend_back_loop_calcBlockSizeSmall
+
+match_extend_back_end_calcBlockSizeSmall:
+ MOVL DX, DI
+ SUBL 12(SP), DI
+ LEAQ 3(CX)(DI*1), DI
+ CMPQ DI, (SP)
+ JB match_dst_size_check_calcBlockSizeSmall
+ MOVQ $0x00000000, ret+32(FP)
+ RET
+
+match_dst_size_check_calcBlockSizeSmall:
+ MOVL DX, DI
+ MOVL 12(SP), R8
+ CMPL R8, DI
+ JEQ emit_literal_done_match_emit_calcBlockSizeSmall
+ MOVL DI, R9
+ MOVL DI, 12(SP)
+ LEAQ (BX)(R8*1), DI
+ SUBL R8, R9
+ LEAL -1(R9), DI
+ CMPL DI, $0x3c
+ JB one_byte_match_emit_calcBlockSizeSmall
+ CMPL DI, $0x00000100
+ JB two_bytes_match_emit_calcBlockSizeSmall
+ JB three_bytes_match_emit_calcBlockSizeSmall
+
+three_bytes_match_emit_calcBlockSizeSmall:
+ ADDQ $0x03, CX
+ JMP memmove_long_match_emit_calcBlockSizeSmall
+
+two_bytes_match_emit_calcBlockSizeSmall:
+ ADDQ $0x02, CX
+ CMPL DI, $0x40
+ JB memmove_match_emit_calcBlockSizeSmall
+ JMP memmove_long_match_emit_calcBlockSizeSmall
+
+one_byte_match_emit_calcBlockSizeSmall:
+ ADDQ $0x01, CX
+
+memmove_match_emit_calcBlockSizeSmall:
+ LEAQ (CX)(R9*1), CX
+ JMP emit_literal_done_match_emit_calcBlockSizeSmall
+
+memmove_long_match_emit_calcBlockSizeSmall:
+ LEAQ (CX)(R9*1), CX
+
+emit_literal_done_match_emit_calcBlockSizeSmall:
+match_nolit_loop_calcBlockSizeSmall:
+ MOVL DX, DI
+ SUBL SI, DI
+ MOVL DI, 16(SP)
+ ADDL $0x04, DX
+ ADDL $0x04, SI
+ MOVQ src_len+8(FP), DI
+ SUBL DX, DI
+ LEAQ (BX)(DX*1), R8
+ LEAQ (BX)(SI*1), SI
+
+ // matchLen
+ XORL R10, R10
+
+matchlen_loopback_16_match_nolit_calcBlockSizeSmall:
+ CMPL DI, $0x10
+ JB matchlen_match8_match_nolit_calcBlockSizeSmall
+ MOVQ (R8)(R10*1), R9
+ MOVQ 8(R8)(R10*1), R11
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_calcBlockSizeSmall
+ XORQ 8(SI)(R10*1), R11
+ JNZ matchlen_bsf_16match_nolit_calcBlockSizeSmall
+ LEAL -16(DI), DI
+ LEAL 16(R10), R10
+ JMP matchlen_loopback_16_match_nolit_calcBlockSizeSmall
+
+matchlen_bsf_16match_nolit_calcBlockSizeSmall:
+#ifdef GOAMD64_v3
+ TZCNTQ R11, R11
+
+#else
+ BSFQ R11, R11
+
+#endif
+ SARQ $0x03, R11
+ LEAL 8(R10)(R11*1), R10
+ JMP match_nolit_end_calcBlockSizeSmall
+
+matchlen_match8_match_nolit_calcBlockSizeSmall:
+ CMPL DI, $0x08
+ JB matchlen_match4_match_nolit_calcBlockSizeSmall
+ MOVQ (R8)(R10*1), R9
+ XORQ (SI)(R10*1), R9
+ JNZ matchlen_bsf_8_match_nolit_calcBlockSizeSmall
+ LEAL -8(DI), DI
+ LEAL 8(R10), R10
+ JMP matchlen_match4_match_nolit_calcBlockSizeSmall
+
+matchlen_bsf_8_match_nolit_calcBlockSizeSmall:
+#ifdef GOAMD64_v3
+ TZCNTQ R9, R9
+
+#else
+ BSFQ R9, R9
+
+#endif
+ SARQ $0x03, R9
+ LEAL (R10)(R9*1), R10
+ JMP match_nolit_end_calcBlockSizeSmall
+
+matchlen_match4_match_nolit_calcBlockSizeSmall:
+ CMPL DI, $0x04
+ JB matchlen_match2_match_nolit_calcBlockSizeSmall
+ MOVL (R8)(R10*1), R9
+ CMPL (SI)(R10*1), R9
+ JNE matchlen_match2_match_nolit_calcBlockSizeSmall
+ LEAL -4(DI), DI
+ LEAL 4(R10), R10
+
+matchlen_match2_match_nolit_calcBlockSizeSmall:
+ CMPL DI, $0x01
+ JE matchlen_match1_match_nolit_calcBlockSizeSmall
+ JB match_nolit_end_calcBlockSizeSmall
+ MOVW (R8)(R10*1), R9
+ CMPW (SI)(R10*1), R9
+ JNE matchlen_match1_match_nolit_calcBlockSizeSmall
+ LEAL 2(R10), R10
+ SUBL $0x02, DI
+ JZ match_nolit_end_calcBlockSizeSmall
+
+matchlen_match1_match_nolit_calcBlockSizeSmall:
+ MOVB (R8)(R10*1), R9
+ CMPB (SI)(R10*1), R9
+ JNE match_nolit_end_calcBlockSizeSmall
+ LEAL 1(R10), R10
+
+match_nolit_end_calcBlockSizeSmall:
+ ADDL R10, DX
+ MOVL 16(SP), SI
+ ADDL $0x04, R10
+ MOVL DX, 12(SP)
+
+ // emitCopy
+two_byte_offset_match_nolit_calcBlockSizeSmall:
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_match_nolit_calcBlockSizeSmall
+ LEAL -60(R10), R10
+ ADDQ $0x03, CX
+ JMP two_byte_offset_match_nolit_calcBlockSizeSmall
+
+two_byte_offset_short_match_nolit_calcBlockSizeSmall:
+ MOVL R10, SI
+ SHLL $0x02, SI
+ CMPL R10, $0x0c
+ JAE emit_copy_three_match_nolit_calcBlockSizeSmall
+ ADDQ $0x02, CX
+ JMP match_nolit_emitcopy_end_calcBlockSizeSmall
+
+emit_copy_three_match_nolit_calcBlockSizeSmall:
+ ADDQ $0x03, CX
+
+match_nolit_emitcopy_end_calcBlockSizeSmall:
+ CMPL DX, 8(SP)
+ JAE emit_remainder_calcBlockSizeSmall
+ MOVQ -2(BX)(DX*1), DI
+ CMPQ CX, (SP)
+ JB match_nolit_dst_ok_calcBlockSizeSmall
+ MOVQ $0x00000000, ret+32(FP)
+ RET
+
+match_nolit_dst_ok_calcBlockSizeSmall:
+ MOVQ $0x9e3779b1, R9
+ MOVQ DI, R8
+ SHRQ $0x10, DI
+ MOVQ DI, SI
+ SHLQ $0x20, R8
+ IMULQ R9, R8
+ SHRQ $0x37, R8
+ SHLQ $0x20, SI
+ IMULQ R9, SI
+ SHRQ $0x37, SI
+ LEAL -2(DX), R9
+ LEAQ (AX)(SI*4), R10
+ MOVL (R10), SI
+ MOVL R9, (AX)(R8*4)
+ MOVL DX, (R10)
+ CMPL (BX)(SI*1), DI
+ JEQ match_nolit_loop_calcBlockSizeSmall
+ INCL DX
+ JMP search_loop_calcBlockSizeSmall
+
+emit_remainder_calcBlockSizeSmall:
+ MOVQ src_len+8(FP), AX
+ SUBL 12(SP), AX
+ LEAQ 3(CX)(AX*1), AX
+ CMPQ AX, (SP)
+ JB emit_remainder_ok_calcBlockSizeSmall
+ MOVQ $0x00000000, ret+32(FP)
+ RET
+
+emit_remainder_ok_calcBlockSizeSmall:
+ MOVQ src_len+8(FP), AX
+ MOVL 12(SP), DX
+ CMPL DX, AX
+ JEQ emit_literal_done_emit_remainder_calcBlockSizeSmall
+ MOVL AX, SI
+ MOVL AX, 12(SP)
+ LEAQ (BX)(DX*1), AX
+ SUBL DX, SI
+ LEAL -1(SI), AX
+ CMPL AX, $0x3c
+ JB one_byte_emit_remainder_calcBlockSizeSmall
+ CMPL AX, $0x00000100
+ JB two_bytes_emit_remainder_calcBlockSizeSmall
+ JB three_bytes_emit_remainder_calcBlockSizeSmall
+
+three_bytes_emit_remainder_calcBlockSizeSmall:
+ ADDQ $0x03, CX
+ JMP memmove_long_emit_remainder_calcBlockSizeSmall
+
+two_bytes_emit_remainder_calcBlockSizeSmall:
+ ADDQ $0x02, CX
+ CMPL AX, $0x40
+ JB memmove_emit_remainder_calcBlockSizeSmall
+ JMP memmove_long_emit_remainder_calcBlockSizeSmall
+
+one_byte_emit_remainder_calcBlockSizeSmall:
+ ADDQ $0x01, CX
+
+memmove_emit_remainder_calcBlockSizeSmall:
+ LEAQ (CX)(SI*1), AX
+ MOVQ AX, CX
+ JMP emit_literal_done_emit_remainder_calcBlockSizeSmall
+
+memmove_long_emit_remainder_calcBlockSizeSmall:
+ LEAQ (CX)(SI*1), AX
+ MOVQ AX, CX
+
+emit_literal_done_emit_remainder_calcBlockSizeSmall:
+ MOVQ CX, ret+32(FP)
+ RET
+
+// func emitLiteral(dst []byte, lit []byte) int
+// Requires: SSE2
+TEXT ·emitLiteral(SB), NOSPLIT, $0-56
+ MOVQ lit_len+32(FP), DX
+ MOVQ dst_base+0(FP), AX
+ MOVQ lit_base+24(FP), CX
+ TESTQ DX, DX
+ JZ emit_literal_end_standalone_skip
+ MOVL DX, BX
+ LEAL -1(DX), SI
+ CMPL SI, $0x3c
+ JB one_byte_standalone
+ CMPL SI, $0x00000100
+ JB two_bytes_standalone
+ CMPL SI, $0x00010000
+ JB three_bytes_standalone
+ CMPL SI, $0x01000000
+ JB four_bytes_standalone
+ MOVB $0xfc, (AX)
+ MOVL SI, 1(AX)
+ ADDQ $0x05, BX
+ ADDQ $0x05, AX
+ JMP memmove_long_standalone
+
+four_bytes_standalone:
+ MOVL SI, DI
+ SHRL $0x10, DI
+ MOVB $0xf8, (AX)
+ MOVW SI, 1(AX)
+ MOVB DI, 3(AX)
+ ADDQ $0x04, BX
+ ADDQ $0x04, AX
+ JMP memmove_long_standalone
+
+three_bytes_standalone:
+ MOVB $0xf4, (AX)
+ MOVW SI, 1(AX)
+ ADDQ $0x03, BX
+ ADDQ $0x03, AX
+ JMP memmove_long_standalone
+
+two_bytes_standalone:
+ MOVB $0xf0, (AX)
+ MOVB SI, 1(AX)
+ ADDQ $0x02, BX
+ ADDQ $0x02, AX
+ CMPL SI, $0x40
+ JB memmove_standalone
+ JMP memmove_long_standalone
+
+one_byte_standalone:
+ SHLB $0x02, SI
+ MOVB SI, (AX)
+ ADDQ $0x01, BX
+ ADDQ $0x01, AX
+
+memmove_standalone:
+ // genMemMoveShort
+ CMPQ DX, $0x03
+ JB emit_lit_memmove_standalone_memmove_move_1or2
+ JE emit_lit_memmove_standalone_memmove_move_3
+ CMPQ DX, $0x08
+ JB emit_lit_memmove_standalone_memmove_move_4through7
+ CMPQ DX, $0x10
+ JBE emit_lit_memmove_standalone_memmove_move_8through16
+ CMPQ DX, $0x20
+ JBE emit_lit_memmove_standalone_memmove_move_17through32
+ JMP emit_lit_memmove_standalone_memmove_move_33through64
+
+emit_lit_memmove_standalone_memmove_move_1or2:
+ MOVB (CX), SI
+ MOVB -1(CX)(DX*1), CL
+ MOVB SI, (AX)
+ MOVB CL, -1(AX)(DX*1)
+ JMP emit_literal_end_standalone
+
+emit_lit_memmove_standalone_memmove_move_3:
+ MOVW (CX), SI
+ MOVB 2(CX), CL
+ MOVW SI, (AX)
+ MOVB CL, 2(AX)
+ JMP emit_literal_end_standalone
+
+emit_lit_memmove_standalone_memmove_move_4through7:
+ MOVL (CX), SI
+ MOVL -4(CX)(DX*1), CX
+ MOVL SI, (AX)
+ MOVL CX, -4(AX)(DX*1)
+ JMP emit_literal_end_standalone
+
+emit_lit_memmove_standalone_memmove_move_8through16:
+ MOVQ (CX), SI
+ MOVQ -8(CX)(DX*1), CX
+ MOVQ SI, (AX)
+ MOVQ CX, -8(AX)(DX*1)
+ JMP emit_literal_end_standalone
+
+emit_lit_memmove_standalone_memmove_move_17through32:
+ MOVOU (CX), X0
+ MOVOU -16(CX)(DX*1), X1
+ MOVOU X0, (AX)
+ MOVOU X1, -16(AX)(DX*1)
+ JMP emit_literal_end_standalone
+
+emit_lit_memmove_standalone_memmove_move_33through64:
+ MOVOU (CX), X0
+ MOVOU 16(CX), X1
+ MOVOU -32(CX)(DX*1), X2
+ MOVOU -16(CX)(DX*1), X3
+ MOVOU X0, (AX)
+ MOVOU X1, 16(AX)
+ MOVOU X2, -32(AX)(DX*1)
+ MOVOU X3, -16(AX)(DX*1)
+ JMP emit_literal_end_standalone
+ JMP emit_literal_end_standalone
+
+memmove_long_standalone:
+ // genMemMoveLong
+ MOVOU (CX), X0
+ MOVOU 16(CX), X1
+ MOVOU -32(CX)(DX*1), X2
+ MOVOU -16(CX)(DX*1), X3
+ MOVQ DX, DI
+ SHRQ $0x05, DI
+ MOVQ AX, SI
+ ANDL $0x0000001f, SI
+ MOVQ $0x00000040, R8
+ SUBQ SI, R8
+ DECQ DI
+ JA emit_lit_memmove_long_standalonelarge_forward_sse_loop_32
+ LEAQ -32(CX)(R8*1), SI
+ LEAQ -32(AX)(R8*1), R9
+
+emit_lit_memmove_long_standalonelarge_big_loop_back:
+ MOVOU (SI), X4
+ MOVOU 16(SI), X5
+ MOVOA X4, (R9)
+ MOVOA X5, 16(R9)
+ ADDQ $0x20, R9
+ ADDQ $0x20, SI
+ ADDQ $0x20, R8
+ DECQ DI
+ JNA emit_lit_memmove_long_standalonelarge_big_loop_back
+
+emit_lit_memmove_long_standalonelarge_forward_sse_loop_32:
+ MOVOU -32(CX)(R8*1), X4
+ MOVOU -16(CX)(R8*1), X5
+ MOVOA X4, -32(AX)(R8*1)
+ MOVOA X5, -16(AX)(R8*1)
+ ADDQ $0x20, R8
+ CMPQ DX, R8
+ JAE emit_lit_memmove_long_standalonelarge_forward_sse_loop_32
+ MOVOU X0, (AX)
+ MOVOU X1, 16(AX)
+ MOVOU X2, -32(AX)(DX*1)
+ MOVOU X3, -16(AX)(DX*1)
+ JMP emit_literal_end_standalone
+ JMP emit_literal_end_standalone
+
+emit_literal_end_standalone_skip:
+ XORQ BX, BX
+
+emit_literal_end_standalone:
+ MOVQ BX, ret+48(FP)
+ RET
+
+// func emitRepeat(dst []byte, offset int, length int) int
+TEXT ·emitRepeat(SB), NOSPLIT, $0-48
+ XORQ BX, BX
+ MOVQ dst_base+0(FP), AX
+ MOVQ offset+24(FP), CX
+ MOVQ length+32(FP), DX
+
+ // emitRepeat
+emit_repeat_again_standalone:
+ MOVL DX, SI
+ LEAL -4(DX), DX
+ CMPL SI, $0x08
+ JBE repeat_two_standalone
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_standalone
+ CMPL CX, $0x00000800
+ JB repeat_two_offset_standalone
+
+cant_repeat_two_offset_standalone:
+ CMPL DX, $0x00000104
+ JB repeat_three_standalone
+ CMPL DX, $0x00010100
+ JB repeat_four_standalone
+ CMPL DX, $0x0100ffff
+ JB repeat_five_standalone
+ LEAL -16842747(DX), DX
+ MOVL $0xfffb001d, (AX)
+ MOVB $0xff, 4(AX)
+ ADDQ $0x05, AX
+ ADDQ $0x05, BX
+ JMP emit_repeat_again_standalone
+
+repeat_five_standalone:
+ LEAL -65536(DX), DX
+ MOVL DX, CX
+ MOVW $0x001d, (AX)
+ MOVW DX, 2(AX)
+ SARL $0x10, CX
+ MOVB CL, 4(AX)
+ ADDQ $0x05, BX
+ ADDQ $0x05, AX
+ JMP gen_emit_repeat_end
+
+repeat_four_standalone:
+ LEAL -256(DX), DX
+ MOVW $0x0019, (AX)
+ MOVW DX, 2(AX)
+ ADDQ $0x04, BX
+ ADDQ $0x04, AX
+ JMP gen_emit_repeat_end
+
+repeat_three_standalone:
+ LEAL -4(DX), DX
+ MOVW $0x0015, (AX)
+ MOVB DL, 2(AX)
+ ADDQ $0x03, BX
+ ADDQ $0x03, AX
+ JMP gen_emit_repeat_end
+
+repeat_two_standalone:
+ SHLL $0x02, DX
+ ORL $0x01, DX
+ MOVW DX, (AX)
+ ADDQ $0x02, BX
+ ADDQ $0x02, AX
+ JMP gen_emit_repeat_end
+
+repeat_two_offset_standalone:
+ XORQ SI, SI
+ LEAL 1(SI)(DX*4), DX
+ MOVB CL, 1(AX)
+ SARL $0x08, CX
+ SHLL $0x05, CX
+ ORL CX, DX
+ MOVB DL, (AX)
+ ADDQ $0x02, BX
+ ADDQ $0x02, AX
+
+gen_emit_repeat_end:
+ MOVQ BX, ret+40(FP)
+ RET
+
+// func emitCopy(dst []byte, offset int, length int) int
+TEXT ·emitCopy(SB), NOSPLIT, $0-48
+ XORQ BX, BX
+ MOVQ dst_base+0(FP), AX
+ MOVQ offset+24(FP), CX
+ MOVQ length+32(FP), DX
+
+ // emitCopy
+ CMPL CX, $0x00010000
+ JB two_byte_offset_standalone
+ CMPL DX, $0x40
+ JBE four_bytes_remain_standalone
+ MOVB $0xff, (AX)
+ MOVL CX, 1(AX)
+ LEAL -64(DX), DX
+ ADDQ $0x05, BX
+ ADDQ $0x05, AX
+ CMPL DX, $0x04
+ JB four_bytes_remain_standalone
+
+ // emitRepeat
+emit_repeat_again_standalone_emit_copy:
+ MOVL DX, SI
+ LEAL -4(DX), DX
+ CMPL SI, $0x08
+ JBE repeat_two_standalone_emit_copy
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_standalone_emit_copy
+ CMPL CX, $0x00000800
+ JB repeat_two_offset_standalone_emit_copy
+
+cant_repeat_two_offset_standalone_emit_copy:
+ CMPL DX, $0x00000104
+ JB repeat_three_standalone_emit_copy
+ CMPL DX, $0x00010100
+ JB repeat_four_standalone_emit_copy
+ CMPL DX, $0x0100ffff
+ JB repeat_five_standalone_emit_copy
+ LEAL -16842747(DX), DX
+ MOVL $0xfffb001d, (AX)
+ MOVB $0xff, 4(AX)
+ ADDQ $0x05, AX
+ ADDQ $0x05, BX
+ JMP emit_repeat_again_standalone_emit_copy
+
+repeat_five_standalone_emit_copy:
+ LEAL -65536(DX), DX
+ MOVL DX, CX
+ MOVW $0x001d, (AX)
+ MOVW DX, 2(AX)
+ SARL $0x10, CX
+ MOVB CL, 4(AX)
+ ADDQ $0x05, BX
+ ADDQ $0x05, AX
+ JMP gen_emit_copy_end
+
+repeat_four_standalone_emit_copy:
+ LEAL -256(DX), DX
+ MOVW $0x0019, (AX)
+ MOVW DX, 2(AX)
+ ADDQ $0x04, BX
+ ADDQ $0x04, AX
+ JMP gen_emit_copy_end
+
+repeat_three_standalone_emit_copy:
+ LEAL -4(DX), DX
+ MOVW $0x0015, (AX)
+ MOVB DL, 2(AX)
+ ADDQ $0x03, BX
+ ADDQ $0x03, AX
+ JMP gen_emit_copy_end
+
+repeat_two_standalone_emit_copy:
+ SHLL $0x02, DX
+ ORL $0x01, DX
+ MOVW DX, (AX)
+ ADDQ $0x02, BX
+ ADDQ $0x02, AX
+ JMP gen_emit_copy_end
+
+repeat_two_offset_standalone_emit_copy:
+ XORQ SI, SI
+ LEAL 1(SI)(DX*4), DX
+ MOVB CL, 1(AX)
+ SARL $0x08, CX
+ SHLL $0x05, CX
+ ORL CX, DX
+ MOVB DL, (AX)
+ ADDQ $0x02, BX
+ ADDQ $0x02, AX
+ JMP gen_emit_copy_end
+
+four_bytes_remain_standalone:
+ TESTL DX, DX
+ JZ gen_emit_copy_end
+ XORL SI, SI
+ LEAL -1(SI)(DX*4), DX
+ MOVB DL, (AX)
+ MOVL CX, 1(AX)
+ ADDQ $0x05, BX
+ ADDQ $0x05, AX
+ JMP gen_emit_copy_end
+
+two_byte_offset_standalone:
+ CMPL DX, $0x40
+ JBE two_byte_offset_short_standalone
+ CMPL CX, $0x00000800
+ JAE long_offset_short_standalone
+ MOVL $0x00000001, SI
+ LEAL 16(SI), SI
+ MOVB CL, 1(AX)
+ MOVL CX, DI
+ SHRL $0x08, DI
+ SHLL $0x05, DI
+ ORL DI, SI
+ MOVB SI, (AX)
+ ADDQ $0x02, BX
+ ADDQ $0x02, AX
+ SUBL $0x08, DX
+
+ // emitRepeat
+ LEAL -4(DX), DX
+ JMP cant_repeat_two_offset_standalone_emit_copy_short_2b
+
+emit_repeat_again_standalone_emit_copy_short_2b:
+ MOVL DX, SI
+ LEAL -4(DX), DX
+ CMPL SI, $0x08
+ JBE repeat_two_standalone_emit_copy_short_2b
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_standalone_emit_copy_short_2b
+ CMPL CX, $0x00000800
+ JB repeat_two_offset_standalone_emit_copy_short_2b
+
+cant_repeat_two_offset_standalone_emit_copy_short_2b:
+ CMPL DX, $0x00000104
+ JB repeat_three_standalone_emit_copy_short_2b
+ CMPL DX, $0x00010100
+ JB repeat_four_standalone_emit_copy_short_2b
+ CMPL DX, $0x0100ffff
+ JB repeat_five_standalone_emit_copy_short_2b
+ LEAL -16842747(DX), DX
+ MOVL $0xfffb001d, (AX)
+ MOVB $0xff, 4(AX)
+ ADDQ $0x05, AX
+ ADDQ $0x05, BX
+ JMP emit_repeat_again_standalone_emit_copy_short_2b
+
+repeat_five_standalone_emit_copy_short_2b:
+ LEAL -65536(DX), DX
+ MOVL DX, CX
+ MOVW $0x001d, (AX)
+ MOVW DX, 2(AX)
+ SARL $0x10, CX
+ MOVB CL, 4(AX)
+ ADDQ $0x05, BX
+ ADDQ $0x05, AX
+ JMP gen_emit_copy_end
+
+repeat_four_standalone_emit_copy_short_2b:
+ LEAL -256(DX), DX
+ MOVW $0x0019, (AX)
+ MOVW DX, 2(AX)
+ ADDQ $0x04, BX
+ ADDQ $0x04, AX
+ JMP gen_emit_copy_end
+
+repeat_three_standalone_emit_copy_short_2b:
+ LEAL -4(DX), DX
+ MOVW $0x0015, (AX)
+ MOVB DL, 2(AX)
+ ADDQ $0x03, BX
+ ADDQ $0x03, AX
+ JMP gen_emit_copy_end
+
+repeat_two_standalone_emit_copy_short_2b:
+ SHLL $0x02, DX
+ ORL $0x01, DX
+ MOVW DX, (AX)
+ ADDQ $0x02, BX
+ ADDQ $0x02, AX
+ JMP gen_emit_copy_end
+
+repeat_two_offset_standalone_emit_copy_short_2b:
+ XORQ SI, SI
+ LEAL 1(SI)(DX*4), DX
+ MOVB CL, 1(AX)
+ SARL $0x08, CX
+ SHLL $0x05, CX
+ ORL CX, DX
+ MOVB DL, (AX)
+ ADDQ $0x02, BX
+ ADDQ $0x02, AX
+ JMP gen_emit_copy_end
+
+long_offset_short_standalone:
+ MOVB $0xee, (AX)
+ MOVW CX, 1(AX)
+ LEAL -60(DX), DX
+ ADDQ $0x03, AX
+ ADDQ $0x03, BX
+
+ // emitRepeat
+emit_repeat_again_standalone_emit_copy_short:
+ MOVL DX, SI
+ LEAL -4(DX), DX
+ CMPL SI, $0x08
+ JBE repeat_two_standalone_emit_copy_short
+ CMPL SI, $0x0c
+ JAE cant_repeat_two_offset_standalone_emit_copy_short
+ CMPL CX, $0x00000800
+ JB repeat_two_offset_standalone_emit_copy_short
+
+cant_repeat_two_offset_standalone_emit_copy_short:
+ CMPL DX, $0x00000104
+ JB repeat_three_standalone_emit_copy_short
+ CMPL DX, $0x00010100
+ JB repeat_four_standalone_emit_copy_short
+ CMPL DX, $0x0100ffff
+ JB repeat_five_standalone_emit_copy_short
+ LEAL -16842747(DX), DX
+ MOVL $0xfffb001d, (AX)
+ MOVB $0xff, 4(AX)
+ ADDQ $0x05, AX
+ ADDQ $0x05, BX
+ JMP emit_repeat_again_standalone_emit_copy_short
+
+repeat_five_standalone_emit_copy_short:
+ LEAL -65536(DX), DX
+ MOVL DX, CX
+ MOVW $0x001d, (AX)
+ MOVW DX, 2(AX)
+ SARL $0x10, CX
+ MOVB CL, 4(AX)
+ ADDQ $0x05, BX
+ ADDQ $0x05, AX
+ JMP gen_emit_copy_end
+
+repeat_four_standalone_emit_copy_short:
+ LEAL -256(DX), DX
+ MOVW $0x0019, (AX)
+ MOVW DX, 2(AX)
+ ADDQ $0x04, BX
+ ADDQ $0x04, AX
+ JMP gen_emit_copy_end
+
+repeat_three_standalone_emit_copy_short:
+ LEAL -4(DX), DX
+ MOVW $0x0015, (AX)
+ MOVB DL, 2(AX)
+ ADDQ $0x03, BX
+ ADDQ $0x03, AX
+ JMP gen_emit_copy_end
+
+repeat_two_standalone_emit_copy_short:
+ SHLL $0x02, DX
+ ORL $0x01, DX
+ MOVW DX, (AX)
+ ADDQ $0x02, BX
+ ADDQ $0x02, AX
+ JMP gen_emit_copy_end
+
+repeat_two_offset_standalone_emit_copy_short:
+ XORQ SI, SI
+ LEAL 1(SI)(DX*4), DX
+ MOVB CL, 1(AX)
+ SARL $0x08, CX
+ SHLL $0x05, CX
+ ORL CX, DX
+ MOVB DL, (AX)
+ ADDQ $0x02, BX
+ ADDQ $0x02, AX
+ JMP gen_emit_copy_end
+
+two_byte_offset_short_standalone:
+ MOVL DX, SI
+ SHLL $0x02, SI
+ CMPL DX, $0x0c
+ JAE emit_copy_three_standalone
+ CMPL CX, $0x00000800
+ JAE emit_copy_three_standalone
+ LEAL -15(SI), SI
+ MOVB CL, 1(AX)
+ SHRL $0x08, CX
+ SHLL $0x05, CX
+ ORL CX, SI
+ MOVB SI, (AX)
+ ADDQ $0x02, BX
+ ADDQ $0x02, AX
+ JMP gen_emit_copy_end
+
+emit_copy_three_standalone:
+ LEAL -2(SI), SI
+ MOVB SI, (AX)
+ MOVW CX, 1(AX)
+ ADDQ $0x03, BX
+ ADDQ $0x03, AX
+
+gen_emit_copy_end:
+ MOVQ BX, ret+40(FP)
+ RET
+
+// func emitCopyNoRepeat(dst []byte, offset int, length int) int
+TEXT ·emitCopyNoRepeat(SB), NOSPLIT, $0-48
+ XORQ BX, BX
+ MOVQ dst_base+0(FP), AX
+ MOVQ offset+24(FP), CX
+ MOVQ length+32(FP), DX
+
+ // emitCopy
+ CMPL CX, $0x00010000
+ JB two_byte_offset_standalone_snappy
+
+four_bytes_loop_back_standalone_snappy:
+ CMPL DX, $0x40
+ JBE four_bytes_remain_standalone_snappy
+ MOVB $0xff, (AX)
+ MOVL CX, 1(AX)
+ LEAL -64(DX), DX
+ ADDQ $0x05, BX
+ ADDQ $0x05, AX
+ CMPL DX, $0x04
+ JB four_bytes_remain_standalone_snappy
+ JMP four_bytes_loop_back_standalone_snappy
+
+four_bytes_remain_standalone_snappy:
+ TESTL DX, DX
+ JZ gen_emit_copy_end_snappy
+ XORL SI, SI
+ LEAL -1(SI)(DX*4), DX
+ MOVB DL, (AX)
+ MOVL CX, 1(AX)
+ ADDQ $0x05, BX
+ ADDQ $0x05, AX
+ JMP gen_emit_copy_end_snappy
+
+two_byte_offset_standalone_snappy:
+ CMPL DX, $0x40
+ JBE two_byte_offset_short_standalone_snappy
+ MOVB $0xee, (AX)
+ MOVW CX, 1(AX)
+ LEAL -60(DX), DX
+ ADDQ $0x03, AX
+ ADDQ $0x03, BX
+ JMP two_byte_offset_standalone_snappy
+
+two_byte_offset_short_standalone_snappy:
+ MOVL DX, SI
+ SHLL $0x02, SI
+ CMPL DX, $0x0c
+ JAE emit_copy_three_standalone_snappy
+ CMPL CX, $0x00000800
+ JAE emit_copy_three_standalone_snappy
+ LEAL -15(SI), SI
+ MOVB CL, 1(AX)
+ SHRL $0x08, CX
+ SHLL $0x05, CX
+ ORL CX, SI
+ MOVB SI, (AX)
+ ADDQ $0x02, BX
+ ADDQ $0x02, AX
+ JMP gen_emit_copy_end_snappy
+
+emit_copy_three_standalone_snappy:
+ LEAL -2(SI), SI
+ MOVB SI, (AX)
+ MOVW CX, 1(AX)
+ ADDQ $0x03, BX
+ ADDQ $0x03, AX
+
+gen_emit_copy_end_snappy:
+ MOVQ BX, ret+40(FP)
+ RET
+
+// func matchLen(a []byte, b []byte) int
+// Requires: BMI
+TEXT ·matchLen(SB), NOSPLIT, $0-56
+ MOVQ a_base+0(FP), AX
+ MOVQ b_base+24(FP), CX
+ MOVQ a_len+8(FP), DX
+
+ // matchLen
+ XORL SI, SI
+
+matchlen_loopback_16_standalone:
+ CMPL DX, $0x10
+ JB matchlen_match8_standalone
+ MOVQ (AX)(SI*1), BX
+ MOVQ 8(AX)(SI*1), DI
+ XORQ (CX)(SI*1), BX
+ JNZ matchlen_bsf_8_standalone
+ XORQ 8(CX)(SI*1), DI
+ JNZ matchlen_bsf_16standalone
+ LEAL -16(DX), DX
+ LEAL 16(SI), SI
+ JMP matchlen_loopback_16_standalone
+
+matchlen_bsf_16standalone:
+#ifdef GOAMD64_v3
+ TZCNTQ DI, DI
+
+#else
+ BSFQ DI, DI
+
+#endif
+ SARQ $0x03, DI
+ LEAL 8(SI)(DI*1), SI
+ JMP gen_match_len_end
+
+matchlen_match8_standalone:
+ CMPL DX, $0x08
+ JB matchlen_match4_standalone
+ MOVQ (AX)(SI*1), BX
+ XORQ (CX)(SI*1), BX
+ JNZ matchlen_bsf_8_standalone
+ LEAL -8(DX), DX
+ LEAL 8(SI), SI
+ JMP matchlen_match4_standalone
+
+matchlen_bsf_8_standalone:
+#ifdef GOAMD64_v3
+ TZCNTQ BX, BX
+
+#else
+ BSFQ BX, BX
+
+#endif
+ SARQ $0x03, BX
+ LEAL (SI)(BX*1), SI
+ JMP gen_match_len_end
+
+matchlen_match4_standalone:
+ CMPL DX, $0x04
+ JB matchlen_match2_standalone
+ MOVL (AX)(SI*1), BX
+ CMPL (CX)(SI*1), BX
+ JNE matchlen_match2_standalone
+ LEAL -4(DX), DX
+ LEAL 4(SI), SI
+
+matchlen_match2_standalone:
+ CMPL DX, $0x01
+ JE matchlen_match1_standalone
+ JB gen_match_len_end
+ MOVW (AX)(SI*1), BX
+ CMPW (CX)(SI*1), BX
+ JNE matchlen_match1_standalone
+ LEAL 2(SI), SI
+ SUBL $0x02, DX
+ JZ gen_match_len_end
+
+matchlen_match1_standalone:
+ MOVB (AX)(SI*1), BL
+ CMPB (CX)(SI*1), BL
+ JNE gen_match_len_end
+ LEAL 1(SI), SI
+
+gen_match_len_end:
+ MOVQ SI, ret+48(FP)
+ RET
+
+// func cvtLZ4BlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
+// Requires: SSE2
+TEXT ·cvtLZ4BlockAsm(SB), NOSPLIT, $0-64
+ XORQ SI, SI
+ MOVQ dst_base+0(FP), AX
+ MOVQ dst_len+8(FP), CX
+ MOVQ src_base+24(FP), DX
+ MOVQ src_len+32(FP), BX
+ LEAQ (DX)(BX*1), BX
+ LEAQ -8(AX)(CX*1), CX
+ XORQ DI, DI
+
+lz4_s2_loop:
+ CMPQ DX, BX
+ JAE lz4_s2_corrupt
+ CMPQ AX, CX
+ JAE lz4_s2_dstfull
+ MOVBQZX (DX), R8
+ MOVQ R8, R9
+ MOVQ R8, R10
+ SHRQ $0x04, R9
+ ANDQ $0x0f, R10
+ CMPQ R8, $0xf0
+ JB lz4_s2_ll_end
+
+lz4_s2_ll_loop:
+ INCQ DX
+ CMPQ DX, BX
+ JAE lz4_s2_corrupt
+ MOVBQZX (DX), R8
+ ADDQ R8, R9
+ CMPQ R8, $0xff
+ JEQ lz4_s2_ll_loop
+
+lz4_s2_ll_end:
+ LEAQ (DX)(R9*1), R8
+ ADDQ $0x04, R10
+ CMPQ R8, BX
+ JAE lz4_s2_corrupt
+ INCQ DX
+ INCQ R8
+ TESTQ R9, R9
+ JZ lz4_s2_lits_done
+ LEAQ (AX)(R9*1), R11
+ CMPQ R11, CX
+ JAE lz4_s2_dstfull
+ ADDQ R9, SI
+ LEAL -1(R9), R11
+ CMPL R11, $0x3c
+ JB one_byte_lz4_s2
+ CMPL R11, $0x00000100
+ JB two_bytes_lz4_s2
+ CMPL R11, $0x00010000
+ JB three_bytes_lz4_s2
+ CMPL R11, $0x01000000
+ JB four_bytes_lz4_s2
+ MOVB $0xfc, (AX)
+ MOVL R11, 1(AX)
+ ADDQ $0x05, AX
+ JMP memmove_long_lz4_s2
+
+four_bytes_lz4_s2:
+ MOVL R11, R12
+ SHRL $0x10, R12
+ MOVB $0xf8, (AX)
+ MOVW R11, 1(AX)
+ MOVB R12, 3(AX)
+ ADDQ $0x04, AX
+ JMP memmove_long_lz4_s2
+
+three_bytes_lz4_s2:
+ MOVB $0xf4, (AX)
+ MOVW R11, 1(AX)
+ ADDQ $0x03, AX
+ JMP memmove_long_lz4_s2
+
+two_bytes_lz4_s2:
+ MOVB $0xf0, (AX)
+ MOVB R11, 1(AX)
+ ADDQ $0x02, AX
+ CMPL R11, $0x40
+ JB memmove_lz4_s2
+ JMP memmove_long_lz4_s2
+
+one_byte_lz4_s2:
+ SHLB $0x02, R11
+ MOVB R11, (AX)
+ ADDQ $0x01, AX
+
+memmove_lz4_s2:
+ LEAQ (AX)(R9*1), R11
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_lz4_s2_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_lz4_s2_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_lz4_s2_memmove_move_17through32
+ JMP emit_lit_memmove_lz4_s2_memmove_move_33through64
+
+emit_lit_memmove_lz4_s2_memmove_move_8:
+ MOVQ (DX), R12
+ MOVQ R12, (AX)
+ JMP memmove_end_copy_lz4_s2
+
+emit_lit_memmove_lz4_s2_memmove_move_8through16:
+ MOVQ (DX), R12
+ MOVQ -8(DX)(R9*1), DX
+ MOVQ R12, (AX)
+ MOVQ DX, -8(AX)(R9*1)
+ JMP memmove_end_copy_lz4_s2
+
+emit_lit_memmove_lz4_s2_memmove_move_17through32:
+ MOVOU (DX), X0
+ MOVOU -16(DX)(R9*1), X1
+ MOVOU X0, (AX)
+ MOVOU X1, -16(AX)(R9*1)
+ JMP memmove_end_copy_lz4_s2
+
+emit_lit_memmove_lz4_s2_memmove_move_33through64:
+ MOVOU (DX), X0
+ MOVOU 16(DX), X1
+ MOVOU -32(DX)(R9*1), X2
+ MOVOU -16(DX)(R9*1), X3
+ MOVOU X0, (AX)
+ MOVOU X1, 16(AX)
+ MOVOU X2, -32(AX)(R9*1)
+ MOVOU X3, -16(AX)(R9*1)
+
+memmove_end_copy_lz4_s2:
+ MOVQ R11, AX
+ JMP lz4_s2_lits_emit_done
+
+memmove_long_lz4_s2:
+ LEAQ (AX)(R9*1), R11
+
+ // genMemMoveLong
+ MOVOU (DX), X0
+ MOVOU 16(DX), X1
+ MOVOU -32(DX)(R9*1), X2
+ MOVOU -16(DX)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ AX, R12
+ ANDL $0x0000001f, R12
+ MOVQ $0x00000040, R14
+ SUBQ R12, R14
+ DECQ R13
+ JA emit_lit_memmove_long_lz4_s2large_forward_sse_loop_32
+ LEAQ -32(DX)(R14*1), R12
+ LEAQ -32(AX)(R14*1), R15
+
+emit_lit_memmove_long_lz4_s2large_big_loop_back:
+ MOVOU (R12), X4
+ MOVOU 16(R12), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R12
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_lz4_s2large_big_loop_back
+
+emit_lit_memmove_long_lz4_s2large_forward_sse_loop_32:
+ MOVOU -32(DX)(R14*1), X4
+ MOVOU -16(DX)(R14*1), X5
+ MOVOA X4, -32(AX)(R14*1)
+ MOVOA X5, -16(AX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_lz4_s2large_forward_sse_loop_32
+ MOVOU X0, (AX)
+ MOVOU X1, 16(AX)
+ MOVOU X2, -32(AX)(R9*1)
+ MOVOU X3, -16(AX)(R9*1)
+ MOVQ R11, AX
+
+lz4_s2_lits_emit_done:
+ MOVQ R8, DX
+
+lz4_s2_lits_done:
+ CMPQ DX, BX
+ JNE lz4_s2_match
+ CMPQ R10, $0x04
+ JEQ lz4_s2_done
+ JMP lz4_s2_corrupt
+
+lz4_s2_match:
+ LEAQ 2(DX), R8
+ CMPQ R8, BX
+ JAE lz4_s2_corrupt
+ MOVWQZX (DX), R9
+ MOVQ R8, DX
+ TESTQ R9, R9
+ JZ lz4_s2_corrupt
+ CMPQ R9, SI
+ JA lz4_s2_corrupt
+ CMPQ R10, $0x13
+ JNE lz4_s2_ml_done
+
+lz4_s2_ml_loop:
+ MOVBQZX (DX), R8
+ INCQ DX
+ ADDQ R8, R10
+ CMPQ DX, BX
+ JAE lz4_s2_corrupt
+ CMPQ R8, $0xff
+ JEQ lz4_s2_ml_loop
+
+lz4_s2_ml_done:
+ ADDQ R10, SI
+ CMPQ R9, DI
+ JNE lz4_s2_docopy
+
+ // emitRepeat
+emit_repeat_again_lz4_s2:
+ MOVL R10, R8
+ LEAL -4(R10), R10
+ CMPL R8, $0x08
+ JBE repeat_two_lz4_s2
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_lz4_s2
+ CMPL R9, $0x00000800
+ JB repeat_two_offset_lz4_s2
+
+cant_repeat_two_offset_lz4_s2:
+ CMPL R10, $0x00000104
+ JB repeat_three_lz4_s2
+ CMPL R10, $0x00010100
+ JB repeat_four_lz4_s2
+ CMPL R10, $0x0100ffff
+ JB repeat_five_lz4_s2
+ LEAL -16842747(R10), R10
+ MOVL $0xfffb001d, (AX)
+ MOVB $0xff, 4(AX)
+ ADDQ $0x05, AX
+ JMP emit_repeat_again_lz4_s2
+
+repeat_five_lz4_s2:
+ LEAL -65536(R10), R10
+ MOVL R10, R9
+ MOVW $0x001d, (AX)
+ MOVW R10, 2(AX)
+ SARL $0x10, R9
+ MOVB R9, 4(AX)
+ ADDQ $0x05, AX
+ JMP lz4_s2_loop
+
+repeat_four_lz4_s2:
+ LEAL -256(R10), R10
+ MOVW $0x0019, (AX)
+ MOVW R10, 2(AX)
+ ADDQ $0x04, AX
+ JMP lz4_s2_loop
+
+repeat_three_lz4_s2:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (AX)
+ MOVB R10, 2(AX)
+ ADDQ $0x03, AX
+ JMP lz4_s2_loop
+
+repeat_two_lz4_s2:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (AX)
+ ADDQ $0x02, AX
+ JMP lz4_s2_loop
+
+repeat_two_offset_lz4_s2:
+ XORQ R8, R8
+ LEAL 1(R8)(R10*4), R10
+ MOVB R9, 1(AX)
+ SARL $0x08, R9
+ SHLL $0x05, R9
+ ORL R9, R10
+ MOVB R10, (AX)
+ ADDQ $0x02, AX
+ JMP lz4_s2_loop
+
+lz4_s2_docopy:
+ MOVQ R9, DI
+
+ // emitCopy
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_lz4_s2
+ CMPL R9, $0x00000800
+ JAE long_offset_short_lz4_s2
+ MOVL $0x00000001, R8
+ LEAL 16(R8), R8
+ MOVB R9, 1(AX)
+ MOVL R9, R11
+ SHRL $0x08, R11
+ SHLL $0x05, R11
+ ORL R11, R8
+ MOVB R8, (AX)
+ ADDQ $0x02, AX
+ SUBL $0x08, R10
+
+ // emitRepeat
+ LEAL -4(R10), R10
+ JMP cant_repeat_two_offset_lz4_s2_emit_copy_short_2b
+
+emit_repeat_again_lz4_s2_emit_copy_short_2b:
+ MOVL R10, R8
+ LEAL -4(R10), R10
+ CMPL R8, $0x08
+ JBE repeat_two_lz4_s2_emit_copy_short_2b
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_lz4_s2_emit_copy_short_2b
+ CMPL R9, $0x00000800
+ JB repeat_two_offset_lz4_s2_emit_copy_short_2b
+
+cant_repeat_two_offset_lz4_s2_emit_copy_short_2b:
+ CMPL R10, $0x00000104
+ JB repeat_three_lz4_s2_emit_copy_short_2b
+ CMPL R10, $0x00010100
+ JB repeat_four_lz4_s2_emit_copy_short_2b
+ CMPL R10, $0x0100ffff
+ JB repeat_five_lz4_s2_emit_copy_short_2b
+ LEAL -16842747(R10), R10
+ MOVL $0xfffb001d, (AX)
+ MOVB $0xff, 4(AX)
+ ADDQ $0x05, AX
+ JMP emit_repeat_again_lz4_s2_emit_copy_short_2b
+
+repeat_five_lz4_s2_emit_copy_short_2b:
+ LEAL -65536(R10), R10
+ MOVL R10, R9
+ MOVW $0x001d, (AX)
+ MOVW R10, 2(AX)
+ SARL $0x10, R9
+ MOVB R9, 4(AX)
+ ADDQ $0x05, AX
+ JMP lz4_s2_loop
+
+repeat_four_lz4_s2_emit_copy_short_2b:
+ LEAL -256(R10), R10
+ MOVW $0x0019, (AX)
+ MOVW R10, 2(AX)
+ ADDQ $0x04, AX
+ JMP lz4_s2_loop
+
+repeat_three_lz4_s2_emit_copy_short_2b:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (AX)
+ MOVB R10, 2(AX)
+ ADDQ $0x03, AX
+ JMP lz4_s2_loop
+
+repeat_two_lz4_s2_emit_copy_short_2b:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (AX)
+ ADDQ $0x02, AX
+ JMP lz4_s2_loop
+
+repeat_two_offset_lz4_s2_emit_copy_short_2b:
+ XORQ R8, R8
+ LEAL 1(R8)(R10*4), R10
+ MOVB R9, 1(AX)
+ SARL $0x08, R9
+ SHLL $0x05, R9
+ ORL R9, R10
+ MOVB R10, (AX)
+ ADDQ $0x02, AX
+ JMP lz4_s2_loop
+
+long_offset_short_lz4_s2:
+ MOVB $0xee, (AX)
+ MOVW R9, 1(AX)
+ LEAL -60(R10), R10
+ ADDQ $0x03, AX
+
+ // emitRepeat
+emit_repeat_again_lz4_s2_emit_copy_short:
+ MOVL R10, R8
+ LEAL -4(R10), R10
+ CMPL R8, $0x08
+ JBE repeat_two_lz4_s2_emit_copy_short
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_lz4_s2_emit_copy_short
+ CMPL R9, $0x00000800
+ JB repeat_two_offset_lz4_s2_emit_copy_short
+
+cant_repeat_two_offset_lz4_s2_emit_copy_short:
+ CMPL R10, $0x00000104
+ JB repeat_three_lz4_s2_emit_copy_short
+ CMPL R10, $0x00010100
+ JB repeat_four_lz4_s2_emit_copy_short
+ CMPL R10, $0x0100ffff
+ JB repeat_five_lz4_s2_emit_copy_short
+ LEAL -16842747(R10), R10
+ MOVL $0xfffb001d, (AX)
+ MOVB $0xff, 4(AX)
+ ADDQ $0x05, AX
+ JMP emit_repeat_again_lz4_s2_emit_copy_short
+
+repeat_five_lz4_s2_emit_copy_short:
+ LEAL -65536(R10), R10
+ MOVL R10, R9
+ MOVW $0x001d, (AX)
+ MOVW R10, 2(AX)
+ SARL $0x10, R9
+ MOVB R9, 4(AX)
+ ADDQ $0x05, AX
+ JMP lz4_s2_loop
+
+repeat_four_lz4_s2_emit_copy_short:
+ LEAL -256(R10), R10
+ MOVW $0x0019, (AX)
+ MOVW R10, 2(AX)
+ ADDQ $0x04, AX
+ JMP lz4_s2_loop
+
+repeat_three_lz4_s2_emit_copy_short:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (AX)
+ MOVB R10, 2(AX)
+ ADDQ $0x03, AX
+ JMP lz4_s2_loop
+
+repeat_two_lz4_s2_emit_copy_short:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (AX)
+ ADDQ $0x02, AX
+ JMP lz4_s2_loop
+
+repeat_two_offset_lz4_s2_emit_copy_short:
+ XORQ R8, R8
+ LEAL 1(R8)(R10*4), R10
+ MOVB R9, 1(AX)
+ SARL $0x08, R9
+ SHLL $0x05, R9
+ ORL R9, R10
+ MOVB R10, (AX)
+ ADDQ $0x02, AX
+ JMP lz4_s2_loop
+
+two_byte_offset_short_lz4_s2:
+ MOVL R10, R8
+ SHLL $0x02, R8
+ CMPL R10, $0x0c
+ JAE emit_copy_three_lz4_s2
+ CMPL R9, $0x00000800
+ JAE emit_copy_three_lz4_s2
+ LEAL -15(R8), R8
+ MOVB R9, 1(AX)
+ SHRL $0x08, R9
+ SHLL $0x05, R9
+ ORL R9, R8
+ MOVB R8, (AX)
+ ADDQ $0x02, AX
+ JMP lz4_s2_loop
+
+emit_copy_three_lz4_s2:
+ LEAL -2(R8), R8
+ MOVB R8, (AX)
+ MOVW R9, 1(AX)
+ ADDQ $0x03, AX
+ JMP lz4_s2_loop
+
+lz4_s2_done:
+ MOVQ dst_base+0(FP), CX
+ SUBQ CX, AX
+ MOVQ SI, uncompressed+48(FP)
+ MOVQ AX, dstUsed+56(FP)
+ RET
+
+lz4_s2_corrupt:
+ XORQ AX, AX
+ LEAQ -1(AX), SI
+ MOVQ SI, uncompressed+48(FP)
+ RET
+
+lz4_s2_dstfull:
+ XORQ AX, AX
+ LEAQ -2(AX), SI
+ MOVQ SI, uncompressed+48(FP)
+ RET
+
+// func cvtLZ4sBlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
+// Requires: SSE2
+TEXT ·cvtLZ4sBlockAsm(SB), NOSPLIT, $0-64
+ XORQ SI, SI
+ MOVQ dst_base+0(FP), AX
+ MOVQ dst_len+8(FP), CX
+ MOVQ src_base+24(FP), DX
+ MOVQ src_len+32(FP), BX
+ LEAQ (DX)(BX*1), BX
+ LEAQ -8(AX)(CX*1), CX
+ XORQ DI, DI
+
+lz4s_s2_loop:
+ CMPQ DX, BX
+ JAE lz4s_s2_corrupt
+ CMPQ AX, CX
+ JAE lz4s_s2_dstfull
+ MOVBQZX (DX), R8
+ MOVQ R8, R9
+ MOVQ R8, R10
+ SHRQ $0x04, R9
+ ANDQ $0x0f, R10
+ CMPQ R8, $0xf0
+ JB lz4s_s2_ll_end
+
+lz4s_s2_ll_loop:
+ INCQ DX
+ CMPQ DX, BX
+ JAE lz4s_s2_corrupt
+ MOVBQZX (DX), R8
+ ADDQ R8, R9
+ CMPQ R8, $0xff
+ JEQ lz4s_s2_ll_loop
+
+lz4s_s2_ll_end:
+ LEAQ (DX)(R9*1), R8
+ ADDQ $0x03, R10
+ CMPQ R8, BX
+ JAE lz4s_s2_corrupt
+ INCQ DX
+ INCQ R8
+ TESTQ R9, R9
+ JZ lz4s_s2_lits_done
+ LEAQ (AX)(R9*1), R11
+ CMPQ R11, CX
+ JAE lz4s_s2_dstfull
+ ADDQ R9, SI
+ LEAL -1(R9), R11
+ CMPL R11, $0x3c
+ JB one_byte_lz4s_s2
+ CMPL R11, $0x00000100
+ JB two_bytes_lz4s_s2
+ CMPL R11, $0x00010000
+ JB three_bytes_lz4s_s2
+ CMPL R11, $0x01000000
+ JB four_bytes_lz4s_s2
+ MOVB $0xfc, (AX)
+ MOVL R11, 1(AX)
+ ADDQ $0x05, AX
+ JMP memmove_long_lz4s_s2
+
+four_bytes_lz4s_s2:
+ MOVL R11, R12
+ SHRL $0x10, R12
+ MOVB $0xf8, (AX)
+ MOVW R11, 1(AX)
+ MOVB R12, 3(AX)
+ ADDQ $0x04, AX
+ JMP memmove_long_lz4s_s2
+
+three_bytes_lz4s_s2:
+ MOVB $0xf4, (AX)
+ MOVW R11, 1(AX)
+ ADDQ $0x03, AX
+ JMP memmove_long_lz4s_s2
+
+two_bytes_lz4s_s2:
+ MOVB $0xf0, (AX)
+ MOVB R11, 1(AX)
+ ADDQ $0x02, AX
+ CMPL R11, $0x40
+ JB memmove_lz4s_s2
+ JMP memmove_long_lz4s_s2
+
+one_byte_lz4s_s2:
+ SHLB $0x02, R11
+ MOVB R11, (AX)
+ ADDQ $0x01, AX
+
+memmove_lz4s_s2:
+ LEAQ (AX)(R9*1), R11
+
+ // genMemMoveShort
+ CMPQ R9, $0x08
+ JBE emit_lit_memmove_lz4s_s2_memmove_move_8
+ CMPQ R9, $0x10
+ JBE emit_lit_memmove_lz4s_s2_memmove_move_8through16
+ CMPQ R9, $0x20
+ JBE emit_lit_memmove_lz4s_s2_memmove_move_17through32
+ JMP emit_lit_memmove_lz4s_s2_memmove_move_33through64
+
+emit_lit_memmove_lz4s_s2_memmove_move_8:
+ MOVQ (DX), R12
+ MOVQ R12, (AX)
+ JMP memmove_end_copy_lz4s_s2
+
+emit_lit_memmove_lz4s_s2_memmove_move_8through16:
+ MOVQ (DX), R12
+ MOVQ -8(DX)(R9*1), DX
+ MOVQ R12, (AX)
+ MOVQ DX, -8(AX)(R9*1)
+ JMP memmove_end_copy_lz4s_s2
+
+emit_lit_memmove_lz4s_s2_memmove_move_17through32:
+ MOVOU (DX), X0
+ MOVOU -16(DX)(R9*1), X1
+ MOVOU X0, (AX)
+ MOVOU X1, -16(AX)(R9*1)
+ JMP memmove_end_copy_lz4s_s2
+
+emit_lit_memmove_lz4s_s2_memmove_move_33through64:
+ MOVOU (DX), X0
+ MOVOU 16(DX), X1
+ MOVOU -32(DX)(R9*1), X2
+ MOVOU -16(DX)(R9*1), X3
+ MOVOU X0, (AX)
+ MOVOU X1, 16(AX)
+ MOVOU X2, -32(AX)(R9*1)
+ MOVOU X3, -16(AX)(R9*1)
+
+memmove_end_copy_lz4s_s2:
+ MOVQ R11, AX
+ JMP lz4s_s2_lits_emit_done
+
+memmove_long_lz4s_s2:
+ LEAQ (AX)(R9*1), R11
+
+ // genMemMoveLong
+ MOVOU (DX), X0
+ MOVOU 16(DX), X1
+ MOVOU -32(DX)(R9*1), X2
+ MOVOU -16(DX)(R9*1), X3
+ MOVQ R9, R13
+ SHRQ $0x05, R13
+ MOVQ AX, R12
+ ANDL $0x0000001f, R12
+ MOVQ $0x00000040, R14
+ SUBQ R12, R14
+ DECQ R13
+ JA emit_lit_memmove_long_lz4s_s2large_forward_sse_loop_32
+ LEAQ -32(DX)(R14*1), R12
+ LEAQ -32(AX)(R14*1), R15
+
+emit_lit_memmove_long_lz4s_s2large_big_loop_back:
+ MOVOU (R12), X4
+ MOVOU 16(R12), X5
+ MOVOA X4, (R15)
+ MOVOA X5, 16(R15)
+ ADDQ $0x20, R15
+ ADDQ $0x20, R12
+ ADDQ $0x20, R14
+ DECQ R13
+ JNA emit_lit_memmove_long_lz4s_s2large_big_loop_back
+
+emit_lit_memmove_long_lz4s_s2large_forward_sse_loop_32:
+ MOVOU -32(DX)(R14*1), X4
+ MOVOU -16(DX)(R14*1), X5
+ MOVOA X4, -32(AX)(R14*1)
+ MOVOA X5, -16(AX)(R14*1)
+ ADDQ $0x20, R14
+ CMPQ R9, R14
+ JAE emit_lit_memmove_long_lz4s_s2large_forward_sse_loop_32
+ MOVOU X0, (AX)
+ MOVOU X1, 16(AX)
+ MOVOU X2, -32(AX)(R9*1)
+ MOVOU X3, -16(AX)(R9*1)
+ MOVQ R11, AX
+
+lz4s_s2_lits_emit_done:
+ MOVQ R8, DX
+
+lz4s_s2_lits_done:
+ CMPQ DX, BX
+ JNE lz4s_s2_match
+ CMPQ R10, $0x03
+ JEQ lz4s_s2_done
+ JMP lz4s_s2_corrupt
+
+lz4s_s2_match:
+ CMPQ R10, $0x03
+ JEQ lz4s_s2_loop
+ LEAQ 2(DX), R8
+ CMPQ R8, BX
+ JAE lz4s_s2_corrupt
+ MOVWQZX (DX), R9
+ MOVQ R8, DX
+ TESTQ R9, R9
+ JZ lz4s_s2_corrupt
+ CMPQ R9, SI
+ JA lz4s_s2_corrupt
+ CMPQ R10, $0x12
+ JNE lz4s_s2_ml_done
+
+lz4s_s2_ml_loop:
+ MOVBQZX (DX), R8
+ INCQ DX
+ ADDQ R8, R10
+ CMPQ DX, BX
+ JAE lz4s_s2_corrupt
+ CMPQ R8, $0xff
+ JEQ lz4s_s2_ml_loop
+
+lz4s_s2_ml_done:
+ ADDQ R10, SI
+ CMPQ R9, DI
+ JNE lz4s_s2_docopy
+
+ // emitRepeat
+emit_repeat_again_lz4_s2:
+ MOVL R10, R8
+ LEAL -4(R10), R10
+ CMPL R8, $0x08
+ JBE repeat_two_lz4_s2
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_lz4_s2
+ CMPL R9, $0x00000800
+ JB repeat_two_offset_lz4_s2
+
+cant_repeat_two_offset_lz4_s2:
+ CMPL R10, $0x00000104
+ JB repeat_three_lz4_s2
+ CMPL R10, $0x00010100
+ JB repeat_four_lz4_s2
+ CMPL R10, $0x0100ffff
+ JB repeat_five_lz4_s2
+ LEAL -16842747(R10), R10
+ MOVL $0xfffb001d, (AX)
+ MOVB $0xff, 4(AX)
+ ADDQ $0x05, AX
+ JMP emit_repeat_again_lz4_s2
+
+repeat_five_lz4_s2:
+ LEAL -65536(R10), R10
+ MOVL R10, R9
+ MOVW $0x001d, (AX)
+ MOVW R10, 2(AX)
+ SARL $0x10, R9
+ MOVB R9, 4(AX)
+ ADDQ $0x05, AX
+ JMP lz4s_s2_loop
+
+repeat_four_lz4_s2:
+ LEAL -256(R10), R10
+ MOVW $0x0019, (AX)
+ MOVW R10, 2(AX)
+ ADDQ $0x04, AX
+ JMP lz4s_s2_loop
+
+repeat_three_lz4_s2:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (AX)
+ MOVB R10, 2(AX)
+ ADDQ $0x03, AX
+ JMP lz4s_s2_loop
+
+repeat_two_lz4_s2:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (AX)
+ ADDQ $0x02, AX
+ JMP lz4s_s2_loop
+
+repeat_two_offset_lz4_s2:
+ XORQ R8, R8
+ LEAL 1(R8)(R10*4), R10
+ MOVB R9, 1(AX)
+ SARL $0x08, R9
+ SHLL $0x05, R9
+ ORL R9, R10
+ MOVB R10, (AX)
+ ADDQ $0x02, AX
+ JMP lz4s_s2_loop
+
+lz4s_s2_docopy:
+ MOVQ R9, DI
+
+ // emitCopy
+ CMPL R10, $0x40
+ JBE two_byte_offset_short_lz4_s2
+ CMPL R9, $0x00000800
+ JAE long_offset_short_lz4_s2
+ MOVL $0x00000001, R8
+ LEAL 16(R8), R8
+ MOVB R9, 1(AX)
+ MOVL R9, R11
+ SHRL $0x08, R11
+ SHLL $0x05, R11
+ ORL R11, R8
+ MOVB R8, (AX)
+ ADDQ $0x02, AX
+ SUBL $0x08, R10
+
+ // emitRepeat
+ LEAL -4(R10), R10
+ JMP cant_repeat_two_offset_lz4_s2_emit_copy_short_2b
+
+emit_repeat_again_lz4_s2_emit_copy_short_2b:
+ MOVL R10, R8
+ LEAL -4(R10), R10
+ CMPL R8, $0x08
+ JBE repeat_two_lz4_s2_emit_copy_short_2b
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_lz4_s2_emit_copy_short_2b
+ CMPL R9, $0x00000800
+ JB repeat_two_offset_lz4_s2_emit_copy_short_2b
+
+cant_repeat_two_offset_lz4_s2_emit_copy_short_2b:
+ CMPL R10, $0x00000104
+ JB repeat_three_lz4_s2_emit_copy_short_2b
+ CMPL R10, $0x00010100
+ JB repeat_four_lz4_s2_emit_copy_short_2b
+ CMPL R10, $0x0100ffff
+ JB repeat_five_lz4_s2_emit_copy_short_2b
+ LEAL -16842747(R10), R10
+ MOVL $0xfffb001d, (AX)
+ MOVB $0xff, 4(AX)
+ ADDQ $0x05, AX
+ JMP emit_repeat_again_lz4_s2_emit_copy_short_2b
+
+repeat_five_lz4_s2_emit_copy_short_2b:
+ LEAL -65536(R10), R10
+ MOVL R10, R9
+ MOVW $0x001d, (AX)
+ MOVW R10, 2(AX)
+ SARL $0x10, R9
+ MOVB R9, 4(AX)
+ ADDQ $0x05, AX
+ JMP lz4s_s2_loop
+
+repeat_four_lz4_s2_emit_copy_short_2b:
+ LEAL -256(R10), R10
+ MOVW $0x0019, (AX)
+ MOVW R10, 2(AX)
+ ADDQ $0x04, AX
+ JMP lz4s_s2_loop
+
+repeat_three_lz4_s2_emit_copy_short_2b:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (AX)
+ MOVB R10, 2(AX)
+ ADDQ $0x03, AX
+ JMP lz4s_s2_loop
+
+repeat_two_lz4_s2_emit_copy_short_2b:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (AX)
+ ADDQ $0x02, AX
+ JMP lz4s_s2_loop
+
+repeat_two_offset_lz4_s2_emit_copy_short_2b:
+ XORQ R8, R8
+ LEAL 1(R8)(R10*4), R10
+ MOVB R9, 1(AX)
+ SARL $0x08, R9
+ SHLL $0x05, R9
+ ORL R9, R10
+ MOVB R10, (AX)
+ ADDQ $0x02, AX
+ JMP lz4s_s2_loop
+
+long_offset_short_lz4_s2:
+ MOVB $0xee, (AX)
+ MOVW R9, 1(AX)
+ LEAL -60(R10), R10
+ ADDQ $0x03, AX
+
+ // emitRepeat
+emit_repeat_again_lz4_s2_emit_copy_short:
+ MOVL R10, R8
+ LEAL -4(R10), R10
+ CMPL R8, $0x08
+ JBE repeat_two_lz4_s2_emit_copy_short
+ CMPL R8, $0x0c
+ JAE cant_repeat_two_offset_lz4_s2_emit_copy_short
+ CMPL R9, $0x00000800
+ JB repeat_two_offset_lz4_s2_emit_copy_short
+
+cant_repeat_two_offset_lz4_s2_emit_copy_short:
+ CMPL R10, $0x00000104
+ JB repeat_three_lz4_s2_emit_copy_short
+ CMPL R10, $0x00010100
+ JB repeat_four_lz4_s2_emit_copy_short
+ CMPL R10, $0x0100ffff
+ JB repeat_five_lz4_s2_emit_copy_short
+ LEAL -16842747(R10), R10
+ MOVL $0xfffb001d, (AX)
+ MOVB $0xff, 4(AX)
+ ADDQ $0x05, AX
+ JMP emit_repeat_again_lz4_s2_emit_copy_short
+
+repeat_five_lz4_s2_emit_copy_short:
+ LEAL -65536(R10), R10
+ MOVL R10, R9
+ MOVW $0x001d, (AX)
+ MOVW R10, 2(AX)
+ SARL $0x10, R9
+ MOVB R9, 4(AX)
+ ADDQ $0x05, AX
+ JMP lz4s_s2_loop
+
+repeat_four_lz4_s2_emit_copy_short:
+ LEAL -256(R10), R10
+ MOVW $0x0019, (AX)
+ MOVW R10, 2(AX)
+ ADDQ $0x04, AX
+ JMP lz4s_s2_loop
+
+repeat_three_lz4_s2_emit_copy_short:
+ LEAL -4(R10), R10
+ MOVW $0x0015, (AX)
+ MOVB R10, 2(AX)
+ ADDQ $0x03, AX
+ JMP lz4s_s2_loop
+
+repeat_two_lz4_s2_emit_copy_short:
+ SHLL $0x02, R10
+ ORL $0x01, R10
+ MOVW R10, (AX)
+ ADDQ $0x02, AX
+ JMP lz4s_s2_loop
+
+repeat_two_offset_lz4_s2_emit_copy_short:
+ XORQ R8, R8
+ LEAL 1(R8)(R10*4), R10
+ MOVB R9, 1(AX)
+ SARL $0x08, R9
+ SHLL $0x05, R9
+ ORL R9, R10
+ MOVB R10, (AX)
+ ADDQ $0x02, AX
+ JMP lz4s_s2_loop
+
+two_byte_offset_short_lz4_s2:
+ MOVL R10, R8
+ SHLL $0x02, R8
+ CMPL R10, $0x0c
+ JAE emit_copy_three_lz4_s2
+ CMPL R9, $0x00000800
+ JAE emit_copy_three_lz4_s2
+ LEAL -15(R8), R8
+ MOVB R9, 1(AX)
+ SHRL $0x08, R9
+ SHLL $0x05, R9
+ ORL R9, R8
+ MOVB R8, (AX)
+ ADDQ $0x02, AX
+ JMP lz4s_s2_loop
+
+emit_copy_three_lz4_s2:
+ LEAL -2(R8), R8
+ MOVB R8, (AX)
+ MOVW R9, 1(AX)
+ ADDQ $0x03, AX
+ JMP lz4s_s2_loop
+
+lz4s_s2_done:
+ MOVQ dst_base+0(FP), CX
+ SUBQ CX, AX
+ MOVQ SI, uncompressed+48(FP)
+ MOVQ AX, dstUsed+56(FP)
+ RET
+
+lz4s_s2_corrupt:
+ XORQ AX, AX
+ LEAQ -1(AX), SI
+ MOVQ SI, uncompressed+48(FP)
+ RET
+
+lz4s_s2_dstfull:
+ XORQ AX, AX
+ LEAQ -2(AX), SI
+ MOVQ SI, uncompressed+48(FP)
+ RET
+
+// func cvtLZ4BlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
+// Requires: SSE2
+TEXT ·cvtLZ4BlockSnappyAsm(SB), NOSPLIT, $0-64
+ XORQ SI, SI
+ MOVQ dst_base+0(FP), AX
+ MOVQ dst_len+8(FP), CX
+ MOVQ src_base+24(FP), DX
+ MOVQ src_len+32(FP), BX
+ LEAQ (DX)(BX*1), BX
+ LEAQ -8(AX)(CX*1), CX
+
+lz4_snappy_loop:
+ CMPQ DX, BX
+ JAE lz4_snappy_corrupt
+ CMPQ AX, CX
+ JAE lz4_snappy_dstfull
+ MOVBQZX (DX), DI
+ MOVQ DI, R8
+ MOVQ DI, R9
+ SHRQ $0x04, R8
+ ANDQ $0x0f, R9
+ CMPQ DI, $0xf0
+ JB lz4_snappy_ll_end
+
+lz4_snappy_ll_loop:
+ INCQ DX
+ CMPQ DX, BX
+ JAE lz4_snappy_corrupt
+ MOVBQZX (DX), DI
+ ADDQ DI, R8
+ CMPQ DI, $0xff
+ JEQ lz4_snappy_ll_loop
+
+lz4_snappy_ll_end:
+ LEAQ (DX)(R8*1), DI
+ ADDQ $0x04, R9
+ CMPQ DI, BX
+ JAE lz4_snappy_corrupt
+ INCQ DX
+ INCQ DI
+ TESTQ R8, R8
+ JZ lz4_snappy_lits_done
+ LEAQ (AX)(R8*1), R10
+ CMPQ R10, CX
+ JAE lz4_snappy_dstfull
+ ADDQ R8, SI
+ LEAL -1(R8), R10
+ CMPL R10, $0x3c
+ JB one_byte_lz4_snappy
+ CMPL R10, $0x00000100
+ JB two_bytes_lz4_snappy
+ CMPL R10, $0x00010000
+ JB three_bytes_lz4_snappy
+ CMPL R10, $0x01000000
+ JB four_bytes_lz4_snappy
+ MOVB $0xfc, (AX)
+ MOVL R10, 1(AX)
+ ADDQ $0x05, AX
+ JMP memmove_long_lz4_snappy
+
+four_bytes_lz4_snappy:
+ MOVL R10, R11
+ SHRL $0x10, R11
+ MOVB $0xf8, (AX)
+ MOVW R10, 1(AX)
+ MOVB R11, 3(AX)
+ ADDQ $0x04, AX
+ JMP memmove_long_lz4_snappy
+
+three_bytes_lz4_snappy:
+ MOVB $0xf4, (AX)
+ MOVW R10, 1(AX)
+ ADDQ $0x03, AX
+ JMP memmove_long_lz4_snappy
+
+two_bytes_lz4_snappy:
+ MOVB $0xf0, (AX)
+ MOVB R10, 1(AX)
+ ADDQ $0x02, AX
+ CMPL R10, $0x40
+ JB memmove_lz4_snappy
+ JMP memmove_long_lz4_snappy
+
+one_byte_lz4_snappy:
+ SHLB $0x02, R10
+ MOVB R10, (AX)
+ ADDQ $0x01, AX
+
+memmove_lz4_snappy:
+ LEAQ (AX)(R8*1), R10
+
+ // genMemMoveShort
+ CMPQ R8, $0x08
+ JBE emit_lit_memmove_lz4_snappy_memmove_move_8
+ CMPQ R8, $0x10
+ JBE emit_lit_memmove_lz4_snappy_memmove_move_8through16
+ CMPQ R8, $0x20
+ JBE emit_lit_memmove_lz4_snappy_memmove_move_17through32
+ JMP emit_lit_memmove_lz4_snappy_memmove_move_33through64
+
+emit_lit_memmove_lz4_snappy_memmove_move_8:
+ MOVQ (DX), R11
+ MOVQ R11, (AX)
+ JMP memmove_end_copy_lz4_snappy
+
+emit_lit_memmove_lz4_snappy_memmove_move_8through16:
+ MOVQ (DX), R11
+ MOVQ -8(DX)(R8*1), DX
+ MOVQ R11, (AX)
+ MOVQ DX, -8(AX)(R8*1)
+ JMP memmove_end_copy_lz4_snappy
+
+emit_lit_memmove_lz4_snappy_memmove_move_17through32:
+ MOVOU (DX), X0
+ MOVOU -16(DX)(R8*1), X1
+ MOVOU X0, (AX)
+ MOVOU X1, -16(AX)(R8*1)
+ JMP memmove_end_copy_lz4_snappy
+
+emit_lit_memmove_lz4_snappy_memmove_move_33through64:
+ MOVOU (DX), X0
+ MOVOU 16(DX), X1
+ MOVOU -32(DX)(R8*1), X2
+ MOVOU -16(DX)(R8*1), X3
+ MOVOU X0, (AX)
+ MOVOU X1, 16(AX)
+ MOVOU X2, -32(AX)(R8*1)
+ MOVOU X3, -16(AX)(R8*1)
+
+memmove_end_copy_lz4_snappy:
+ MOVQ R10, AX
+ JMP lz4_snappy_lits_emit_done
+
+memmove_long_lz4_snappy:
+ LEAQ (AX)(R8*1), R10
+
+ // genMemMoveLong
+ MOVOU (DX), X0
+ MOVOU 16(DX), X1
+ MOVOU -32(DX)(R8*1), X2
+ MOVOU -16(DX)(R8*1), X3
+ MOVQ R8, R12
+ SHRQ $0x05, R12
+ MOVQ AX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R13
+ SUBQ R11, R13
+ DECQ R12
+ JA emit_lit_memmove_long_lz4_snappylarge_forward_sse_loop_32
+ LEAQ -32(DX)(R13*1), R11
+ LEAQ -32(AX)(R13*1), R14
+
+emit_lit_memmove_long_lz4_snappylarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R14)
+ MOVOA X5, 16(R14)
+ ADDQ $0x20, R14
+ ADDQ $0x20, R11
+ ADDQ $0x20, R13
+ DECQ R12
+ JNA emit_lit_memmove_long_lz4_snappylarge_big_loop_back
+
+emit_lit_memmove_long_lz4_snappylarge_forward_sse_loop_32:
+ MOVOU -32(DX)(R13*1), X4
+ MOVOU -16(DX)(R13*1), X5
+ MOVOA X4, -32(AX)(R13*1)
+ MOVOA X5, -16(AX)(R13*1)
+ ADDQ $0x20, R13
+ CMPQ R8, R13
+ JAE emit_lit_memmove_long_lz4_snappylarge_forward_sse_loop_32
+ MOVOU X0, (AX)
+ MOVOU X1, 16(AX)
+ MOVOU X2, -32(AX)(R8*1)
+ MOVOU X3, -16(AX)(R8*1)
+ MOVQ R10, AX
+
+lz4_snappy_lits_emit_done:
+ MOVQ DI, DX
+
+lz4_snappy_lits_done:
+ CMPQ DX, BX
+ JNE lz4_snappy_match
+ CMPQ R9, $0x04
+ JEQ lz4_snappy_done
+ JMP lz4_snappy_corrupt
+
+lz4_snappy_match:
+ LEAQ 2(DX), DI
+ CMPQ DI, BX
+ JAE lz4_snappy_corrupt
+ MOVWQZX (DX), R8
+ MOVQ DI, DX
+ TESTQ R8, R8
+ JZ lz4_snappy_corrupt
+ CMPQ R8, SI
+ JA lz4_snappy_corrupt
+ CMPQ R9, $0x13
+ JNE lz4_snappy_ml_done
+
+lz4_snappy_ml_loop:
+ MOVBQZX (DX), DI
+ INCQ DX
+ ADDQ DI, R9
+ CMPQ DX, BX
+ JAE lz4_snappy_corrupt
+ CMPQ DI, $0xff
+ JEQ lz4_snappy_ml_loop
+
+lz4_snappy_ml_done:
+ ADDQ R9, SI
+
+ // emitCopy
+two_byte_offset_lz4_s2:
+ CMPL R9, $0x40
+ JBE two_byte_offset_short_lz4_s2
+ MOVB $0xee, (AX)
+ MOVW R8, 1(AX)
+ LEAL -60(R9), R9
+ ADDQ $0x03, AX
+ CMPQ AX, CX
+ JAE lz4_snappy_loop
+ JMP two_byte_offset_lz4_s2
+
+two_byte_offset_short_lz4_s2:
+ MOVL R9, DI
+ SHLL $0x02, DI
+ CMPL R9, $0x0c
+ JAE emit_copy_three_lz4_s2
+ CMPL R8, $0x00000800
+ JAE emit_copy_three_lz4_s2
+ LEAL -15(DI), DI
+ MOVB R8, 1(AX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, DI
+ MOVB DI, (AX)
+ ADDQ $0x02, AX
+ JMP lz4_snappy_loop
+
+emit_copy_three_lz4_s2:
+ LEAL -2(DI), DI
+ MOVB DI, (AX)
+ MOVW R8, 1(AX)
+ ADDQ $0x03, AX
+ JMP lz4_snappy_loop
+
+lz4_snappy_done:
+ MOVQ dst_base+0(FP), CX
+ SUBQ CX, AX
+ MOVQ SI, uncompressed+48(FP)
+ MOVQ AX, dstUsed+56(FP)
+ RET
+
+lz4_snappy_corrupt:
+ XORQ AX, AX
+ LEAQ -1(AX), SI
+ MOVQ SI, uncompressed+48(FP)
+ RET
+
+lz4_snappy_dstfull:
+ XORQ AX, AX
+ LEAQ -2(AX), SI
+ MOVQ SI, uncompressed+48(FP)
+ RET
+
+// func cvtLZ4sBlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
+// Requires: SSE2
+TEXT ·cvtLZ4sBlockSnappyAsm(SB), NOSPLIT, $0-64
+ XORQ SI, SI
+ MOVQ dst_base+0(FP), AX
+ MOVQ dst_len+8(FP), CX
+ MOVQ src_base+24(FP), DX
+ MOVQ src_len+32(FP), BX
+ LEAQ (DX)(BX*1), BX
+ LEAQ -8(AX)(CX*1), CX
+
+lz4s_snappy_loop:
+ CMPQ DX, BX
+ JAE lz4s_snappy_corrupt
+ CMPQ AX, CX
+ JAE lz4s_snappy_dstfull
+ MOVBQZX (DX), DI
+ MOVQ DI, R8
+ MOVQ DI, R9
+ SHRQ $0x04, R8
+ ANDQ $0x0f, R9
+ CMPQ DI, $0xf0
+ JB lz4s_snappy_ll_end
+
+lz4s_snappy_ll_loop:
+ INCQ DX
+ CMPQ DX, BX
+ JAE lz4s_snappy_corrupt
+ MOVBQZX (DX), DI
+ ADDQ DI, R8
+ CMPQ DI, $0xff
+ JEQ lz4s_snappy_ll_loop
+
+lz4s_snappy_ll_end:
+ LEAQ (DX)(R8*1), DI
+ ADDQ $0x03, R9
+ CMPQ DI, BX
+ JAE lz4s_snappy_corrupt
+ INCQ DX
+ INCQ DI
+ TESTQ R8, R8
+ JZ lz4s_snappy_lits_done
+ LEAQ (AX)(R8*1), R10
+ CMPQ R10, CX
+ JAE lz4s_snappy_dstfull
+ ADDQ R8, SI
+ LEAL -1(R8), R10
+ CMPL R10, $0x3c
+ JB one_byte_lz4s_snappy
+ CMPL R10, $0x00000100
+ JB two_bytes_lz4s_snappy
+ CMPL R10, $0x00010000
+ JB three_bytes_lz4s_snappy
+ CMPL R10, $0x01000000
+ JB four_bytes_lz4s_snappy
+ MOVB $0xfc, (AX)
+ MOVL R10, 1(AX)
+ ADDQ $0x05, AX
+ JMP memmove_long_lz4s_snappy
+
+four_bytes_lz4s_snappy:
+ MOVL R10, R11
+ SHRL $0x10, R11
+ MOVB $0xf8, (AX)
+ MOVW R10, 1(AX)
+ MOVB R11, 3(AX)
+ ADDQ $0x04, AX
+ JMP memmove_long_lz4s_snappy
+
+three_bytes_lz4s_snappy:
+ MOVB $0xf4, (AX)
+ MOVW R10, 1(AX)
+ ADDQ $0x03, AX
+ JMP memmove_long_lz4s_snappy
+
+two_bytes_lz4s_snappy:
+ MOVB $0xf0, (AX)
+ MOVB R10, 1(AX)
+ ADDQ $0x02, AX
+ CMPL R10, $0x40
+ JB memmove_lz4s_snappy
+ JMP memmove_long_lz4s_snappy
+
+one_byte_lz4s_snappy:
+ SHLB $0x02, R10
+ MOVB R10, (AX)
+ ADDQ $0x01, AX
+
+memmove_lz4s_snappy:
+ LEAQ (AX)(R8*1), R10
+
+ // genMemMoveShort
+ CMPQ R8, $0x08
+ JBE emit_lit_memmove_lz4s_snappy_memmove_move_8
+ CMPQ R8, $0x10
+ JBE emit_lit_memmove_lz4s_snappy_memmove_move_8through16
+ CMPQ R8, $0x20
+ JBE emit_lit_memmove_lz4s_snappy_memmove_move_17through32
+ JMP emit_lit_memmove_lz4s_snappy_memmove_move_33through64
+
+emit_lit_memmove_lz4s_snappy_memmove_move_8:
+ MOVQ (DX), R11
+ MOVQ R11, (AX)
+ JMP memmove_end_copy_lz4s_snappy
+
+emit_lit_memmove_lz4s_snappy_memmove_move_8through16:
+ MOVQ (DX), R11
+ MOVQ -8(DX)(R8*1), DX
+ MOVQ R11, (AX)
+ MOVQ DX, -8(AX)(R8*1)
+ JMP memmove_end_copy_lz4s_snappy
+
+emit_lit_memmove_lz4s_snappy_memmove_move_17through32:
+ MOVOU (DX), X0
+ MOVOU -16(DX)(R8*1), X1
+ MOVOU X0, (AX)
+ MOVOU X1, -16(AX)(R8*1)
+ JMP memmove_end_copy_lz4s_snappy
+
+emit_lit_memmove_lz4s_snappy_memmove_move_33through64:
+ MOVOU (DX), X0
+ MOVOU 16(DX), X1
+ MOVOU -32(DX)(R8*1), X2
+ MOVOU -16(DX)(R8*1), X3
+ MOVOU X0, (AX)
+ MOVOU X1, 16(AX)
+ MOVOU X2, -32(AX)(R8*1)
+ MOVOU X3, -16(AX)(R8*1)
+
+memmove_end_copy_lz4s_snappy:
+ MOVQ R10, AX
+ JMP lz4s_snappy_lits_emit_done
+
+memmove_long_lz4s_snappy:
+ LEAQ (AX)(R8*1), R10
+
+ // genMemMoveLong
+ MOVOU (DX), X0
+ MOVOU 16(DX), X1
+ MOVOU -32(DX)(R8*1), X2
+ MOVOU -16(DX)(R8*1), X3
+ MOVQ R8, R12
+ SHRQ $0x05, R12
+ MOVQ AX, R11
+ ANDL $0x0000001f, R11
+ MOVQ $0x00000040, R13
+ SUBQ R11, R13
+ DECQ R12
+ JA emit_lit_memmove_long_lz4s_snappylarge_forward_sse_loop_32
+ LEAQ -32(DX)(R13*1), R11
+ LEAQ -32(AX)(R13*1), R14
+
+emit_lit_memmove_long_lz4s_snappylarge_big_loop_back:
+ MOVOU (R11), X4
+ MOVOU 16(R11), X5
+ MOVOA X4, (R14)
+ MOVOA X5, 16(R14)
+ ADDQ $0x20, R14
+ ADDQ $0x20, R11
+ ADDQ $0x20, R13
+ DECQ R12
+ JNA emit_lit_memmove_long_lz4s_snappylarge_big_loop_back
+
+emit_lit_memmove_long_lz4s_snappylarge_forward_sse_loop_32:
+ MOVOU -32(DX)(R13*1), X4
+ MOVOU -16(DX)(R13*1), X5
+ MOVOA X4, -32(AX)(R13*1)
+ MOVOA X5, -16(AX)(R13*1)
+ ADDQ $0x20, R13
+ CMPQ R8, R13
+ JAE emit_lit_memmove_long_lz4s_snappylarge_forward_sse_loop_32
+ MOVOU X0, (AX)
+ MOVOU X1, 16(AX)
+ MOVOU X2, -32(AX)(R8*1)
+ MOVOU X3, -16(AX)(R8*1)
+ MOVQ R10, AX
+
+lz4s_snappy_lits_emit_done:
+ MOVQ DI, DX
+
+lz4s_snappy_lits_done:
+ CMPQ DX, BX
+ JNE lz4s_snappy_match
+ CMPQ R9, $0x03
+ JEQ lz4s_snappy_done
+ JMP lz4s_snappy_corrupt
+
+lz4s_snappy_match:
+ CMPQ R9, $0x03
+ JEQ lz4s_snappy_loop
+ LEAQ 2(DX), DI
+ CMPQ DI, BX
+ JAE lz4s_snappy_corrupt
+ MOVWQZX (DX), R8
+ MOVQ DI, DX
+ TESTQ R8, R8
+ JZ lz4s_snappy_corrupt
+ CMPQ R8, SI
+ JA lz4s_snappy_corrupt
+ CMPQ R9, $0x12
+ JNE lz4s_snappy_ml_done
+
+lz4s_snappy_ml_loop:
+ MOVBQZX (DX), DI
+ INCQ DX
+ ADDQ DI, R9
+ CMPQ DX, BX
+ JAE lz4s_snappy_corrupt
+ CMPQ DI, $0xff
+ JEQ lz4s_snappy_ml_loop
+
+lz4s_snappy_ml_done:
+ ADDQ R9, SI
+
+ // emitCopy
+two_byte_offset_lz4_s2:
+ CMPL R9, $0x40
+ JBE two_byte_offset_short_lz4_s2
+ MOVB $0xee, (AX)
+ MOVW R8, 1(AX)
+ LEAL -60(R9), R9
+ ADDQ $0x03, AX
+ CMPQ AX, CX
+ JAE lz4s_snappy_loop
+ JMP two_byte_offset_lz4_s2
+
+two_byte_offset_short_lz4_s2:
+ MOVL R9, DI
+ SHLL $0x02, DI
+ CMPL R9, $0x0c
+ JAE emit_copy_three_lz4_s2
+ CMPL R8, $0x00000800
+ JAE emit_copy_three_lz4_s2
+ LEAL -15(DI), DI
+ MOVB R8, 1(AX)
+ SHRL $0x08, R8
+ SHLL $0x05, R8
+ ORL R8, DI
+ MOVB DI, (AX)
+ ADDQ $0x02, AX
+ JMP lz4s_snappy_loop
+
+emit_copy_three_lz4_s2:
+ LEAL -2(DI), DI
+ MOVB DI, (AX)
+ MOVW R8, 1(AX)
+ ADDQ $0x03, AX
+ JMP lz4s_snappy_loop
+
+lz4s_snappy_done:
+ MOVQ dst_base+0(FP), CX
+ SUBQ CX, AX
+ MOVQ SI, uncompressed+48(FP)
+ MOVQ AX, dstUsed+56(FP)
+ RET
+
+lz4s_snappy_corrupt:
+ XORQ AX, AX
+ LEAQ -1(AX), SI
+ MOVQ SI, uncompressed+48(FP)
+ RET
+
+lz4s_snappy_dstfull:
+ XORQ AX, AX
+ LEAQ -2(AX), SI
+ MOVQ SI, uncompressed+48(FP)
+ RET
diff --git a/vendor/github.com/klauspost/compress/s2/hashtable_pool.go b/vendor/github.com/klauspost/compress/s2/hashtable_pool.go
new file mode 100644
index 00000000000..bc7cabd5c5c
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/hashtable_pool.go
@@ -0,0 +1,65 @@
+package s2
+
+import "sync"
+
+// Table size constants
+const (
+ betterLongTableBits = 17
+ betterLongTableSize = 1 << betterLongTableBits // 131072
+
+ betterShortTableBits = 14
+ betterShortTableSize = 1 << betterShortTableBits // 16384
+
+ betterSnappyLongTableBits = 16
+ betterSnappyLongTableSize = 1 << betterSnappyLongTableBits // 65536
+
+ bestLongTableBits = 19
+ bestLongTableSize = 1 << bestLongTableBits // 524288
+
+ bestShortTableBits = 16
+ bestShortTableSize = 1 << bestShortTableBits // 65536
+)
+
+type betterTables struct {
+ lTable [betterLongTableSize]uint32
+ sTable [betterShortTableSize]uint32
+}
+
+var betterTablePool = sync.Pool{New: func() interface{} { return &betterTables{} }}
+
+// betterSnappyTables holds better-snappy compression hash tables.
+type betterSnappyTables struct {
+ lTable [betterSnappyLongTableSize]uint32
+ sTable [betterShortTableSize]uint32
+}
+
+var betterSnappyTablePool = sync.Pool{New: func() interface{} { return &betterSnappyTables{} }}
+
+// bestTables holds best compression hash tables.
+type bestTables struct {
+ lTable [bestLongTableSize]uint64
+ sTable [bestShortTableSize]uint64
+}
+
+var bestTablePool = sync.Pool{New: func() interface{} { return &bestTables{} }}
+
+// getBetterTables gets a zeroed betterTables from the pool.
+func getBetterTables() *betterTables {
+ t := betterTablePool.Get().(*betterTables)
+ *t = betterTables{}
+ return t
+}
+
+// getBetterSnappyTables gets a zeroed betterSnappyTables from the pool.
+func getBetterSnappyTables() *betterSnappyTables {
+ t := betterSnappyTablePool.Get().(*betterSnappyTables)
+ *t = betterSnappyTables{}
+ return t
+}
+
+// getBestTables gets a zeroed bestTables from the pool.
+func getBestTables() *bestTables {
+ t := bestTablePool.Get().(*bestTables)
+ *t = bestTables{}
+ return t
+}
diff --git a/vendor/github.com/klauspost/compress/s2/index.go b/vendor/github.com/klauspost/compress/s2/index.go
new file mode 100644
index 00000000000..fb7db25315a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/index.go
@@ -0,0 +1,602 @@
+// Copyright (c) 2022+ Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+ "fmt"
+ "io"
+ "sort"
+)
+
+const (
+ S2IndexHeader = "s2idx\x00"
+ S2IndexTrailer = "\x00xdi2s"
+ maxIndexEntries = 1 << 16
+ // If distance is less than this, we do not add the entry.
+ minIndexDist = 1 << 20
+)
+
+// Index represents an S2/Snappy index.
+type Index struct {
+ TotalUncompressed int64 // Total Uncompressed size if known. Will be -1 if unknown.
+ TotalCompressed int64 // Total Compressed size if known. Will be -1 if unknown.
+ info []struct {
+ compressedOffset int64
+ uncompressedOffset int64
+ }
+ estBlockUncomp int64
+}
+
+func (i *Index) reset(maxBlock int) {
+ i.estBlockUncomp = int64(maxBlock)
+ i.TotalCompressed = -1
+ i.TotalUncompressed = -1
+ if len(i.info) > 0 {
+ i.info = i.info[:0]
+ }
+}
+
+// allocInfos will allocate an empty slice of infos.
+func (i *Index) allocInfos(n int) {
+ if n > maxIndexEntries {
+ panic("n > maxIndexEntries")
+ }
+ i.info = make([]struct {
+ compressedOffset int64
+ uncompressedOffset int64
+ }, 0, n)
+}
+
+// add an uncompressed and compressed pair.
+// Entries must be sent in order.
+func (i *Index) add(compressedOffset, uncompressedOffset int64) error {
+ if i == nil {
+ return nil
+ }
+ lastIdx := len(i.info) - 1
+ if lastIdx >= 0 {
+ latest := i.info[lastIdx]
+ if latest.uncompressedOffset == uncompressedOffset {
+ // Uncompressed didn't change, don't add entry,
+ // but update start index.
+ latest.compressedOffset = compressedOffset
+ i.info[lastIdx] = latest
+ return nil
+ }
+ if latest.uncompressedOffset > uncompressedOffset {
+ return fmt.Errorf("internal error: Earlier uncompressed received (%d > %d)", latest.uncompressedOffset, uncompressedOffset)
+ }
+ if latest.compressedOffset > compressedOffset {
+ return fmt.Errorf("internal error: Earlier compressed received (%d > %d)", latest.compressedOffset, compressedOffset)
+ }
+ if latest.uncompressedOffset+minIndexDist > uncompressedOffset {
+ // Only add entry if distance is large enough.
+ return nil
+ }
+ }
+ i.info = append(i.info, struct {
+ compressedOffset int64
+ uncompressedOffset int64
+ }{compressedOffset: compressedOffset, uncompressedOffset: uncompressedOffset})
+ return nil
+}
+
+// Find the offset at or before the wanted (uncompressed) offset.
+// If offset is 0 or positive it is the offset from the beginning of the file.
+// If the uncompressed size is known, the offset must be within the file.
+// If an offset outside the file is requested io.ErrUnexpectedEOF is returned.
+// If the offset is negative, it is interpreted as the distance from the end of the file,
+// where -1 represents the last byte.
+// If offset from the end of the file is requested, but size is unknown,
+// ErrUnsupported will be returned.
+func (i *Index) Find(offset int64) (compressedOff, uncompressedOff int64, err error) {
+ if i.TotalUncompressed < 0 {
+ return 0, 0, ErrCorrupt
+ }
+ if offset < 0 {
+ offset = i.TotalUncompressed + offset
+ if offset < 0 {
+ return 0, 0, io.ErrUnexpectedEOF
+ }
+ }
+ if offset > i.TotalUncompressed {
+ return 0, 0, io.ErrUnexpectedEOF
+ }
+ if len(i.info) > 200 {
+ n := sort.Search(len(i.info), func(n int) bool {
+ return i.info[n].uncompressedOffset > offset
+ })
+ if n == 0 {
+ n = 1
+ }
+ return i.info[n-1].compressedOffset, i.info[n-1].uncompressedOffset, nil
+ }
+ for _, info := range i.info {
+ if info.uncompressedOffset > offset {
+ break
+ }
+ compressedOff = info.compressedOffset
+ uncompressedOff = info.uncompressedOffset
+ }
+ return compressedOff, uncompressedOff, nil
+}
+
+// reduce to stay below maxIndexEntries
+func (i *Index) reduce() {
+ if len(i.info) < maxIndexEntries && i.estBlockUncomp >= minIndexDist {
+ return
+ }
+
+ // Algorithm, keep 1, remove removeN entries...
+ removeN := (len(i.info) + 1) / maxIndexEntries
+ src := i.info
+ j := 0
+
+ // Each block should be at least 1MB, but don't reduce below 1000 entries.
+ for i.estBlockUncomp*(int64(removeN)+1) < minIndexDist && len(i.info)/(removeN+1) > 1000 {
+ removeN++
+ }
+ for idx := 0; idx < len(src); idx++ {
+ i.info[j] = src[idx]
+ j++
+ idx += removeN
+ }
+ i.info = i.info[:j]
+ // Update maxblock estimate.
+ i.estBlockUncomp += i.estBlockUncomp * int64(removeN)
+}
+
+func (i *Index) appendTo(b []byte, uncompTotal, compTotal int64) []byte {
+ i.reduce()
+ var tmp [binary.MaxVarintLen64]byte
+
+ initSize := len(b)
+ // We make the start a skippable header+size.
+ b = append(b, ChunkTypeIndex, 0, 0, 0)
+ b = append(b, []byte(S2IndexHeader)...)
+ // Total Uncompressed size
+ n := binary.PutVarint(tmp[:], uncompTotal)
+ b = append(b, tmp[:n]...)
+ // Total Compressed size
+ n = binary.PutVarint(tmp[:], compTotal)
+ b = append(b, tmp[:n]...)
+ // Put EstBlockUncomp size
+ n = binary.PutVarint(tmp[:], i.estBlockUncomp)
+ b = append(b, tmp[:n]...)
+ // Put length
+ n = binary.PutVarint(tmp[:], int64(len(i.info)))
+ b = append(b, tmp[:n]...)
+
+ // Check if we should add uncompressed offsets
+ var hasUncompressed byte
+ for idx, info := range i.info {
+ if idx == 0 {
+ if info.uncompressedOffset != 0 {
+ hasUncompressed = 1
+ break
+ }
+ continue
+ }
+ if info.uncompressedOffset != i.info[idx-1].uncompressedOffset+i.estBlockUncomp {
+ hasUncompressed = 1
+ break
+ }
+ }
+ b = append(b, hasUncompressed)
+
+ // Add each entry
+ if hasUncompressed == 1 {
+ for idx, info := range i.info {
+ uOff := info.uncompressedOffset
+ if idx > 0 {
+ prev := i.info[idx-1]
+ uOff -= prev.uncompressedOffset + (i.estBlockUncomp)
+ }
+ n = binary.PutVarint(tmp[:], uOff)
+ b = append(b, tmp[:n]...)
+ }
+ }
+
+ // Initial compressed size estimate.
+ cPredict := i.estBlockUncomp / 2
+
+ for idx, info := range i.info {
+ cOff := info.compressedOffset
+ if idx > 0 {
+ prev := i.info[idx-1]
+ cOff -= prev.compressedOffset + cPredict
+ // Update compressed size prediction, with half the error.
+ cPredict += cOff / 2
+ }
+ n = binary.PutVarint(tmp[:], cOff)
+ b = append(b, tmp[:n]...)
+ }
+
+ // Add Total Size.
+ // Stored as fixed size for easier reading.
+ binary.LittleEndian.PutUint32(tmp[:], uint32(len(b)-initSize+4+len(S2IndexTrailer)))
+ b = append(b, tmp[:4]...)
+ // Trailer
+ b = append(b, []byte(S2IndexTrailer)...)
+
+ // Update size
+ chunkLen := len(b) - initSize - skippableFrameHeader
+ b[initSize+1] = uint8(chunkLen >> 0)
+ b[initSize+2] = uint8(chunkLen >> 8)
+ b[initSize+3] = uint8(chunkLen >> 16)
+ //fmt.Printf("chunklen: 0x%x Uncomp:%d, Comp:%d\n", chunkLen, uncompTotal, compTotal)
+ return b
+}
+
+// Load a binary index.
+// A zero value Index can be used or a previous one can be reused.
+func (i *Index) Load(b []byte) ([]byte, error) {
+ if len(b) <= 4+len(S2IndexHeader)+len(S2IndexTrailer) {
+ return b, io.ErrUnexpectedEOF
+ }
+ if b[0] != ChunkTypeIndex {
+ return b, ErrCorrupt
+ }
+ chunkLen := int(b[1]) | int(b[2])<<8 | int(b[3])<<16
+ b = b[4:]
+
+ // Validate we have enough...
+ if len(b) < chunkLen {
+ return b, io.ErrUnexpectedEOF
+ }
+ if !bytes.Equal(b[:len(S2IndexHeader)], []byte(S2IndexHeader)) {
+ return b, ErrUnsupported
+ }
+ b = b[len(S2IndexHeader):]
+
+ // Total Uncompressed
+ if v, n := binary.Varint(b); n <= 0 || v < 0 {
+ return b, ErrCorrupt
+ } else {
+ i.TotalUncompressed = v
+ b = b[n:]
+ }
+
+ // Total Compressed
+ if v, n := binary.Varint(b); n <= 0 {
+ return b, ErrCorrupt
+ } else {
+ i.TotalCompressed = v
+ b = b[n:]
+ }
+
+ // Read EstBlockUncomp
+ if v, n := binary.Varint(b); n <= 0 {
+ return b, ErrCorrupt
+ } else {
+ if v < 0 {
+ return b, ErrCorrupt
+ }
+ i.estBlockUncomp = v
+ b = b[n:]
+ }
+
+ var entries int
+ if v, n := binary.Varint(b); n <= 0 {
+ return b, ErrCorrupt
+ } else {
+ if v < 0 || v > maxIndexEntries {
+ return b, ErrCorrupt
+ }
+ entries = int(v)
+ b = b[n:]
+ }
+ if cap(i.info) < entries {
+ i.allocInfos(entries)
+ }
+ i.info = i.info[:entries]
+
+ if len(b) < 1 {
+ return b, io.ErrUnexpectedEOF
+ }
+ hasUncompressed := b[0]
+ b = b[1:]
+ if hasUncompressed&1 != hasUncompressed {
+ return b, ErrCorrupt
+ }
+
+ // Add each uncompressed entry
+ for idx := range i.info {
+ var uOff int64
+ if hasUncompressed != 0 {
+ // Load delta
+ if v, n := binary.Varint(b); n <= 0 {
+ return b, ErrCorrupt
+ } else {
+ uOff = v
+ b = b[n:]
+ }
+ }
+
+ if idx > 0 {
+ prev := i.info[idx-1].uncompressedOffset
+ uOff += prev + (i.estBlockUncomp)
+ if uOff <= prev {
+ return b, ErrCorrupt
+ }
+ }
+ if uOff < 0 {
+ return b, ErrCorrupt
+ }
+ i.info[idx].uncompressedOffset = uOff
+ }
+
+ // Initial compressed size estimate.
+ cPredict := i.estBlockUncomp / 2
+
+ // Add each compressed entry
+ for idx := range i.info {
+ var cOff int64
+ if v, n := binary.Varint(b); n <= 0 {
+ return b, ErrCorrupt
+ } else {
+ cOff = v
+ b = b[n:]
+ }
+
+ if idx > 0 {
+ // Update compressed size prediction, with half the error.
+ cPredictNew := cPredict + cOff/2
+
+ prev := i.info[idx-1].compressedOffset
+ cOff += prev + cPredict
+ if cOff <= prev {
+ return b, ErrCorrupt
+ }
+ cPredict = cPredictNew
+ }
+ if cOff < 0 {
+ return b, ErrCorrupt
+ }
+ i.info[idx].compressedOffset = cOff
+ }
+ if len(b) < 4+len(S2IndexTrailer) {
+ return b, io.ErrUnexpectedEOF
+ }
+ // Skip size...
+ b = b[4:]
+
+ // Check trailer...
+ if !bytes.Equal(b[:len(S2IndexTrailer)], []byte(S2IndexTrailer)) {
+ return b, ErrCorrupt
+ }
+ return b[len(S2IndexTrailer):], nil
+}
+
+// LoadStream will load an index from the end of the supplied stream.
+// ErrUnsupported will be returned if the signature cannot be found.
+// ErrCorrupt will be returned if unexpected values are found.
+// io.ErrUnexpectedEOF is returned if there are too few bytes.
+// IO errors are returned as-is.
+func (i *Index) LoadStream(rs io.ReadSeeker) error {
+ // Go to end.
+ _, err := rs.Seek(-10, io.SeekEnd)
+ if err != nil {
+ return err
+ }
+ var tmp [10]byte
+ _, err = io.ReadFull(rs, tmp[:])
+ if err != nil {
+ return err
+ }
+ // Check trailer...
+ if !bytes.Equal(tmp[4:4+len(S2IndexTrailer)], []byte(S2IndexTrailer)) {
+ return ErrUnsupported
+ }
+ sz := binary.LittleEndian.Uint32(tmp[:4])
+ if sz > maxChunkSize+skippableFrameHeader {
+ return ErrCorrupt
+ }
+ _, err = rs.Seek(-int64(sz), io.SeekEnd)
+ if err != nil {
+ return err
+ }
+
+ // Read index.
+ buf := make([]byte, sz)
+ _, err = io.ReadFull(rs, buf)
+ if err != nil {
+ return err
+ }
+ _, err = i.Load(buf)
+ return err
+}
+
+// IndexStream will return an index for a stream.
+// The stream structure will be checked, but
+// data within blocks is not verified.
+// The returned index can either be appended to the end of the stream
+// or stored separately.
+func IndexStream(r io.Reader) ([]byte, error) {
+ var i Index
+ var buf [maxChunkSize]byte
+ var readHeader bool
+ for {
+ _, err := io.ReadFull(r, buf[:4])
+ if err != nil {
+ if err == io.EOF {
+ return i.appendTo(nil, i.TotalUncompressed, i.TotalCompressed), nil
+ }
+ return nil, err
+ }
+ // Start of this chunk.
+ startChunk := i.TotalCompressed
+ i.TotalCompressed += 4
+
+ chunkType := buf[0]
+ if !readHeader {
+ if chunkType != chunkTypeStreamIdentifier {
+ return nil, ErrCorrupt
+ }
+ readHeader = true
+ }
+ chunkLen := int(buf[1]) | int(buf[2])<<8 | int(buf[3])<<16
+ if chunkLen < checksumSize {
+ return nil, ErrCorrupt
+ }
+
+ i.TotalCompressed += int64(chunkLen)
+ _, err = io.ReadFull(r, buf[:chunkLen])
+ if err != nil {
+ return nil, io.ErrUnexpectedEOF
+ }
+ // The chunk types are specified at
+ // https://github.com/google/snappy/blob/master/framing_format.txt
+ switch chunkType {
+ case chunkTypeCompressedData:
+ // Section 4.2. Compressed data (chunk type 0x00).
+ // Skip checksum.
+ dLen, err := DecodedLen(buf[checksumSize:])
+ if err != nil {
+ return nil, err
+ }
+ if dLen > maxBlockSize {
+ return nil, ErrCorrupt
+ }
+ if i.estBlockUncomp == 0 {
+ // Use first block for estimate...
+ i.estBlockUncomp = int64(dLen)
+ }
+ err = i.add(startChunk, i.TotalUncompressed)
+ if err != nil {
+ return nil, err
+ }
+ i.TotalUncompressed += int64(dLen)
+ continue
+ case chunkTypeUncompressedData:
+ n2 := chunkLen - checksumSize
+ if n2 > maxBlockSize {
+ return nil, ErrCorrupt
+ }
+ if i.estBlockUncomp == 0 {
+ // Use first block for estimate...
+ i.estBlockUncomp = int64(n2)
+ }
+ err = i.add(startChunk, i.TotalUncompressed)
+ if err != nil {
+ return nil, err
+ }
+ i.TotalUncompressed += int64(n2)
+ continue
+ case chunkTypeStreamIdentifier:
+ // Section 4.1. Stream identifier (chunk type 0xff).
+ if chunkLen != len(magicBody) {
+ return nil, ErrCorrupt
+ }
+
+ if string(buf[:len(magicBody)]) != magicBody {
+ if string(buf[:len(magicBody)]) != magicBodySnappy {
+ return nil, ErrCorrupt
+ }
+ }
+
+ continue
+ }
+
+ if chunkType <= 0x7f {
+ // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
+ return nil, ErrUnsupported
+ }
+ if chunkLen > maxChunkSize {
+ return nil, ErrUnsupported
+ }
+ // Section 4.4 Padding (chunk type 0xfe).
+ // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
+ }
+}
+
+// JSON returns the index as JSON text.
+func (i *Index) JSON() []byte {
+ type offset struct {
+ CompressedOffset int64 `json:"compressed"`
+ UncompressedOffset int64 `json:"uncompressed"`
+ }
+ x := struct {
+ TotalUncompressed int64 `json:"total_uncompressed"` // Total Uncompressed size if known. Will be -1 if unknown.
+ TotalCompressed int64 `json:"total_compressed"` // Total Compressed size if known. Will be -1 if unknown.
+ Offsets []offset `json:"offsets"`
+ EstBlockUncomp int64 `json:"est_block_uncompressed"`
+ }{
+ TotalUncompressed: i.TotalUncompressed,
+ TotalCompressed: i.TotalCompressed,
+ EstBlockUncomp: i.estBlockUncomp,
+ }
+ for _, v := range i.info {
+ x.Offsets = append(x.Offsets, offset{CompressedOffset: v.compressedOffset, UncompressedOffset: v.uncompressedOffset})
+ }
+ b, _ := json.MarshalIndent(x, "", " ")
+ return b
+}
+
+// RemoveIndexHeaders will trim all headers and trailers from a given index.
+// This is expected to save 20 bytes.
+// These can be restored using RestoreIndexHeaders.
+// This removes a layer of security, but is the most compact representation.
+// Returns nil if headers contains errors.
+// The returned slice references the provided slice.
+func RemoveIndexHeaders(b []byte) []byte {
+ const save = 4 + len(S2IndexHeader) + len(S2IndexTrailer) + 4
+ if len(b) <= save {
+ return nil
+ }
+ if b[0] != ChunkTypeIndex {
+ return nil
+ }
+ chunkLen := int(b[1]) | int(b[2])<<8 | int(b[3])<<16
+ b = b[4:]
+
+ // Validate we have enough...
+ if len(b) < chunkLen {
+ return nil
+ }
+ b = b[:chunkLen]
+
+ if !bytes.Equal(b[:len(S2IndexHeader)], []byte(S2IndexHeader)) {
+ return nil
+ }
+ b = b[len(S2IndexHeader):]
+ if !bytes.HasSuffix(b, []byte(S2IndexTrailer)) {
+ return nil
+ }
+ b = bytes.TrimSuffix(b, []byte(S2IndexTrailer))
+
+ if len(b) < 4 {
+ return nil
+ }
+ return b[:len(b)-4]
+}
+
+// RestoreIndexHeaders will index restore headers removed by RemoveIndexHeaders.
+// No error checking is performed on the input.
+// If a 0 length slice is sent, it is returned without modification.
+func RestoreIndexHeaders(in []byte) []byte {
+ if len(in) == 0 {
+ return in
+ }
+ b := make([]byte, 0, 4+len(S2IndexHeader)+len(in)+len(S2IndexTrailer)+4)
+ b = append(b, ChunkTypeIndex, 0, 0, 0)
+ b = append(b, []byte(S2IndexHeader)...)
+ b = append(b, in...)
+
+ var tmp [4]byte
+ binary.LittleEndian.PutUint32(tmp[:], uint32(len(b)+4+len(S2IndexTrailer)))
+ b = append(b, tmp[:4]...)
+ // Trailer
+ b = append(b, []byte(S2IndexTrailer)...)
+
+ chunkLen := len(b) - skippableFrameHeader
+ b[1] = uint8(chunkLen >> 0)
+ b[2] = uint8(chunkLen >> 8)
+ b[3] = uint8(chunkLen >> 16)
+ return b
+}
diff --git a/vendor/github.com/klauspost/compress/s2/lz4convert.go b/vendor/github.com/klauspost/compress/s2/lz4convert.go
new file mode 100644
index 00000000000..46ed908e3c0
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/lz4convert.go
@@ -0,0 +1,585 @@
+// Copyright (c) 2022 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+)
+
+// LZ4Converter provides conversion from LZ4 blocks as defined here:
+// https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md
+type LZ4Converter struct {
+}
+
+// ErrDstTooSmall is returned when provided destination is too small.
+var ErrDstTooSmall = errors.New("s2: destination too small")
+
+// ConvertBlock will convert an LZ4 block and append it as an S2
+// block without block length to dst.
+// The uncompressed size is returned as well.
+// dst must have capacity to contain the entire compressed block.
+func (l *LZ4Converter) ConvertBlock(dst, src []byte) ([]byte, int, error) {
+ if len(src) == 0 {
+ return dst, 0, nil
+ }
+ const debug = false
+ const inline = true
+ const lz4MinMatch = 4
+
+ s, d := 0, len(dst)
+ dst = dst[:cap(dst)]
+ if !debug && hasAmd64Asm {
+ res, sz := cvtLZ4BlockAsm(dst[d:], src)
+ if res < 0 {
+ const (
+ errCorrupt = -1
+ errDstTooSmall = -2
+ )
+ switch res {
+ case errCorrupt:
+ return nil, 0, ErrCorrupt
+ case errDstTooSmall:
+ return nil, 0, ErrDstTooSmall
+ default:
+ return nil, 0, fmt.Errorf("unexpected result: %d", res)
+ }
+ }
+ if d+sz > len(dst) {
+ return nil, 0, ErrDstTooSmall
+ }
+ return dst[:d+sz], res, nil
+ }
+
+ dLimit := len(dst) - 10
+ var lastOffset uint16
+ var uncompressed int
+ if debug {
+ fmt.Printf("convert block start: len(src): %d, len(dst):%d \n", len(src), len(dst))
+ }
+
+ for {
+ if s >= len(src) {
+ return dst[:d], 0, ErrCorrupt
+ }
+ // Read literal info
+ token := src[s]
+ ll := int(token >> 4)
+ ml := int(lz4MinMatch + (token & 0xf))
+
+ // If upper nibble is 15, literal length is extended
+ if token >= 0xf0 {
+ for {
+ s++
+ if s >= len(src) {
+ if debug {
+ fmt.Printf("error reading ll: s (%d) >= len(src) (%d)\n", s, len(src))
+ }
+ return dst[:d], 0, ErrCorrupt
+ }
+ val := src[s]
+ ll += int(val)
+ if val != 255 {
+ break
+ }
+ }
+ }
+ // Skip past token
+ if s+ll >= len(src) {
+ if debug {
+ fmt.Printf("error literals: s+ll (%d+%d) >= len(src) (%d)\n", s, ll, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ s++
+ if ll > 0 {
+ if d+ll > dLimit {
+ return nil, 0, ErrDstTooSmall
+ }
+ if debug {
+ fmt.Printf("emit %d literals\n", ll)
+ }
+ d += emitLiteralGo(dst[d:], src[s:s+ll])
+ s += ll
+ uncompressed += ll
+ }
+
+ // Check if we are done...
+ if s == len(src) && ml == lz4MinMatch {
+ break
+ }
+ // 2 byte offset
+ if s >= len(src)-2 {
+ if debug {
+ fmt.Printf("s (%d) >= len(src)-2 (%d)", s, len(src)-2)
+ }
+ return nil, 0, ErrCorrupt
+ }
+ offset := binary.LittleEndian.Uint16(src[s:])
+ s += 2
+ if offset == 0 {
+ if debug {
+ fmt.Printf("error: offset 0, ml: %d, len(src)-s: %d\n", ml, len(src)-s)
+ }
+ return nil, 0, ErrCorrupt
+ }
+ if int(offset) > uncompressed {
+ if debug {
+ fmt.Printf("error: offset (%d)> uncompressed (%d)\n", offset, uncompressed)
+ }
+ return nil, 0, ErrCorrupt
+ }
+
+ if ml == lz4MinMatch+15 {
+ for {
+ if s >= len(src) {
+ if debug {
+ fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ val := src[s]
+ s++
+ ml += int(val)
+ if val != 255 {
+ if s >= len(src) {
+ if debug {
+ fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ break
+ }
+ }
+ }
+ if offset == lastOffset {
+ if debug {
+ fmt.Printf("emit repeat, length: %d, offset: %d\n", ml, offset)
+ }
+ if !inline {
+ d += emitRepeat16(dst[d:], offset, ml)
+ } else {
+ length := ml
+ dst := dst[d:]
+ for len(dst) > 5 {
+ // Repeat offset, make length cheaper
+ length -= 4
+ if length <= 4 {
+ dst[0] = uint8(length)<<2 | tagCopy1
+ dst[1] = 0
+ d += 2
+ break
+ }
+ if length < 8 && offset < 2048 {
+ // Encode WITH offset
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(length)<<2 | tagCopy1
+ d += 2
+ break
+ }
+ if length < (1<<8)+4 {
+ length -= 4
+ dst[2] = uint8(length)
+ dst[1] = 0
+ dst[0] = 5<<2 | tagCopy1
+ d += 3
+ break
+ }
+ if length < (1<<16)+(1<<8) {
+ length -= 1 << 8
+ dst[3] = uint8(length >> 8)
+ dst[2] = uint8(length >> 0)
+ dst[1] = 0
+ dst[0] = 6<<2 | tagCopy1
+ d += 4
+ break
+ }
+ const maxRepeat = (1 << 24) - 1
+ length -= 1 << 16
+ left := 0
+ if length > maxRepeat {
+ left = length - maxRepeat + 4
+ length = maxRepeat - 4
+ }
+ dst[4] = uint8(length >> 16)
+ dst[3] = uint8(length >> 8)
+ dst[2] = uint8(length >> 0)
+ dst[1] = 0
+ dst[0] = 7<<2 | tagCopy1
+ if left > 0 {
+ d += 5 + emitRepeat16(dst[5:], offset, left)
+ break
+ }
+ d += 5
+ break
+ }
+ }
+ } else {
+ if debug {
+ fmt.Printf("emit copy, length: %d, offset: %d\n", ml, offset)
+ }
+ if !inline {
+ d += emitCopy16(dst[d:], offset, ml)
+ } else {
+ length := ml
+ dst := dst[d:]
+ for len(dst) > 5 {
+ // Offset no more than 2 bytes.
+ if length > 64 {
+ off := 3
+ if offset < 2048 {
+ // emit 8 bytes as tagCopy1, rest as repeats.
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(8-4)<<2 | tagCopy1
+ length -= 8
+ off = 2
+ } else {
+ // Emit a length 60 copy, encoded as 3 bytes.
+ // Emit remaining as repeat value (minimum 4 bytes).
+ dst[2] = uint8(offset >> 8)
+ dst[1] = uint8(offset)
+ dst[0] = 59<<2 | tagCopy2
+ length -= 60
+ }
+ // Emit remaining as repeats, at least 4 bytes remain.
+ d += off + emitRepeat16(dst[off:], offset, length)
+ break
+ }
+ if length >= 12 || offset >= 2048 {
+ // Emit the remaining copy, encoded as 3 bytes.
+ dst[2] = uint8(offset >> 8)
+ dst[1] = uint8(offset)
+ dst[0] = uint8(length-1)<<2 | tagCopy2
+ d += 3
+ break
+ }
+ // Emit the remaining copy, encoded as 2 bytes.
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
+ d += 2
+ break
+ }
+ }
+ lastOffset = offset
+ }
+ uncompressed += ml
+ if d > dLimit {
+ return nil, 0, ErrDstTooSmall
+ }
+ }
+
+ return dst[:d], uncompressed, nil
+}
+
+// ConvertBlockSnappy will convert an LZ4 block and append it
+// as a Snappy block without block length to dst.
+// The uncompressed size is returned as well.
+// dst must have capacity to contain the entire compressed block.
+func (l *LZ4Converter) ConvertBlockSnappy(dst, src []byte) ([]byte, int, error) {
+ if len(src) == 0 {
+ return dst, 0, nil
+ }
+ const debug = false
+ const lz4MinMatch = 4
+
+ s, d := 0, len(dst)
+ dst = dst[:cap(dst)]
+ // Use assembly when possible
+ if !debug && hasAmd64Asm {
+ res, sz := cvtLZ4BlockSnappyAsm(dst[d:], src)
+ if res < 0 {
+ const (
+ errCorrupt = -1
+ errDstTooSmall = -2
+ )
+ switch res {
+ case errCorrupt:
+ return nil, 0, ErrCorrupt
+ case errDstTooSmall:
+ return nil, 0, ErrDstTooSmall
+ default:
+ return nil, 0, fmt.Errorf("unexpected result: %d", res)
+ }
+ }
+ if d+sz > len(dst) {
+ return nil, 0, ErrDstTooSmall
+ }
+ return dst[:d+sz], res, nil
+ }
+
+ dLimit := len(dst) - 10
+ var uncompressed int
+ if debug {
+ fmt.Printf("convert block start: len(src): %d, len(dst):%d \n", len(src), len(dst))
+ }
+
+ for {
+ if s >= len(src) {
+ return nil, 0, ErrCorrupt
+ }
+ // Read literal info
+ token := src[s]
+ ll := int(token >> 4)
+ ml := int(lz4MinMatch + (token & 0xf))
+
+ // If upper nibble is 15, literal length is extended
+ if token >= 0xf0 {
+ for {
+ s++
+ if s >= len(src) {
+ if debug {
+ fmt.Printf("error reading ll: s (%d) >= len(src) (%d)\n", s, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ val := src[s]
+ ll += int(val)
+ if val != 255 {
+ break
+ }
+ }
+ }
+ // Skip past token
+ if s+ll >= len(src) {
+ if debug {
+ fmt.Printf("error literals: s+ll (%d+%d) >= len(src) (%d)\n", s, ll, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ s++
+ if ll > 0 {
+ if d+ll > dLimit {
+ return nil, 0, ErrDstTooSmall
+ }
+ if debug {
+ fmt.Printf("emit %d literals\n", ll)
+ }
+ d += emitLiteralGo(dst[d:], src[s:s+ll])
+ s += ll
+ uncompressed += ll
+ }
+
+ // Check if we are done...
+ if s == len(src) && ml == lz4MinMatch {
+ break
+ }
+ // 2 byte offset
+ if s >= len(src)-2 {
+ if debug {
+ fmt.Printf("s (%d) >= len(src)-2 (%d)", s, len(src)-2)
+ }
+ return nil, 0, ErrCorrupt
+ }
+ offset := binary.LittleEndian.Uint16(src[s:])
+ s += 2
+ if offset == 0 {
+ if debug {
+ fmt.Printf("error: offset 0, ml: %d, len(src)-s: %d\n", ml, len(src)-s)
+ }
+ return nil, 0, ErrCorrupt
+ }
+ if int(offset) > uncompressed {
+ if debug {
+ fmt.Printf("error: offset (%d)> uncompressed (%d)\n", offset, uncompressed)
+ }
+ return nil, 0, ErrCorrupt
+ }
+
+ if ml == lz4MinMatch+15 {
+ for {
+ if s >= len(src) {
+ if debug {
+ fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ val := src[s]
+ s++
+ ml += int(val)
+ if val != 255 {
+ if s >= len(src) {
+ if debug {
+ fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ break
+ }
+ }
+ }
+ if debug {
+ fmt.Printf("emit copy, length: %d, offset: %d\n", ml, offset)
+ }
+ length := ml
+ // d += emitCopyNoRepeat(dst[d:], int(offset), ml)
+ for length > 0 {
+ if d >= dLimit {
+ return nil, 0, ErrDstTooSmall
+ }
+
+ // Offset no more than 2 bytes.
+ if length > 64 {
+ // Emit a length 64 copy, encoded as 3 bytes.
+ dst[d+2] = uint8(offset >> 8)
+ dst[d+1] = uint8(offset)
+ dst[d+0] = 63<<2 | tagCopy2
+ length -= 64
+ d += 3
+ continue
+ }
+ if length >= 12 || offset >= 2048 || length < 4 {
+ // Emit the remaining copy, encoded as 3 bytes.
+ dst[d+2] = uint8(offset >> 8)
+ dst[d+1] = uint8(offset)
+ dst[d+0] = uint8(length-1)<<2 | tagCopy2
+ d += 3
+ break
+ }
+ // Emit the remaining copy, encoded as 2 bytes.
+ dst[d+1] = uint8(offset)
+ dst[d+0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
+ d += 2
+ break
+ }
+ uncompressed += ml
+ if d > dLimit {
+ return nil, 0, ErrDstTooSmall
+ }
+ }
+
+ return dst[:d], uncompressed, nil
+}
+
+// emitRepeat writes a repeat chunk and returns the number of bytes written.
+// Length must be at least 4 and < 1<<24
+func emitRepeat16(dst []byte, offset uint16, length int) int {
+ // Repeat offset, make length cheaper
+ length -= 4
+ if length <= 4 {
+ dst[0] = uint8(length)<<2 | tagCopy1
+ dst[1] = 0
+ return 2
+ }
+ if length < 8 && offset < 2048 {
+ // Encode WITH offset
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(length)<<2 | tagCopy1
+ return 2
+ }
+ if length < (1<<8)+4 {
+ length -= 4
+ dst[2] = uint8(length)
+ dst[1] = 0
+ dst[0] = 5<<2 | tagCopy1
+ return 3
+ }
+ if length < (1<<16)+(1<<8) {
+ length -= 1 << 8
+ dst[3] = uint8(length >> 8)
+ dst[2] = uint8(length >> 0)
+ dst[1] = 0
+ dst[0] = 6<<2 | tagCopy1
+ return 4
+ }
+ const maxRepeat = (1 << 24) - 1
+ length -= 1 << 16
+ left := 0
+ if length > maxRepeat {
+ left = length - maxRepeat + 4
+ length = maxRepeat - 4
+ }
+ dst[4] = uint8(length >> 16)
+ dst[3] = uint8(length >> 8)
+ dst[2] = uint8(length >> 0)
+ dst[1] = 0
+ dst[0] = 7<<2 | tagCopy1
+ if left > 0 {
+ return 5 + emitRepeat16(dst[5:], offset, left)
+ }
+ return 5
+}
+
+// emitCopy writes a copy chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes
+// 1 <= offset && offset <= math.MaxUint16
+// 4 <= length && length <= math.MaxUint32
+func emitCopy16(dst []byte, offset uint16, length int) int {
+ // Offset no more than 2 bytes.
+ if length > 64 {
+ off := 3
+ if offset < 2048 {
+ // emit 8 bytes as tagCopy1, rest as repeats.
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(8-4)<<2 | tagCopy1
+ length -= 8
+ off = 2
+ } else {
+ // Emit a length 60 copy, encoded as 3 bytes.
+ // Emit remaining as repeat value (minimum 4 bytes).
+ dst[2] = uint8(offset >> 8)
+ dst[1] = uint8(offset)
+ dst[0] = 59<<2 | tagCopy2
+ length -= 60
+ }
+ // Emit remaining as repeats, at least 4 bytes remain.
+ return off + emitRepeat16(dst[off:], offset, length)
+ }
+ if length >= 12 || offset >= 2048 {
+ // Emit the remaining copy, encoded as 3 bytes.
+ dst[2] = uint8(offset >> 8)
+ dst[1] = uint8(offset)
+ dst[0] = uint8(length-1)<<2 | tagCopy2
+ return 3
+ }
+ // Emit the remaining copy, encoded as 2 bytes.
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
+ return 2
+}
+
+// emitLiteral writes a literal chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes
+// 0 <= len(lit) && len(lit) <= math.MaxUint32
+func emitLiteralGo(dst, lit []byte) int {
+ if len(lit) == 0 {
+ return 0
+ }
+ i, n := 0, uint(len(lit)-1)
+ switch {
+ case n < 60:
+ dst[0] = uint8(n)<<2 | tagLiteral
+ i = 1
+ case n < 1<<8:
+ dst[1] = uint8(n)
+ dst[0] = 60<<2 | tagLiteral
+ i = 2
+ case n < 1<<16:
+ dst[2] = uint8(n >> 8)
+ dst[1] = uint8(n)
+ dst[0] = 61<<2 | tagLiteral
+ i = 3
+ case n < 1<<24:
+ dst[3] = uint8(n >> 16)
+ dst[2] = uint8(n >> 8)
+ dst[1] = uint8(n)
+ dst[0] = 62<<2 | tagLiteral
+ i = 4
+ default:
+ dst[4] = uint8(n >> 24)
+ dst[3] = uint8(n >> 16)
+ dst[2] = uint8(n >> 8)
+ dst[1] = uint8(n)
+ dst[0] = 63<<2 | tagLiteral
+ i = 5
+ }
+ return i + copy(dst[i:], lit)
+}
diff --git a/vendor/github.com/klauspost/compress/s2/lz4sconvert.go b/vendor/github.com/klauspost/compress/s2/lz4sconvert.go
new file mode 100644
index 00000000000..000f39719c5
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/lz4sconvert.go
@@ -0,0 +1,467 @@
+// Copyright (c) 2022 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+// LZ4sConverter provides conversion from LZ4s.
+// (Intel modified LZ4 Blocks)
+// https://cdrdv2-public.intel.com/743912/743912-qat-programmers-guide-v2.0.pdf
+// LZ4s is a variant of LZ4 block format. LZ4s should be considered as an intermediate compressed block format.
+// The LZ4s format is selected when the application sets the compType to CPA_DC_LZ4S in CpaDcSessionSetupData.
+// The LZ4s block returned by the Intel® QAT hardware can be used by an external
+// software post-processing to generate other compressed data formats.
+// The following table lists the differences between LZ4 and LZ4s block format. LZ4s block format uses
+// the same high-level formatting as LZ4 block format with the following encoding changes:
+// For Min Match of 4 bytes, Copy length value 1-15 means length 4-18 with 18 bytes adding an extra byte.
+// ONLY "Min match of 4 bytes" is supported.
+type LZ4sConverter struct {
+}
+
+// ConvertBlock will convert an LZ4s block and append it as an S2
+// block without block length to dst.
+// The uncompressed size is returned as well.
+// dst must have capacity to contain the entire compressed block.
+func (l *LZ4sConverter) ConvertBlock(dst, src []byte) ([]byte, int, error) {
+ if len(src) == 0 {
+ return dst, 0, nil
+ }
+ const debug = false
+ const inline = true
+ const lz4MinMatch = 3
+
+ s, d := 0, len(dst)
+ dst = dst[:cap(dst)]
+ if !debug && hasAmd64Asm {
+ res, sz := cvtLZ4sBlockAsm(dst[d:], src)
+ if res < 0 {
+ const (
+ errCorrupt = -1
+ errDstTooSmall = -2
+ )
+ switch res {
+ case errCorrupt:
+ return nil, 0, ErrCorrupt
+ case errDstTooSmall:
+ return nil, 0, ErrDstTooSmall
+ default:
+ return nil, 0, fmt.Errorf("unexpected result: %d", res)
+ }
+ }
+ if d+sz > len(dst) {
+ return nil, 0, ErrDstTooSmall
+ }
+ return dst[:d+sz], res, nil
+ }
+
+ dLimit := len(dst) - 10
+ var lastOffset uint16
+ var uncompressed int
+ if debug {
+ fmt.Printf("convert block start: len(src): %d, len(dst):%d \n", len(src), len(dst))
+ }
+
+ for {
+ if s >= len(src) {
+ return dst[:d], 0, ErrCorrupt
+ }
+ // Read literal info
+ token := src[s]
+ ll := int(token >> 4)
+ ml := int(lz4MinMatch + (token & 0xf))
+
+ // If upper nibble is 15, literal length is extended
+ if token >= 0xf0 {
+ for {
+ s++
+ if s >= len(src) {
+ if debug {
+ fmt.Printf("error reading ll: s (%d) >= len(src) (%d)\n", s, len(src))
+ }
+ return dst[:d], 0, ErrCorrupt
+ }
+ val := src[s]
+ ll += int(val)
+ if val != 255 {
+ break
+ }
+ }
+ }
+ // Skip past token
+ if s+ll >= len(src) {
+ if debug {
+ fmt.Printf("error literals: s+ll (%d+%d) >= len(src) (%d)\n", s, ll, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ s++
+ if ll > 0 {
+ if d+ll > dLimit {
+ return nil, 0, ErrDstTooSmall
+ }
+ if debug {
+ fmt.Printf("emit %d literals\n", ll)
+ }
+ d += emitLiteralGo(dst[d:], src[s:s+ll])
+ s += ll
+ uncompressed += ll
+ }
+
+ // Check if we are done...
+ if ml == lz4MinMatch {
+ if s == len(src) {
+ break
+ }
+ // 0 bytes.
+ continue
+ }
+ // 2 byte offset
+ if s >= len(src)-2 {
+ if debug {
+ fmt.Printf("s (%d) >= len(src)-2 (%d)", s, len(src)-2)
+ }
+ return nil, 0, ErrCorrupt
+ }
+ offset := binary.LittleEndian.Uint16(src[s:])
+ s += 2
+ if offset == 0 {
+ if debug {
+ fmt.Printf("error: offset 0, ml: %d, len(src)-s: %d\n", ml, len(src)-s)
+ }
+ return nil, 0, ErrCorrupt
+ }
+ if int(offset) > uncompressed {
+ if debug {
+ fmt.Printf("error: offset (%d)> uncompressed (%d)\n", offset, uncompressed)
+ }
+ return nil, 0, ErrCorrupt
+ }
+
+ if ml == lz4MinMatch+15 {
+ for {
+ if s >= len(src) {
+ if debug {
+ fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ val := src[s]
+ s++
+ ml += int(val)
+ if val != 255 {
+ if s >= len(src) {
+ if debug {
+ fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ break
+ }
+ }
+ }
+ if offset == lastOffset {
+ if debug {
+ fmt.Printf("emit repeat, length: %d, offset: %d\n", ml, offset)
+ }
+ if !inline {
+ d += emitRepeat16(dst[d:], offset, ml)
+ } else {
+ length := ml
+ dst := dst[d:]
+ for len(dst) > 5 {
+ // Repeat offset, make length cheaper
+ length -= 4
+ if length <= 4 {
+ dst[0] = uint8(length)<<2 | tagCopy1
+ dst[1] = 0
+ d += 2
+ break
+ }
+ if length < 8 && offset < 2048 {
+ // Encode WITH offset
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(length)<<2 | tagCopy1
+ d += 2
+ break
+ }
+ if length < (1<<8)+4 {
+ length -= 4
+ dst[2] = uint8(length)
+ dst[1] = 0
+ dst[0] = 5<<2 | tagCopy1
+ d += 3
+ break
+ }
+ if length < (1<<16)+(1<<8) {
+ length -= 1 << 8
+ dst[3] = uint8(length >> 8)
+ dst[2] = uint8(length >> 0)
+ dst[1] = 0
+ dst[0] = 6<<2 | tagCopy1
+ d += 4
+ break
+ }
+ const maxRepeat = (1 << 24) - 1
+ length -= 1 << 16
+ left := 0
+ if length > maxRepeat {
+ left = length - maxRepeat + 4
+ length = maxRepeat - 4
+ }
+ dst[4] = uint8(length >> 16)
+ dst[3] = uint8(length >> 8)
+ dst[2] = uint8(length >> 0)
+ dst[1] = 0
+ dst[0] = 7<<2 | tagCopy1
+ if left > 0 {
+ d += 5 + emitRepeat16(dst[5:], offset, left)
+ break
+ }
+ d += 5
+ break
+ }
+ }
+ } else {
+ if debug {
+ fmt.Printf("emit copy, length: %d, offset: %d\n", ml, offset)
+ }
+ if !inline {
+ d += emitCopy16(dst[d:], offset, ml)
+ } else {
+ length := ml
+ dst := dst[d:]
+ for len(dst) > 5 {
+ // Offset no more than 2 bytes.
+ if length > 64 {
+ off := 3
+ if offset < 2048 {
+ // emit 8 bytes as tagCopy1, rest as repeats.
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(8-4)<<2 | tagCopy1
+ length -= 8
+ off = 2
+ } else {
+ // Emit a length 60 copy, encoded as 3 bytes.
+ // Emit remaining as repeat value (minimum 4 bytes).
+ dst[2] = uint8(offset >> 8)
+ dst[1] = uint8(offset)
+ dst[0] = 59<<2 | tagCopy2
+ length -= 60
+ }
+ // Emit remaining as repeats, at least 4 bytes remain.
+ d += off + emitRepeat16(dst[off:], offset, length)
+ break
+ }
+ if length >= 12 || offset >= 2048 {
+ // Emit the remaining copy, encoded as 3 bytes.
+ dst[2] = uint8(offset >> 8)
+ dst[1] = uint8(offset)
+ dst[0] = uint8(length-1)<<2 | tagCopy2
+ d += 3
+ break
+ }
+ // Emit the remaining copy, encoded as 2 bytes.
+ dst[1] = uint8(offset)
+ dst[0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
+ d += 2
+ break
+ }
+ }
+ lastOffset = offset
+ }
+ uncompressed += ml
+ if d > dLimit {
+ return nil, 0, ErrDstTooSmall
+ }
+ }
+
+ return dst[:d], uncompressed, nil
+}
+
+// ConvertBlockSnappy will convert an LZ4s block and append it
+// as a Snappy block without block length to dst.
+// The uncompressed size is returned as well.
+// dst must have capacity to contain the entire compressed block.
+func (l *LZ4sConverter) ConvertBlockSnappy(dst, src []byte) ([]byte, int, error) {
+ if len(src) == 0 {
+ return dst, 0, nil
+ }
+ const debug = false
+ const lz4MinMatch = 3
+
+ s, d := 0, len(dst)
+ dst = dst[:cap(dst)]
+ // Use assembly when possible
+ if !debug && hasAmd64Asm {
+ res, sz := cvtLZ4sBlockSnappyAsm(dst[d:], src)
+ if res < 0 {
+ const (
+ errCorrupt = -1
+ errDstTooSmall = -2
+ )
+ switch res {
+ case errCorrupt:
+ return nil, 0, ErrCorrupt
+ case errDstTooSmall:
+ return nil, 0, ErrDstTooSmall
+ default:
+ return nil, 0, fmt.Errorf("unexpected result: %d", res)
+ }
+ }
+ if d+sz > len(dst) {
+ return nil, 0, ErrDstTooSmall
+ }
+ return dst[:d+sz], res, nil
+ }
+
+ dLimit := len(dst) - 10
+ var uncompressed int
+ if debug {
+ fmt.Printf("convert block start: len(src): %d, len(dst):%d \n", len(src), len(dst))
+ }
+
+ for {
+ if s >= len(src) {
+ return nil, 0, ErrCorrupt
+ }
+ // Read literal info
+ token := src[s]
+ ll := int(token >> 4)
+ ml := int(lz4MinMatch + (token & 0xf))
+
+ // If upper nibble is 15, literal length is extended
+ if token >= 0xf0 {
+ for {
+ s++
+ if s >= len(src) {
+ if debug {
+ fmt.Printf("error reading ll: s (%d) >= len(src) (%d)\n", s, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ val := src[s]
+ ll += int(val)
+ if val != 255 {
+ break
+ }
+ }
+ }
+ // Skip past token
+ if s+ll >= len(src) {
+ if debug {
+ fmt.Printf("error literals: s+ll (%d+%d) >= len(src) (%d)\n", s, ll, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ s++
+ if ll > 0 {
+ if d+ll > dLimit {
+ return nil, 0, ErrDstTooSmall
+ }
+ if debug {
+ fmt.Printf("emit %d literals\n", ll)
+ }
+ d += emitLiteralGo(dst[d:], src[s:s+ll])
+ s += ll
+ uncompressed += ll
+ }
+
+ // Check if we are done...
+ if ml == lz4MinMatch {
+ if s == len(src) {
+ break
+ }
+ // 0 bytes.
+ continue
+ }
+ // 2 byte offset
+ if s >= len(src)-2 {
+ if debug {
+ fmt.Printf("s (%d) >= len(src)-2 (%d)", s, len(src)-2)
+ }
+ return nil, 0, ErrCorrupt
+ }
+ offset := binary.LittleEndian.Uint16(src[s:])
+ s += 2
+ if offset == 0 {
+ if debug {
+ fmt.Printf("error: offset 0, ml: %d, len(src)-s: %d\n", ml, len(src)-s)
+ }
+ return nil, 0, ErrCorrupt
+ }
+ if int(offset) > uncompressed {
+ if debug {
+ fmt.Printf("error: offset (%d)> uncompressed (%d)\n", offset, uncompressed)
+ }
+ return nil, 0, ErrCorrupt
+ }
+
+ if ml == lz4MinMatch+15 {
+ for {
+ if s >= len(src) {
+ if debug {
+ fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ val := src[s]
+ s++
+ ml += int(val)
+ if val != 255 {
+ if s >= len(src) {
+ if debug {
+ fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
+ }
+ return nil, 0, ErrCorrupt
+ }
+ break
+ }
+ }
+ }
+ if debug {
+ fmt.Printf("emit copy, length: %d, offset: %d\n", ml, offset)
+ }
+ length := ml
+ // d += emitCopyNoRepeat(dst[d:], int(offset), ml)
+ for length > 0 {
+ if d >= dLimit {
+ return nil, 0, ErrDstTooSmall
+ }
+
+ // Offset no more than 2 bytes.
+ if length > 64 {
+ // Emit a length 64 copy, encoded as 3 bytes.
+ dst[d+2] = uint8(offset >> 8)
+ dst[d+1] = uint8(offset)
+ dst[d+0] = 63<<2 | tagCopy2
+ length -= 64
+ d += 3
+ continue
+ }
+ if length >= 12 || offset >= 2048 || length < 4 {
+ // Emit the remaining copy, encoded as 3 bytes.
+ dst[d+2] = uint8(offset >> 8)
+ dst[d+1] = uint8(offset)
+ dst[d+0] = uint8(length-1)<<2 | tagCopy2
+ d += 3
+ break
+ }
+ // Emit the remaining copy, encoded as 2 bytes.
+ dst[d+1] = uint8(offset)
+ dst[d+0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
+ d += 2
+ break
+ }
+ uncompressed += ml
+ if d > dLimit {
+ return nil, 0, ErrDstTooSmall
+ }
+ }
+
+ return dst[:d], uncompressed, nil
+}
diff --git a/vendor/github.com/klauspost/compress/s2/reader.go b/vendor/github.com/klauspost/compress/s2/reader.go
new file mode 100644
index 00000000000..4d01c4190cc
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/reader.go
@@ -0,0 +1,1075 @@
+// Copyright 2011 The Snappy-Go Authors. All rights reserved.
+// Copyright (c) 2019+ Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "math"
+ "runtime"
+ "sync"
+)
+
+// ErrCantSeek is returned if the stream cannot be seeked.
+type ErrCantSeek struct {
+ Reason string
+}
+
+// Error returns the error as string.
+func (e ErrCantSeek) Error() string {
+ return fmt.Sprintf("s2: Can't seek because %s", e.Reason)
+}
+
+// NewReader returns a new Reader that decompresses from r, using the framing
+// format described at
+// https://github.com/google/snappy/blob/master/framing_format.txt with S2 changes.
+func NewReader(r io.Reader, opts ...ReaderOption) *Reader {
+ nr := Reader{
+ r: r,
+ maxBlock: maxBlockSize,
+ }
+ for _, opt := range opts {
+ if err := opt(&nr); err != nil {
+ nr.err = err
+ return &nr
+ }
+ }
+ nr.maxBufSize = MaxEncodedLen(nr.maxBlock) + checksumSize
+ if nr.lazyBuf > 0 {
+ nr.buf = make([]byte, MaxEncodedLen(nr.lazyBuf)+checksumSize)
+ } else {
+ nr.buf = make([]byte, MaxEncodedLen(defaultBlockSize)+checksumSize)
+ }
+ nr.readHeader = nr.ignoreStreamID
+ nr.paramsOK = true
+ return &nr
+}
+
+// ReaderOption is an option for creating a decoder.
+type ReaderOption func(*Reader) error
+
+// ReaderMaxBlockSize allows to control allocations if the stream
+// has been compressed with a smaller WriterBlockSize, or with the default 1MB.
+// Blocks must be this size or smaller to decompress,
+// otherwise the decoder will return ErrUnsupported.
+//
+// For streams compressed with Snappy this can safely be set to 64KB (64 << 10).
+//
+// Default is the maximum limit of 4MB.
+func ReaderMaxBlockSize(blockSize int) ReaderOption {
+ return func(r *Reader) error {
+ if blockSize > maxBlockSize || blockSize <= 0 {
+ return errors.New("s2: block size too large. Must be <= 4MB and > 0")
+ }
+ if r.lazyBuf == 0 && blockSize < defaultBlockSize {
+ r.lazyBuf = blockSize
+ }
+ r.maxBlock = blockSize
+ return nil
+ }
+}
+
+// ReaderAllocBlock allows to control upfront stream allocations
+// and not allocate for frames bigger than this initially.
+// If frames bigger than this is seen a bigger buffer will be allocated.
+//
+// Default is 1MB, which is default output size.
+func ReaderAllocBlock(blockSize int) ReaderOption {
+ return func(r *Reader) error {
+ if blockSize > maxBlockSize || blockSize < 1024 {
+ return errors.New("s2: invalid ReaderAllocBlock. Must be <= 4MB and >= 1024")
+ }
+ r.lazyBuf = blockSize
+ return nil
+ }
+}
+
+// ReaderIgnoreStreamIdentifier will make the reader skip the expected
+// stream identifier at the beginning of the stream.
+// This can be used when serving a stream that has been forwarded to a specific point.
+func ReaderIgnoreStreamIdentifier() ReaderOption {
+ return func(r *Reader) error {
+ r.ignoreStreamID = true
+ return nil
+ }
+}
+
+// ReaderSkippableCB will register a callback for chuncks with the specified ID.
+// ID must be a Reserved skippable chunks ID, 0x80-0xfd (inclusive).
+// For each chunk with the ID, the callback is called with the content.
+// Any returned non-nil error will abort decompression.
+// Only one callback per ID is supported, latest sent will be used.
+// You can peek the stream, triggering the callback, by doing a Read with a 0
+// byte buffer.
+func ReaderSkippableCB(id uint8, fn func(r io.Reader) error) ReaderOption {
+ return func(r *Reader) error {
+ if id < 0x80 || id > 0xfd {
+ return fmt.Errorf("ReaderSkippableCB: Invalid id provided, must be 0x80-0xfd (inclusive)")
+ }
+ r.skippableCB[id-0x80] = fn
+ return nil
+ }
+}
+
+// ReaderIgnoreCRC will make the reader skip CRC calculation and checks.
+func ReaderIgnoreCRC() ReaderOption {
+ return func(r *Reader) error {
+ r.ignoreCRC = true
+ return nil
+ }
+}
+
+// Reader is an io.Reader that can read Snappy-compressed bytes.
+type Reader struct {
+ r io.Reader
+ err error
+ decoded []byte
+ buf []byte
+ skippableCB [0xff - 0x80]func(r io.Reader) error
+ blockStart int64 // Uncompressed offset at start of current.
+ index *Index
+
+ // decoded[i:j] contains decoded bytes that have not yet been passed on.
+ i, j int
+ // maximum block size allowed.
+ maxBlock int
+ // maximum expected buffer size.
+ maxBufSize int
+ // alloc a buffer this size if > 0.
+ lazyBuf int
+ readHeader bool
+ paramsOK bool
+ snappyFrame bool
+ ignoreStreamID bool
+ ignoreCRC bool
+}
+
+// GetBufferCapacity returns the capacity of the internal buffer.
+// This might be useful to know when reusing the same reader in combination
+// with the lazy buffer option.
+func (r *Reader) GetBufferCapacity() int {
+ return cap(r.buf)
+}
+
+// ensureBufferSize will ensure that the buffer can take at least n bytes.
+// If false is returned the buffer exceeds maximum allowed size.
+func (r *Reader) ensureBufferSize(n int) bool {
+ if n > r.maxBufSize {
+ r.err = ErrCorrupt
+ return false
+ }
+ if cap(r.buf) >= n {
+ return true
+ }
+ // Realloc buffer.
+ r.buf = make([]byte, n)
+ return true
+}
+
+// Reset discards any buffered data, resets all state, and switches the Snappy
+// reader to read from r. This permits reusing a Reader rather than allocating
+// a new one.
+func (r *Reader) Reset(reader io.Reader) {
+ if !r.paramsOK {
+ return
+ }
+ r.index = nil
+ r.r = reader
+ r.err = nil
+ r.i = 0
+ r.j = 0
+ r.blockStart = 0
+ r.readHeader = r.ignoreStreamID
+}
+
+func (r *Reader) readFull(p []byte, allowEOF bool) (ok bool) {
+ if _, r.err = io.ReadFull(r.r, p); r.err != nil {
+ if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) {
+ r.err = ErrCorrupt
+ }
+ return false
+ }
+ return true
+}
+
+// skippable will skip n bytes.
+// If the supplied reader supports seeking that is used.
+// tmp is used as a temporary buffer for reading.
+// The supplied slice does not need to be the size of the read.
+func (r *Reader) skippable(tmp []byte, n int, allowEOF bool, id uint8) (ok bool) {
+ if id < 0x80 {
+ r.err = fmt.Errorf("internal error: skippable id < 0x80")
+ return false
+ }
+ if fn := r.skippableCB[id-0x80]; fn != nil {
+ rd := io.LimitReader(r.r, int64(n))
+ r.err = fn(rd)
+ if r.err != nil {
+ return false
+ }
+ _, r.err = io.CopyBuffer(ioutil.Discard, rd, tmp)
+ return r.err == nil
+ }
+ if rs, ok := r.r.(io.ReadSeeker); ok {
+ _, err := rs.Seek(int64(n), io.SeekCurrent)
+ if err == nil {
+ return true
+ }
+ if err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) {
+ r.err = ErrCorrupt
+ return false
+ }
+ }
+ for n > 0 {
+ if n < len(tmp) {
+ tmp = tmp[:n]
+ }
+ if _, r.err = io.ReadFull(r.r, tmp); r.err != nil {
+ if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) {
+ r.err = ErrCorrupt
+ }
+ return false
+ }
+ n -= len(tmp)
+ }
+ return true
+}
+
+// Read satisfies the io.Reader interface.
+func (r *Reader) Read(p []byte) (int, error) {
+ if r.err != nil {
+ return 0, r.err
+ }
+ for {
+ if r.i < r.j {
+ n := copy(p, r.decoded[r.i:r.j])
+ r.i += n
+ return n, nil
+ }
+ if !r.readFull(r.buf[:4], true) {
+ return 0, r.err
+ }
+ chunkType := r.buf[0]
+ if !r.readHeader {
+ if chunkType != chunkTypeStreamIdentifier {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ r.readHeader = true
+ }
+ chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
+
+ // The chunk types are specified at
+ // https://github.com/google/snappy/blob/master/framing_format.txt
+ switch chunkType {
+ case chunkTypeCompressedData:
+ r.blockStart += int64(r.j)
+ // Section 4.2. Compressed data (chunk type 0x00).
+ if chunkLen < checksumSize {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ if !r.ensureBufferSize(chunkLen) {
+ if r.err == nil {
+ r.err = ErrUnsupported
+ }
+ return 0, r.err
+ }
+ buf := r.buf[:chunkLen]
+ if !r.readFull(buf, false) {
+ return 0, r.err
+ }
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ buf = buf[checksumSize:]
+
+ n, err := DecodedLen(buf)
+ if err != nil {
+ r.err = err
+ return 0, r.err
+ }
+ if r.snappyFrame && n > maxSnappyBlockSize {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+
+ if n > len(r.decoded) {
+ if n > r.maxBlock {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ r.decoded = make([]byte, n)
+ }
+ if _, err := Decode(r.decoded, buf); err != nil {
+ r.err = err
+ return 0, r.err
+ }
+ if !r.ignoreCRC && crc(r.decoded[:n]) != checksum {
+ r.err = ErrCRC
+ return 0, r.err
+ }
+ r.i, r.j = 0, n
+ continue
+
+ case chunkTypeUncompressedData:
+ r.blockStart += int64(r.j)
+ // Section 4.3. Uncompressed data (chunk type 0x01).
+ if chunkLen < checksumSize {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ if !r.ensureBufferSize(chunkLen) {
+ if r.err == nil {
+ r.err = ErrUnsupported
+ }
+ return 0, r.err
+ }
+ buf := r.buf[:checksumSize]
+ if !r.readFull(buf, false) {
+ return 0, r.err
+ }
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ // Read directly into r.decoded instead of via r.buf.
+ n := chunkLen - checksumSize
+ if r.snappyFrame && n > maxSnappyBlockSize {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ if n > len(r.decoded) {
+ if n > r.maxBlock {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ r.decoded = make([]byte, n)
+ }
+ if !r.readFull(r.decoded[:n], false) {
+ return 0, r.err
+ }
+ if !r.ignoreCRC && crc(r.decoded[:n]) != checksum {
+ r.err = ErrCRC
+ return 0, r.err
+ }
+ r.i, r.j = 0, n
+ continue
+
+ case chunkTypeStreamIdentifier:
+ // Section 4.1. Stream identifier (chunk type 0xff).
+ if chunkLen != len(magicBody) {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ if !r.readFull(r.buf[:len(magicBody)], false) {
+ return 0, r.err
+ }
+ if string(r.buf[:len(magicBody)]) != magicBody {
+ if string(r.buf[:len(magicBody)]) != magicBodySnappy {
+ r.err = ErrCorrupt
+ return 0, r.err
+ } else {
+ r.snappyFrame = true
+ }
+ } else {
+ r.snappyFrame = false
+ }
+ continue
+ }
+
+ if chunkType <= 0x7f {
+ // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
+ // fmt.Printf("ERR chunktype: 0x%x\n", chunkType)
+ r.err = ErrUnsupported
+ return 0, r.err
+ }
+ // Section 4.4 Padding (chunk type 0xfe).
+ // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
+ if chunkLen > maxChunkSize {
+ // fmt.Printf("ERR chunkLen: 0x%x\n", chunkLen)
+ r.err = ErrUnsupported
+ return 0, r.err
+ }
+
+ // fmt.Printf("skippable: ID: 0x%x, len: 0x%x\n", chunkType, chunkLen)
+ if !r.skippable(r.buf, chunkLen, false, chunkType) {
+ return 0, r.err
+ }
+ }
+}
+
+// DecodeConcurrent will decode the full stream to w.
+// This function should not be combined with reading, seeking or other operations.
+// Up to 'concurrent' goroutines will be used.
+// If <= 0, runtime.NumCPU will be used.
+// On success the number of bytes decompressed nil and is returned.
+// This is mainly intended for bigger streams.
+func (r *Reader) DecodeConcurrent(w io.Writer, concurrent int) (written int64, err error) {
+ if r.i > 0 || r.j > 0 || r.blockStart > 0 {
+ return 0, errors.New("DecodeConcurrent called after ")
+ }
+ if concurrent <= 0 {
+ concurrent = runtime.NumCPU()
+ }
+
+ // Write to output
+ var errMu sync.Mutex
+ var aErr error
+ setErr := func(e error) (ok bool) {
+ errMu.Lock()
+ defer errMu.Unlock()
+ if e == nil {
+ return aErr == nil
+ }
+ if aErr == nil {
+ aErr = e
+ }
+ return false
+ }
+ hasErr := func() (ok bool) {
+ errMu.Lock()
+ v := aErr != nil
+ errMu.Unlock()
+ return v
+ }
+
+ var aWritten int64
+ toRead := make(chan []byte, concurrent)
+ writtenBlocks := make(chan []byte, concurrent)
+ queue := make(chan chan []byte, concurrent)
+ reUse := make(chan chan []byte, concurrent)
+ for i := 0; i < concurrent; i++ {
+ toRead <- make([]byte, 0, r.maxBufSize)
+ writtenBlocks <- make([]byte, 0, r.maxBufSize)
+ reUse <- make(chan []byte, 1)
+ }
+ // Writer
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for toWrite := range queue {
+ entry := <-toWrite
+ reUse <- toWrite
+ if hasErr() || entry == nil {
+ if entry != nil {
+ writtenBlocks <- entry
+ }
+ continue
+ }
+ if hasErr() {
+ writtenBlocks <- entry
+ continue
+ }
+ n, err := w.Write(entry)
+ want := len(entry)
+ writtenBlocks <- entry
+ if err != nil {
+ setErr(err)
+ continue
+ }
+ if n != want {
+ setErr(io.ErrShortWrite)
+ continue
+ }
+ aWritten += int64(n)
+ }
+ }()
+
+ defer func() {
+ if r.err != nil {
+ setErr(r.err)
+ } else if err != nil {
+ setErr(err)
+ }
+ close(queue)
+ wg.Wait()
+ if err == nil {
+ err = aErr
+ }
+ written = aWritten
+ }()
+
+ // Reader
+ for !hasErr() {
+ if !r.readFull(r.buf[:4], true) {
+ if r.err == io.EOF {
+ r.err = nil
+ }
+ return 0, r.err
+ }
+ chunkType := r.buf[0]
+ if !r.readHeader {
+ if chunkType != chunkTypeStreamIdentifier {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ r.readHeader = true
+ }
+ chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
+
+ // The chunk types are specified at
+ // https://github.com/google/snappy/blob/master/framing_format.txt
+ switch chunkType {
+ case chunkTypeCompressedData:
+ r.blockStart += int64(r.j)
+ // Section 4.2. Compressed data (chunk type 0x00).
+ if chunkLen < checksumSize {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ if chunkLen > r.maxBufSize {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ orgBuf := <-toRead
+ buf := orgBuf[:chunkLen]
+
+ if !r.readFull(buf, false) {
+ return 0, r.err
+ }
+
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ buf = buf[checksumSize:]
+
+ n, err := DecodedLen(buf)
+ if err != nil {
+ r.err = err
+ return 0, r.err
+ }
+ if r.snappyFrame && n > maxSnappyBlockSize {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+
+ if n > r.maxBlock {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ wg.Add(1)
+
+ decoded := <-writtenBlocks
+ entry := <-reUse
+ queue <- entry
+ go func() {
+ defer wg.Done()
+ decoded = decoded[:n]
+ _, err := Decode(decoded, buf)
+ toRead <- orgBuf
+ if err != nil {
+ writtenBlocks <- decoded
+ setErr(err)
+ entry <- nil
+ return
+ }
+ if !r.ignoreCRC && crc(decoded) != checksum {
+ writtenBlocks <- decoded
+ setErr(ErrCRC)
+ entry <- nil
+ return
+ }
+ entry <- decoded
+ }()
+ continue
+
+ case chunkTypeUncompressedData:
+
+ // Section 4.3. Uncompressed data (chunk type 0x01).
+ if chunkLen < checksumSize {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ if chunkLen > r.maxBufSize {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ // Grab write buffer
+ orgBuf := <-writtenBlocks
+ buf := orgBuf[:checksumSize]
+ if !r.readFull(buf, false) {
+ return 0, r.err
+ }
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ // Read content.
+ n := chunkLen - checksumSize
+
+ if r.snappyFrame && n > maxSnappyBlockSize {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ if n > r.maxBlock {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ // Read uncompressed
+ buf = orgBuf[:n]
+ if !r.readFull(buf, false) {
+ return 0, r.err
+ }
+
+ if !r.ignoreCRC && crc(buf) != checksum {
+ r.err = ErrCRC
+ return 0, r.err
+ }
+ entry := <-reUse
+ queue <- entry
+ entry <- buf
+ continue
+
+ case chunkTypeStreamIdentifier:
+ // Section 4.1. Stream identifier (chunk type 0xff).
+ if chunkLen != len(magicBody) {
+ r.err = ErrCorrupt
+ return 0, r.err
+ }
+ if !r.readFull(r.buf[:len(magicBody)], false) {
+ return 0, r.err
+ }
+ if string(r.buf[:len(magicBody)]) != magicBody {
+ if string(r.buf[:len(magicBody)]) != magicBodySnappy {
+ r.err = ErrCorrupt
+ return 0, r.err
+ } else {
+ r.snappyFrame = true
+ }
+ } else {
+ r.snappyFrame = false
+ }
+ continue
+ }
+
+ if chunkType <= 0x7f {
+ // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
+ // fmt.Printf("ERR chunktype: 0x%x\n", chunkType)
+ r.err = ErrUnsupported
+ return 0, r.err
+ }
+ // Section 4.4 Padding (chunk type 0xfe).
+ // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
+ if chunkLen > maxChunkSize {
+ // fmt.Printf("ERR chunkLen: 0x%x\n", chunkLen)
+ r.err = ErrUnsupported
+ return 0, r.err
+ }
+
+ // fmt.Printf("skippable: ID: 0x%x, len: 0x%x\n", chunkType, chunkLen)
+ if !r.skippable(r.buf, chunkLen, false, chunkType) {
+ return 0, r.err
+ }
+ }
+ return 0, r.err
+}
+
+// Skip will skip n bytes forward in the decompressed output.
+// For larger skips this consumes less CPU and is faster than reading output and discarding it.
+// CRC is not checked on skipped blocks.
+// io.ErrUnexpectedEOF is returned if the stream ends before all bytes have been skipped.
+// If a decoding error is encountered subsequent calls to Read will also fail.
+func (r *Reader) Skip(n int64) error {
+ if n < 0 {
+ return errors.New("attempted negative skip")
+ }
+ if r.err != nil {
+ return r.err
+ }
+
+ for n > 0 {
+ if r.i < r.j {
+ // Skip in buffer.
+ // decoded[i:j] contains decoded bytes that have not yet been passed on.
+ left := int64(r.j - r.i)
+ if left >= n {
+ tmp := int64(r.i) + n
+ if tmp > math.MaxInt32 {
+ return errors.New("s2: internal overflow in skip")
+ }
+ r.i = int(tmp)
+ return nil
+ }
+ n -= int64(r.j - r.i)
+ r.i = r.j
+ }
+
+ // Buffer empty; read blocks until we have content.
+ if !r.readFull(r.buf[:4], true) {
+ if r.err == io.EOF {
+ r.err = io.ErrUnexpectedEOF
+ }
+ return r.err
+ }
+ chunkType := r.buf[0]
+ if !r.readHeader {
+ if chunkType != chunkTypeStreamIdentifier {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ r.readHeader = true
+ }
+ chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
+
+ // The chunk types are specified at
+ // https://github.com/google/snappy/blob/master/framing_format.txt
+ switch chunkType {
+ case chunkTypeCompressedData:
+ r.blockStart += int64(r.j)
+ // Section 4.2. Compressed data (chunk type 0x00).
+ if chunkLen < checksumSize {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ if !r.ensureBufferSize(chunkLen) {
+ if r.err == nil {
+ r.err = ErrUnsupported
+ }
+ return r.err
+ }
+ buf := r.buf[:chunkLen]
+ if !r.readFull(buf, false) {
+ return r.err
+ }
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ buf = buf[checksumSize:]
+
+ dLen, err := DecodedLen(buf)
+ if err != nil {
+ r.err = err
+ return r.err
+ }
+ if dLen > r.maxBlock {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ // Check if destination is within this block
+ if int64(dLen) > n {
+ if len(r.decoded) < dLen {
+ r.decoded = make([]byte, dLen)
+ }
+ if _, err := Decode(r.decoded, buf); err != nil {
+ r.err = err
+ return r.err
+ }
+ if crc(r.decoded[:dLen]) != checksum {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ } else {
+ // Skip block completely
+ n -= int64(dLen)
+ r.blockStart += int64(dLen)
+ dLen = 0
+ }
+ r.i, r.j = 0, dLen
+ continue
+ case chunkTypeUncompressedData:
+ r.blockStart += int64(r.j)
+ // Section 4.3. Uncompressed data (chunk type 0x01).
+ if chunkLen < checksumSize {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ if !r.ensureBufferSize(chunkLen) {
+ if r.err != nil {
+ r.err = ErrUnsupported
+ }
+ return r.err
+ }
+ buf := r.buf[:checksumSize]
+ if !r.readFull(buf, false) {
+ return r.err
+ }
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ // Read directly into r.decoded instead of via r.buf.
+ n2 := chunkLen - checksumSize
+ if n2 > len(r.decoded) {
+ if n2 > r.maxBlock {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ r.decoded = make([]byte, n2)
+ }
+ if !r.readFull(r.decoded[:n2], false) {
+ return r.err
+ }
+ if int64(n2) < n {
+ if crc(r.decoded[:n2]) != checksum {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ }
+ r.i, r.j = 0, n2
+ continue
+ case chunkTypeStreamIdentifier:
+ // Section 4.1. Stream identifier (chunk type 0xff).
+ if chunkLen != len(magicBody) {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ if !r.readFull(r.buf[:len(magicBody)], false) {
+ return r.err
+ }
+ if string(r.buf[:len(magicBody)]) != magicBody {
+ if string(r.buf[:len(magicBody)]) != magicBodySnappy {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ }
+
+ continue
+ }
+
+ if chunkType <= 0x7f {
+ // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
+ r.err = ErrUnsupported
+ return r.err
+ }
+ if chunkLen > maxChunkSize {
+ r.err = ErrUnsupported
+ return r.err
+ }
+ // Section 4.4 Padding (chunk type 0xfe).
+ // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
+ if !r.skippable(r.buf, chunkLen, false, chunkType) {
+ return r.err
+ }
+ }
+ return nil
+}
+
+// ReadSeeker provides random or forward seeking in compressed content.
+// See Reader.ReadSeeker
+type ReadSeeker struct {
+ *Reader
+ readAtMu sync.Mutex
+}
+
+// ReadSeeker will return an io.ReadSeeker and io.ReaderAt
+// compatible version of the reader.
+// If 'random' is specified the returned io.Seeker can be used for
+// random seeking, otherwise only forward seeking is supported.
+// Enabling random seeking requires the original input to support
+// the io.Seeker interface.
+// A custom index can be specified which will be used if supplied.
+// When using a custom index, it will not be read from the input stream.
+// The ReadAt position will affect regular reads and the current position of Seek.
+// So using Read after ReadAt will continue from where the ReadAt stopped.
+// No functions should be used concurrently.
+// The returned ReadSeeker contains a shallow reference to the existing Reader,
+// meaning changes performed to one is reflected in the other.
+func (r *Reader) ReadSeeker(random bool, index []byte) (*ReadSeeker, error) {
+ // Read index if provided.
+ if len(index) != 0 {
+ if r.index == nil {
+ r.index = &Index{}
+ }
+ if _, err := r.index.Load(index); err != nil {
+ return nil, ErrCantSeek{Reason: "loading index returned: " + err.Error()}
+ }
+ }
+
+ // Check if input is seekable
+ rs, ok := r.r.(io.ReadSeeker)
+ if !ok {
+ if !random {
+ return &ReadSeeker{Reader: r}, nil
+ }
+ return nil, ErrCantSeek{Reason: "input stream isn't seekable"}
+ }
+
+ if r.index != nil {
+ // Seekable and index, ok...
+ return &ReadSeeker{Reader: r}, nil
+ }
+
+ // Load from stream.
+ r.index = &Index{}
+
+ // Read current position.
+ pos, err := rs.Seek(0, io.SeekCurrent)
+ if err != nil {
+ return nil, ErrCantSeek{Reason: "seeking input returned: " + err.Error()}
+ }
+ err = r.index.LoadStream(rs)
+ if err != nil {
+ if err == ErrUnsupported {
+ // If we don't require random seeking, reset input and return.
+ if !random {
+ _, err = rs.Seek(pos, io.SeekStart)
+ if err != nil {
+ return nil, ErrCantSeek{Reason: "resetting stream returned: " + err.Error()}
+ }
+ r.index = nil
+ return &ReadSeeker{Reader: r}, nil
+ }
+ return nil, ErrCantSeek{Reason: "input stream does not contain an index"}
+ }
+ return nil, ErrCantSeek{Reason: "reading index returned: " + err.Error()}
+ }
+
+ // reset position.
+ _, err = rs.Seek(pos, io.SeekStart)
+ if err != nil {
+ return nil, ErrCantSeek{Reason: "seeking input returned: " + err.Error()}
+ }
+ return &ReadSeeker{Reader: r}, nil
+}
+
+// Seek allows seeking in compressed data.
+func (r *ReadSeeker) Seek(offset int64, whence int) (int64, error) {
+ if r.err != nil {
+ if !errors.Is(r.err, io.EOF) {
+ return 0, r.err
+ }
+ // Reset on EOF
+ r.err = nil
+ }
+
+ // Calculate absolute offset.
+ absOffset := offset
+
+ switch whence {
+ case io.SeekStart:
+ case io.SeekCurrent:
+ absOffset = r.blockStart + int64(r.i) + offset
+ case io.SeekEnd:
+ if r.index == nil {
+ return 0, ErrUnsupported
+ }
+ absOffset = r.index.TotalUncompressed + offset
+ default:
+ r.err = ErrUnsupported
+ return 0, r.err
+ }
+
+ if absOffset < 0 {
+ return 0, errors.New("seek before start of file")
+ }
+
+ if !r.readHeader {
+ // Make sure we read the header.
+ _, r.err = r.Read([]byte{})
+ if r.err != nil {
+ return 0, r.err
+ }
+ }
+
+ // If we are inside current block no need to seek.
+ // This includes no offset changes.
+ if absOffset >= r.blockStart && absOffset < r.blockStart+int64(r.j) {
+ r.i = int(absOffset - r.blockStart)
+ return r.blockStart + int64(r.i), nil
+ }
+
+ rs, ok := r.r.(io.ReadSeeker)
+ if r.index == nil || !ok {
+ currOffset := r.blockStart + int64(r.i)
+ if absOffset >= currOffset {
+ err := r.Skip(absOffset - currOffset)
+ return r.blockStart + int64(r.i), err
+ }
+ return 0, ErrUnsupported
+ }
+
+ // We can seek and we have an index.
+ c, u, err := r.index.Find(absOffset)
+ if err != nil {
+ return r.blockStart + int64(r.i), err
+ }
+
+ // Seek to next block
+ _, err = rs.Seek(c, io.SeekStart)
+ if err != nil {
+ return 0, err
+ }
+
+ r.i = r.j // Remove rest of current block.
+ r.blockStart = u - int64(r.j) // Adjust current block start for accounting.
+ if u < absOffset {
+ // Forward inside block
+ return absOffset, r.Skip(absOffset - u)
+ }
+ if u > absOffset {
+ return 0, fmt.Errorf("s2 seek: (internal error) u (%d) > absOffset (%d)", u, absOffset)
+ }
+ return absOffset, nil
+}
+
+// ReadAt reads len(p) bytes into p starting at offset off in the
+// underlying input source. It returns the number of bytes
+// read (0 <= n <= len(p)) and any error encountered.
+//
+// When ReadAt returns n < len(p), it returns a non-nil error
+// explaining why more bytes were not returned. In this respect,
+// ReadAt is stricter than Read.
+//
+// Even if ReadAt returns n < len(p), it may use all of p as scratch
+// space during the call. If some data is available but not len(p) bytes,
+// ReadAt blocks until either all the data is available or an error occurs.
+// In this respect ReadAt is different from Read.
+//
+// If the n = len(p) bytes returned by ReadAt are at the end of the
+// input source, ReadAt may return either err == EOF or err == nil.
+//
+// If ReadAt is reading from an input source with a seek offset,
+// ReadAt should not affect nor be affected by the underlying
+// seek offset.
+//
+// Clients of ReadAt can execute parallel ReadAt calls on the
+// same input source. This is however not recommended.
+func (r *ReadSeeker) ReadAt(p []byte, offset int64) (int, error) {
+ r.readAtMu.Lock()
+ defer r.readAtMu.Unlock()
+ _, err := r.Seek(offset, io.SeekStart)
+ if err != nil {
+ return 0, err
+ }
+ n := 0
+ for n < len(p) {
+ n2, err := r.Read(p[n:])
+ if err != nil {
+ // This will include io.EOF
+ return n + n2, err
+ }
+ n += n2
+ }
+ return n, nil
+}
+
+// ReadByte satisfies the io.ByteReader interface.
+func (r *Reader) ReadByte() (byte, error) {
+ if r.err != nil {
+ return 0, r.err
+ }
+ if r.i < r.j {
+ c := r.decoded[r.i]
+ r.i++
+ return c, nil
+ }
+ var tmp [1]byte
+ for range 10 {
+ n, err := r.Read(tmp[:])
+ if err != nil {
+ return 0, err
+ }
+ if n == 1 {
+ return tmp[0], nil
+ }
+ }
+ return 0, io.ErrNoProgress
+}
+
+// SkippableCB will register a callback for chunks with the specified ID.
+// ID must be a Reserved skippable chunks ID, 0x80-0xfd (inclusive).
+// For each chunk with the ID, the callback is called with the content.
+// Any returned non-nil error will abort decompression.
+// Only one callback per ID is supported, latest sent will be used.
+// Sending a nil function will disable previous callbacks.
+// You can peek the stream, triggering the callback, by doing a Read with a 0
+// byte buffer.
+func (r *Reader) SkippableCB(id uint8, fn func(r io.Reader) error) error {
+ if id < 0x80 || id >= chunkTypePadding {
+ return fmt.Errorf("ReaderSkippableCB: Invalid id provided, must be 0x80-0xfe (inclusive)")
+ }
+ r.skippableCB[id-0x80] = fn
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/s2/s2.go b/vendor/github.com/klauspost/compress/s2/s2.go
new file mode 100644
index 00000000000..cbd1ed64d69
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/s2.go
@@ -0,0 +1,151 @@
+// Copyright 2011 The Snappy-Go Authors. All rights reserved.
+// Copyright (c) 2019 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package s2 implements the S2 compression format.
+//
+// S2 is an extension of Snappy. Similar to Snappy S2 is aimed for high throughput,
+// which is why it features concurrent compression for bigger payloads.
+//
+// Decoding is compatible with Snappy compressed content,
+// but content compressed with S2 cannot be decompressed by Snappy.
+//
+// For more information on Snappy/S2 differences see README in: https://github.com/klauspost/compress/tree/master/s2
+//
+// There are actually two S2 formats: block and stream. They are related,
+// but different: trying to decompress block-compressed data as a S2 stream
+// will fail, and vice versa. The block format is the Decode and Encode
+// functions and the stream format is the Reader and Writer types.
+//
+// A "better" compression option is available. This will trade some compression
+// speed
+//
+// The block format, the more common case, is used when the complete size (the
+// number of bytes) of the original data is known upfront, at the time
+// compression starts. The stream format, also known as the framing format, is
+// for when that isn't always true.
+//
+// Blocks to not offer much data protection, so it is up to you to
+// add data validation of decompressed blocks.
+//
+// Streams perform CRC validation of the decompressed data.
+// Stream compression will also be performed on multiple CPU cores concurrently
+// significantly improving throughput.
+package s2
+
+import (
+ "bytes"
+ "hash/crc32"
+
+ "github.com/klauspost/compress/internal/race"
+)
+
+/*
+Each encoded block begins with the varint-encoded length of the decoded data,
+followed by a sequence of chunks. Chunks begin and end on byte boundaries. The
+first byte of each chunk is broken into its 2 least and 6 most significant bits
+called l and m: l ranges in [0, 4) and m ranges in [0, 64). l is the chunk tag.
+Zero means a literal tag. All other values mean a copy tag.
+
+For literal tags:
+ - If m < 60, the next 1 + m bytes are literal bytes.
+ - Otherwise, let n be the little-endian unsigned integer denoted by the next
+ m - 59 bytes. The next 1 + n bytes after that are literal bytes.
+
+For copy tags, length bytes are copied from offset bytes ago, in the style of
+Lempel-Ziv compression algorithms. In particular:
+ - For l == 1, the offset ranges in [0, 1<<11) and the length in [4, 12).
+ The length is 4 + the low 3 bits of m. The high 3 bits of m form bits 8-10
+ of the offset. The next byte is bits 0-7 of the offset.
+ - For l == 2, the offset ranges in [0, 1<<16) and the length in [1, 65).
+ The length is 1 + m. The offset is the little-endian unsigned integer
+ denoted by the next 2 bytes.
+ - For l == 3, the offset ranges in [0, 1<<32) and the length in
+ [1, 65). The length is 1 + m. The offset is the little-endian unsigned
+ integer denoted by the next 4 bytes.
+*/
+const (
+ tagLiteral = 0x00
+ tagCopy1 = 0x01
+ tagCopy2 = 0x02
+ tagCopy4 = 0x03
+)
+
+const (
+ checksumSize = 4
+ chunkHeaderSize = 4
+ magicChunk = "\xff\x06\x00\x00" + magicBody
+ magicChunkSnappy = "\xff\x06\x00\x00" + magicBodySnappy
+ magicBodySnappy = "sNaPpY"
+ magicBody = "S2sTwO"
+
+ // maxBlockSize is the maximum size of the input to encodeBlock.
+ //
+ // For the framing format (Writer type instead of Encode function),
+ // this is the maximum uncompressed size of a block.
+ maxBlockSize = 4 << 20
+
+ // minBlockSize is the minimum size of block setting when creating a writer.
+ minBlockSize = 4 << 10
+
+ skippableFrameHeader = 4
+ maxChunkSize = 1<<24 - 1 // 16777215
+
+ // Default block size
+ defaultBlockSize = 1 << 20
+
+ // maxSnappyBlockSize is the maximum snappy block size.
+ maxSnappyBlockSize = 1 << 16
+
+ obufHeaderLen = checksumSize + chunkHeaderSize
+)
+
+const (
+ chunkTypeCompressedData = 0x00
+ chunkTypeUncompressedData = 0x01
+ ChunkTypeIndex = 0x99
+ chunkTypePadding = 0xfe
+ chunkTypeStreamIdentifier = 0xff
+)
+
+var (
+ crcTable = crc32.MakeTable(crc32.Castagnoli)
+ magicChunkSnappyBytes = []byte(magicChunkSnappy) // Can be passed to functions where it escapes.
+ magicChunkBytes = []byte(magicChunk) // Can be passed to functions where it escapes.
+)
+
+// crc implements the checksum specified in section 3 of
+// https://github.com/google/snappy/blob/master/framing_format.txt
+func crc(b []byte) uint32 {
+ race.ReadSlice(b)
+
+ c := crc32.Update(0, crcTable, b)
+ return c>>15 | c<<17 + 0xa282ead8
+}
+
+// literalExtraSize returns the extra size of encoding n literals.
+// n should be >= 0 and <= math.MaxUint32.
+func literalExtraSize(n int64) int64 {
+ if n == 0 {
+ return 0
+ }
+ switch {
+ case n < 60:
+ return 1
+ case n < 1<<8:
+ return 2
+ case n < 1<<16:
+ return 3
+ case n < 1<<24:
+ return 4
+ default:
+ return 5
+ }
+}
+
+type byter interface {
+ Bytes() []byte
+}
+
+var _ byter = &bytes.Buffer{}
diff --git a/vendor/github.com/klauspost/compress/s2/writer.go b/vendor/github.com/klauspost/compress/s2/writer.go
new file mode 100644
index 00000000000..09f1cff3a96
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2/writer.go
@@ -0,0 +1,1064 @@
+// Copyright 2011 The Snappy-Go Authors. All rights reserved.
+// Copyright (c) 2019+ Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2
+
+import (
+ "crypto/rand"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "runtime"
+ "sync"
+
+ "github.com/klauspost/compress/internal/race"
+)
+
+const (
+ levelUncompressed = iota + 1
+ levelFast
+ levelBetter
+ levelBest
+)
+
+// NewWriter returns a new Writer that compresses to w, using the
+// framing format described at
+// https://github.com/google/snappy/blob/master/framing_format.txt
+//
+// Users must call Close to guarantee all data has been forwarded to
+// the underlying io.Writer and that resources are released.
+// They may also call Flush zero or more times before calling Close.
+func NewWriter(w io.Writer, opts ...WriterOption) *Writer {
+ w2 := Writer{
+ blockSize: defaultBlockSize,
+ concurrency: runtime.GOMAXPROCS(0),
+ randSrc: rand.Reader,
+ level: levelFast,
+ }
+ for _, opt := range opts {
+ if err := opt(&w2); err != nil {
+ w2.errState = err
+ return &w2
+ }
+ }
+ w2.obufLen = obufHeaderLen + MaxEncodedLen(w2.blockSize)
+ w2.paramsOK = true
+ w2.ibuf = make([]byte, 0, w2.blockSize)
+ w2.buffers.New = func() any {
+ return make([]byte, w2.obufLen)
+ }
+ w2.Reset(w)
+ return &w2
+}
+
+// Writer is an io.Writer that can write Snappy-compressed bytes.
+type Writer struct {
+ errMu sync.Mutex
+ errState error
+
+ // ibuf is a buffer for the incoming (uncompressed) bytes.
+ ibuf []byte
+
+ blockSize int
+ obufLen int
+ concurrency int
+ written int64
+ uncompWritten int64 // Bytes sent to compression
+ output chan chan result
+ buffers sync.Pool
+ pad int
+
+ writer io.Writer
+ randSrc io.Reader
+ writerWg sync.WaitGroup
+ index Index
+ customEnc func(dst, src []byte) int
+
+ // wroteStreamHeader is whether we have written the stream header.
+ wroteStreamHeader bool
+ paramsOK bool
+ snappy bool
+ flushOnWrite bool
+ appendIndex bool
+ bufferCB func([]byte)
+ level uint8
+}
+
+type result struct {
+ b []byte
+ // return when writing
+ ret []byte
+ // Uncompressed start offset
+ startOffset int64
+}
+
+// err returns the previously set error.
+// If no error has been set it is set to err if not nil.
+func (w *Writer) err(err error) error {
+ w.errMu.Lock()
+ errSet := w.errState
+ if errSet == nil && err != nil {
+ w.errState = err
+ errSet = err
+ }
+ w.errMu.Unlock()
+ return errSet
+}
+
+// Reset discards the writer's state and switches the Snappy writer to write to w.
+// This permits reusing a Writer rather than allocating a new one.
+func (w *Writer) Reset(writer io.Writer) {
+ if !w.paramsOK {
+ return
+ }
+ // Close previous writer, if any.
+ if w.output != nil {
+ close(w.output)
+ w.writerWg.Wait()
+ w.output = nil
+ }
+ w.errState = nil
+ w.ibuf = w.ibuf[:0]
+ w.wroteStreamHeader = false
+ w.written = 0
+ w.writer = writer
+ w.uncompWritten = 0
+ w.index.reset(w.blockSize)
+
+ // If we didn't get a writer, stop here.
+ if writer == nil {
+ return
+ }
+ // If no concurrency requested, don't spin up writer goroutine.
+ if w.concurrency == 1 {
+ return
+ }
+
+ toWrite := make(chan chan result, w.concurrency)
+ w.output = toWrite
+ w.writerWg.Add(1)
+
+ // Start a writer goroutine that will write all output in order.
+ go func() {
+ defer w.writerWg.Done()
+
+ // Get a queued write.
+ for write := range toWrite {
+ // Wait for the data to be available.
+ input := <-write
+ if input.ret != nil && w.bufferCB != nil {
+ w.bufferCB(input.ret)
+ input.ret = nil
+ }
+ in := input.b
+ if len(in) > 0 {
+ if w.err(nil) == nil {
+ // Don't expose data from previous buffers.
+ toWrite := in[:len(in):len(in)]
+ // Write to output.
+ n, err := writer.Write(toWrite)
+ if err == nil && n != len(toWrite) {
+ err = io.ErrShortBuffer
+ }
+ _ = w.err(err)
+ w.err(w.index.add(w.written, input.startOffset))
+ w.written += int64(n)
+ }
+ }
+ if cap(in) >= w.obufLen {
+ w.buffers.Put(in)
+ }
+ // close the incoming write request.
+ // This can be used for synchronizing flushes.
+ close(write)
+ }
+ }()
+}
+
+// Write satisfies the io.Writer interface.
+func (w *Writer) Write(p []byte) (nRet int, errRet error) {
+ if err := w.err(nil); err != nil {
+ return 0, err
+ }
+ if w.flushOnWrite {
+ return w.write(p)
+ }
+ // If we exceed the input buffer size, start writing
+ for len(p) > (cap(w.ibuf)-len(w.ibuf)) && w.err(nil) == nil {
+ var n int
+ if len(w.ibuf) == 0 {
+ // Large write, empty buffer.
+ // Write directly from p to avoid copy.
+ n, _ = w.write(p)
+ } else {
+ n = copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
+ w.ibuf = w.ibuf[:len(w.ibuf)+n]
+ w.write(w.ibuf)
+ w.ibuf = w.ibuf[:0]
+ }
+ nRet += n
+ p = p[n:]
+ }
+ if err := w.err(nil); err != nil {
+ return nRet, err
+ }
+ // p should always be able to fit into w.ibuf now.
+ n := copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
+ w.ibuf = w.ibuf[:len(w.ibuf)+n]
+ nRet += n
+ return nRet, nil
+}
+
+// ReadFrom implements the io.ReaderFrom interface.
+// Using this is typically more efficient since it avoids a memory copy.
+// ReadFrom reads data from r until EOF or error.
+// The return value n is the number of bytes read.
+// Any error except io.EOF encountered during the read is also returned.
+func (w *Writer) ReadFrom(r io.Reader) (n int64, err error) {
+ if err := w.err(nil); err != nil {
+ return 0, err
+ }
+ if len(w.ibuf) > 0 {
+ err := w.AsyncFlush()
+ if err != nil {
+ return 0, err
+ }
+ }
+ if br, ok := r.(byter); ok {
+ buf := br.Bytes()
+ if err := w.EncodeBuffer(buf); err != nil {
+ return 0, err
+ }
+ return int64(len(buf)), w.AsyncFlush()
+ }
+ for {
+ inbuf := w.buffers.Get().([]byte)[:w.blockSize+obufHeaderLen]
+ n2, err := io.ReadFull(r, inbuf[obufHeaderLen:])
+ if err != nil {
+ if err == io.ErrUnexpectedEOF {
+ err = io.EOF
+ }
+ if err != io.EOF {
+ return n, w.err(err)
+ }
+ }
+ if n2 == 0 {
+ if cap(inbuf) >= w.obufLen {
+ w.buffers.Put(inbuf)
+ }
+ break
+ }
+ n += int64(n2)
+ err2 := w.writeFull(inbuf[:n2+obufHeaderLen])
+ if w.err(err2) != nil {
+ break
+ }
+
+ if err != nil {
+ // We got EOF and wrote everything
+ break
+ }
+ }
+
+ return n, w.err(nil)
+}
+
+// AddSkippableBlock will add a skippable block to the stream.
+// The ID must be 0x80-0xfe (inclusive).
+// Length of the skippable block must be <= 16777215 bytes.
+func (w *Writer) AddSkippableBlock(id uint8, data []byte) (err error) {
+ if err := w.err(nil); err != nil {
+ return err
+ }
+ if len(data) == 0 {
+ return nil
+ }
+ if id < 0x80 || id > chunkTypePadding {
+ return fmt.Errorf("invalid skippable block id %x", id)
+ }
+ if len(data) > maxChunkSize {
+ return fmt.Errorf("skippable block excessed maximum size")
+ }
+ var header [4]byte
+ chunkLen := len(data)
+ header[0] = id
+ header[1] = uint8(chunkLen >> 0)
+ header[2] = uint8(chunkLen >> 8)
+ header[3] = uint8(chunkLen >> 16)
+ if w.concurrency == 1 {
+ write := func(b []byte) error {
+ n, err := w.writer.Write(b)
+ if err = w.err(err); err != nil {
+ return err
+ }
+ if n != len(b) {
+ return w.err(io.ErrShortWrite)
+ }
+ w.written += int64(n)
+ return w.err(nil)
+ }
+ if !w.wroteStreamHeader {
+ w.wroteStreamHeader = true
+ if w.snappy {
+ if err := write([]byte(magicChunkSnappy)); err != nil {
+ return err
+ }
+ } else {
+ if err := write([]byte(magicChunk)); err != nil {
+ return err
+ }
+ }
+ }
+ if err := write(header[:]); err != nil {
+ return err
+ }
+ return write(data)
+ }
+
+ // Create output...
+ if !w.wroteStreamHeader {
+ w.wroteStreamHeader = true
+ hWriter := make(chan result)
+ w.output <- hWriter
+ if w.snappy {
+ hWriter <- result{startOffset: w.uncompWritten, b: magicChunkSnappyBytes}
+ } else {
+ hWriter <- result{startOffset: w.uncompWritten, b: magicChunkBytes}
+ }
+ }
+
+ // Copy input.
+ inbuf := w.buffers.Get().([]byte)[:4]
+ copy(inbuf, header[:])
+ inbuf = append(inbuf, data...)
+
+ output := make(chan result, 1)
+ // Queue output.
+ w.output <- output
+ output <- result{startOffset: w.uncompWritten, b: inbuf}
+
+ return nil
+}
+
+// EncodeBuffer will add a buffer to the stream.
+// This is the fastest way to encode a stream,
+// but the input buffer cannot be written to by the caller
+// until Flush or Close has been called when concurrency != 1.
+//
+// Use the WriterBufferDone to receive a callback when the buffer is done
+// Processing.
+//
+// Note that input is not buffered.
+// This means that each write will result in discrete blocks being created.
+// For buffered writes, use the regular Write function.
+func (w *Writer) EncodeBuffer(buf []byte) (err error) {
+ if err := w.err(nil); err != nil {
+ return err
+ }
+
+ if w.flushOnWrite {
+ _, err := w.write(buf)
+ return err
+ }
+ // Flush queued data first.
+ if len(w.ibuf) > 0 {
+ err := w.AsyncFlush()
+ if err != nil {
+ return err
+ }
+ }
+ if w.concurrency == 1 {
+ _, err := w.writeSync(buf)
+ if w.bufferCB != nil {
+ w.bufferCB(buf)
+ }
+ return err
+ }
+
+ // Spawn goroutine and write block to output channel.
+ if !w.wroteStreamHeader {
+ w.wroteStreamHeader = true
+ hWriter := make(chan result)
+ w.output <- hWriter
+ if w.snappy {
+ hWriter <- result{startOffset: w.uncompWritten, b: magicChunkSnappyBytes}
+ } else {
+ hWriter <- result{startOffset: w.uncompWritten, b: magicChunkBytes}
+ }
+ }
+ orgBuf := buf
+ for len(buf) > 0 {
+ // Cut input.
+ uncompressed := buf
+ if len(uncompressed) > w.blockSize {
+ uncompressed = uncompressed[:w.blockSize]
+ }
+ buf = buf[len(uncompressed):]
+ // Get an output buffer.
+ obuf := w.buffers.Get().([]byte)[:len(uncompressed)+obufHeaderLen]
+ race.WriteSlice(obuf)
+
+ output := make(chan result)
+ // Queue output now, so we keep order.
+ w.output <- output
+ res := result{
+ startOffset: w.uncompWritten,
+ }
+ w.uncompWritten += int64(len(uncompressed))
+ if len(buf) == 0 && w.bufferCB != nil {
+ res.ret = orgBuf
+ }
+ go func() {
+ race.ReadSlice(uncompressed)
+
+ checksum := crc(uncompressed)
+
+ // Set to uncompressed.
+ chunkType := uint8(chunkTypeUncompressedData)
+ chunkLen := 4 + len(uncompressed)
+
+ // Attempt compressing.
+ n := binary.PutUvarint(obuf[obufHeaderLen:], uint64(len(uncompressed)))
+ n2 := w.encodeBlock(obuf[obufHeaderLen+n:], uncompressed)
+
+ // Check if we should use this, or store as uncompressed instead.
+ if n2 > 0 {
+ chunkType = uint8(chunkTypeCompressedData)
+ chunkLen = 4 + n + n2
+ obuf = obuf[:obufHeaderLen+n+n2]
+ } else {
+ // copy uncompressed
+ copy(obuf[obufHeaderLen:], uncompressed)
+ }
+
+ // Fill in the per-chunk header that comes before the body.
+ obuf[0] = chunkType
+ obuf[1] = uint8(chunkLen >> 0)
+ obuf[2] = uint8(chunkLen >> 8)
+ obuf[3] = uint8(chunkLen >> 16)
+ obuf[4] = uint8(checksum >> 0)
+ obuf[5] = uint8(checksum >> 8)
+ obuf[6] = uint8(checksum >> 16)
+ obuf[7] = uint8(checksum >> 24)
+
+ // Queue final output.
+ res.b = obuf
+ output <- res
+ }()
+ }
+ return nil
+}
+
+func (w *Writer) encodeBlock(obuf, uncompressed []byte) int {
+ if w.customEnc != nil {
+ if ret := w.customEnc(obuf, uncompressed); ret >= 0 {
+ return ret
+ }
+ }
+ if w.snappy {
+ switch w.level {
+ case levelFast:
+ return encodeBlockSnappy(obuf, uncompressed)
+ case levelBetter:
+ return encodeBlockBetterSnappy(obuf, uncompressed)
+ case levelBest:
+ return encodeBlockBestSnappy(obuf, uncompressed)
+ }
+ return 0
+ }
+ switch w.level {
+ case levelFast:
+ return encodeBlock(obuf, uncompressed)
+ case levelBetter:
+ return encodeBlockBetter(obuf, uncompressed)
+ case levelBest:
+ return encodeBlockBest(obuf, uncompressed, nil)
+ }
+ return 0
+}
+
+func (w *Writer) write(p []byte) (nRet int, errRet error) {
+ if err := w.err(nil); err != nil {
+ return 0, err
+ }
+ if w.concurrency == 1 {
+ return w.writeSync(p)
+ }
+
+ // Spawn goroutine and write block to output channel.
+ for len(p) > 0 {
+ if !w.wroteStreamHeader {
+ w.wroteStreamHeader = true
+ hWriter := make(chan result)
+ w.output <- hWriter
+ if w.snappy {
+ hWriter <- result{startOffset: w.uncompWritten, b: magicChunkSnappyBytes}
+ } else {
+ hWriter <- result{startOffset: w.uncompWritten, b: magicChunkBytes}
+ }
+ }
+
+ var uncompressed []byte
+ if len(p) > w.blockSize {
+ uncompressed, p = p[:w.blockSize], p[w.blockSize:]
+ } else {
+ uncompressed, p = p, nil
+ }
+
+ // Copy input.
+ // If the block is incompressible, this is used for the result.
+ inbuf := w.buffers.Get().([]byte)[:len(uncompressed)+obufHeaderLen]
+ obuf := w.buffers.Get().([]byte)[:w.obufLen]
+ copy(inbuf[obufHeaderLen:], uncompressed)
+ uncompressed = inbuf[obufHeaderLen:]
+
+ output := make(chan result)
+ // Queue output now, so we keep order.
+ w.output <- output
+ res := result{
+ startOffset: w.uncompWritten,
+ }
+ w.uncompWritten += int64(len(uncompressed))
+
+ go func() {
+ checksum := crc(uncompressed)
+
+ // Set to uncompressed.
+ chunkType := uint8(chunkTypeUncompressedData)
+ chunkLen := 4 + len(uncompressed)
+
+ // Attempt compressing.
+ n := binary.PutUvarint(obuf[obufHeaderLen:], uint64(len(uncompressed)))
+ n2 := w.encodeBlock(obuf[obufHeaderLen+n:], uncompressed)
+
+ // Check if we should use this, or store as uncompressed instead.
+ if n2 > 0 {
+ chunkType = uint8(chunkTypeCompressedData)
+ chunkLen = 4 + n + n2
+ obuf = obuf[:obufHeaderLen+n+n2]
+ } else {
+ // Use input as output.
+ obuf, inbuf = inbuf, obuf
+ }
+
+ // Fill in the per-chunk header that comes before the body.
+ obuf[0] = chunkType
+ obuf[1] = uint8(chunkLen >> 0)
+ obuf[2] = uint8(chunkLen >> 8)
+ obuf[3] = uint8(chunkLen >> 16)
+ obuf[4] = uint8(checksum >> 0)
+ obuf[5] = uint8(checksum >> 8)
+ obuf[6] = uint8(checksum >> 16)
+ obuf[7] = uint8(checksum >> 24)
+
+ // Queue final output.
+ res.b = obuf
+ output <- res
+
+ // Put unused buffer back in pool.
+ w.buffers.Put(inbuf)
+ }()
+ nRet += len(uncompressed)
+ }
+ return nRet, nil
+}
+
+// writeFull is a special version of write that will always write the full buffer.
+// Data to be compressed should start at offset obufHeaderLen and fill the remainder of the buffer.
+// The data will be written as a single block.
+// The caller is not allowed to use inbuf after this function has been called.
+func (w *Writer) writeFull(inbuf []byte) (errRet error) {
+ if err := w.err(nil); err != nil {
+ return err
+ }
+
+ if w.concurrency == 1 {
+ _, err := w.writeSync(inbuf[obufHeaderLen:])
+ if cap(inbuf) >= w.obufLen {
+ w.buffers.Put(inbuf)
+ }
+ return err
+ }
+
+ // Spawn goroutine and write block to output channel.
+ if !w.wroteStreamHeader {
+ w.wroteStreamHeader = true
+ hWriter := make(chan result)
+ w.output <- hWriter
+ if w.snappy {
+ hWriter <- result{startOffset: w.uncompWritten, b: magicChunkSnappyBytes}
+ } else {
+ hWriter <- result{startOffset: w.uncompWritten, b: magicChunkBytes}
+ }
+ }
+
+ // Get an output buffer.
+ obuf := w.buffers.Get().([]byte)[:w.obufLen]
+ uncompressed := inbuf[obufHeaderLen:]
+
+ output := make(chan result)
+ // Queue output now, so we keep order.
+ w.output <- output
+ res := result{
+ startOffset: w.uncompWritten,
+ }
+ w.uncompWritten += int64(len(uncompressed))
+
+ go func() {
+ checksum := crc(uncompressed)
+
+ // Set to uncompressed.
+ chunkType := uint8(chunkTypeUncompressedData)
+ chunkLen := 4 + len(uncompressed)
+
+ // Attempt compressing.
+ n := binary.PutUvarint(obuf[obufHeaderLen:], uint64(len(uncompressed)))
+ n2 := w.encodeBlock(obuf[obufHeaderLen+n:], uncompressed)
+
+ // Check if we should use this, or store as uncompressed instead.
+ if n2 > 0 {
+ chunkType = uint8(chunkTypeCompressedData)
+ chunkLen = 4 + n + n2
+ obuf = obuf[:obufHeaderLen+n+n2]
+ } else {
+ // Use input as output.
+ obuf, inbuf = inbuf, obuf
+ }
+
+ // Fill in the per-chunk header that comes before the body.
+ obuf[0] = chunkType
+ obuf[1] = uint8(chunkLen >> 0)
+ obuf[2] = uint8(chunkLen >> 8)
+ obuf[3] = uint8(chunkLen >> 16)
+ obuf[4] = uint8(checksum >> 0)
+ obuf[5] = uint8(checksum >> 8)
+ obuf[6] = uint8(checksum >> 16)
+ obuf[7] = uint8(checksum >> 24)
+
+ // Queue final output.
+ res.b = obuf
+ output <- res
+
+ // Put unused buffer back in pool.
+ w.buffers.Put(inbuf)
+ }()
+ return nil
+}
+
+func (w *Writer) writeSync(p []byte) (nRet int, errRet error) {
+ if err := w.err(nil); err != nil {
+ return 0, err
+ }
+ if !w.wroteStreamHeader {
+ w.wroteStreamHeader = true
+ var n int
+ var err error
+ if w.snappy {
+ n, err = w.writer.Write(magicChunkSnappyBytes)
+ } else {
+ n, err = w.writer.Write(magicChunkBytes)
+ }
+ if err != nil {
+ return 0, w.err(err)
+ }
+ if n != len(magicChunk) {
+ return 0, w.err(io.ErrShortWrite)
+ }
+ w.written += int64(n)
+ }
+
+ for len(p) > 0 {
+ var uncompressed []byte
+ if len(p) > w.blockSize {
+ uncompressed, p = p[:w.blockSize], p[w.blockSize:]
+ } else {
+ uncompressed, p = p, nil
+ }
+
+ obuf := w.buffers.Get().([]byte)[:w.obufLen]
+ checksum := crc(uncompressed)
+
+ // Set to uncompressed.
+ chunkType := uint8(chunkTypeUncompressedData)
+ chunkLen := 4 + len(uncompressed)
+
+ // Attempt compressing.
+ n := binary.PutUvarint(obuf[obufHeaderLen:], uint64(len(uncompressed)))
+ n2 := w.encodeBlock(obuf[obufHeaderLen+n:], uncompressed)
+
+ if n2 > 0 {
+ chunkType = uint8(chunkTypeCompressedData)
+ chunkLen = 4 + n + n2
+ obuf = obuf[:obufHeaderLen+n+n2]
+ } else {
+ obuf = obuf[:8]
+ }
+
+ // Fill in the per-chunk header that comes before the body.
+ obuf[0] = chunkType
+ obuf[1] = uint8(chunkLen >> 0)
+ obuf[2] = uint8(chunkLen >> 8)
+ obuf[3] = uint8(chunkLen >> 16)
+ obuf[4] = uint8(checksum >> 0)
+ obuf[5] = uint8(checksum >> 8)
+ obuf[6] = uint8(checksum >> 16)
+ obuf[7] = uint8(checksum >> 24)
+
+ n, err := w.writer.Write(obuf)
+ if err != nil {
+ return 0, w.err(err)
+ }
+ if n != len(obuf) {
+ return 0, w.err(io.ErrShortWrite)
+ }
+ w.err(w.index.add(w.written, w.uncompWritten))
+ w.written += int64(n)
+ w.uncompWritten += int64(len(uncompressed))
+
+ if chunkType == chunkTypeUncompressedData {
+ // Write uncompressed data.
+ n, err := w.writer.Write(uncompressed)
+ if err != nil {
+ return 0, w.err(err)
+ }
+ if n != len(uncompressed) {
+ return 0, w.err(io.ErrShortWrite)
+ }
+ w.written += int64(n)
+ }
+ w.buffers.Put(obuf)
+ // Queue final output.
+ nRet += len(uncompressed)
+ }
+ return nRet, nil
+}
+
+// AsyncFlush writes any buffered bytes to a block and starts compressing it.
+// It does not wait for the output has been written as Flush() does.
+func (w *Writer) AsyncFlush() error {
+ if err := w.err(nil); err != nil {
+ return err
+ }
+
+ // Queue any data still in input buffer.
+ if len(w.ibuf) != 0 {
+ if !w.wroteStreamHeader {
+ _, err := w.writeSync(w.ibuf)
+ w.ibuf = w.ibuf[:0]
+ return w.err(err)
+ } else {
+ _, err := w.write(w.ibuf)
+ w.ibuf = w.ibuf[:0]
+ err = w.err(err)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return w.err(nil)
+}
+
+// Flush flushes the Writer to its underlying io.Writer.
+// This does not apply padding.
+func (w *Writer) Flush() error {
+ if err := w.AsyncFlush(); err != nil {
+ return err
+ }
+ if w.output == nil {
+ return w.err(nil)
+ }
+
+ // Send empty buffer
+ res := make(chan result)
+ w.output <- res
+ // Block until this has been picked up.
+ res <- result{b: nil, startOffset: w.uncompWritten}
+ // When it is closed, we have flushed.
+ <-res
+ return w.err(nil)
+}
+
+// Close calls Flush and then closes the Writer.
+// Calling Close multiple times is ok,
+// but calling CloseIndex after this will make it not return the index.
+func (w *Writer) Close() error {
+ _, err := w.closeIndex(w.appendIndex)
+ return err
+}
+
+// CloseIndex calls Close and returns an index on first call.
+// This is not required if you are only adding index to a stream.
+func (w *Writer) CloseIndex() ([]byte, error) {
+ return w.closeIndex(true)
+}
+
+func (w *Writer) closeIndex(idx bool) ([]byte, error) {
+ err := w.Flush()
+ if w.output != nil {
+ close(w.output)
+ w.writerWg.Wait()
+ w.output = nil
+ }
+
+ var index []byte
+ if w.err(err) == nil && w.writer != nil {
+ // Create index.
+ if idx {
+ compSize := int64(-1)
+ if w.pad <= 1 {
+ compSize = w.written
+ }
+ index = w.index.appendTo(w.ibuf[:0], w.uncompWritten, compSize)
+ // Count as written for padding.
+ if w.appendIndex {
+ w.written += int64(len(index))
+ }
+ }
+
+ if w.pad > 1 {
+ tmp := w.ibuf[:0]
+ if len(index) > 0 {
+ // Allocate another buffer.
+ tmp = w.buffers.Get().([]byte)[:0]
+ defer w.buffers.Put(tmp)
+ }
+ add := calcSkippableFrame(w.written, int64(w.pad))
+ frame, err := skippableFrame(tmp, add, w.randSrc)
+ if err = w.err(err); err != nil {
+ return nil, err
+ }
+ n, err2 := w.writer.Write(frame)
+ if err2 == nil && n != len(frame) {
+ err2 = io.ErrShortWrite
+ }
+ _ = w.err(err2)
+ }
+ if len(index) > 0 && w.appendIndex {
+ n, err2 := w.writer.Write(index)
+ if err2 == nil && n != len(index) {
+ err2 = io.ErrShortWrite
+ }
+ _ = w.err(err2)
+ }
+ }
+ err = w.err(errClosed)
+ if err == errClosed {
+ return index, nil
+ }
+ return nil, err
+}
+
+// calcSkippableFrame will return a total size to be added for written
+// to be divisible by multiple.
+// The value will always be > skippableFrameHeader.
+// The function will panic if written < 0 or wantMultiple <= 0.
+func calcSkippableFrame(written, wantMultiple int64) int {
+ if wantMultiple <= 0 {
+ panic("wantMultiple <= 0")
+ }
+ if written < 0 {
+ panic("written < 0")
+ }
+ leftOver := written % wantMultiple
+ if leftOver == 0 {
+ return 0
+ }
+ toAdd := wantMultiple - leftOver
+ for toAdd < skippableFrameHeader {
+ toAdd += wantMultiple
+ }
+ return int(toAdd)
+}
+
+// skippableFrame will add a skippable frame with a total size of bytes.
+// total should be >= skippableFrameHeader and < maxBlockSize + skippableFrameHeader
+func skippableFrame(dst []byte, total int, r io.Reader) ([]byte, error) {
+ if total == 0 {
+ return dst, nil
+ }
+ if total < skippableFrameHeader {
+ return dst, fmt.Errorf("s2: requested skippable frame (%d) < 4", total)
+ }
+ if int64(total) >= maxBlockSize+skippableFrameHeader {
+ return dst, fmt.Errorf("s2: requested skippable frame (%d) >= max 1<<24", total)
+ }
+ // Chunk type 0xfe "Section 4.4 Padding (chunk type 0xfe)"
+ dst = append(dst, chunkTypePadding)
+ f := uint32(total - skippableFrameHeader)
+ // Add chunk length.
+ dst = append(dst, uint8(f), uint8(f>>8), uint8(f>>16))
+ // Add data
+ start := len(dst)
+ dst = append(dst, make([]byte, f)...)
+ _, err := io.ReadFull(r, dst[start:])
+ return dst, err
+}
+
+var errClosed = errors.New("s2: Writer is closed")
+
+// WriterOption is an option for creating a encoder.
+type WriterOption func(*Writer) error
+
+// WriterConcurrency will set the concurrency,
+// meaning the maximum number of decoders to run concurrently.
+// The value supplied must be at least 1.
+// By default this will be set to GOMAXPROCS.
+func WriterConcurrency(n int) WriterOption {
+ return func(w *Writer) error {
+ if n <= 0 {
+ return errors.New("concurrency must be at least 1")
+ }
+ w.concurrency = n
+ return nil
+ }
+}
+
+// WriterAddIndex will append an index to the end of a stream
+// when it is closed.
+func WriterAddIndex() WriterOption {
+ return func(w *Writer) error {
+ w.appendIndex = true
+ return nil
+ }
+}
+
+// WriterBetterCompression will enable better compression.
+// EncodeBetter compresses better than Encode but typically with a
+// 10-40% speed decrease on both compression and decompression.
+func WriterBetterCompression() WriterOption {
+ return func(w *Writer) error {
+ w.level = levelBetter
+ return nil
+ }
+}
+
+// WriterBestCompression will enable better compression.
+// EncodeBest compresses better than Encode but typically with a
+// big speed decrease on compression.
+func WriterBestCompression() WriterOption {
+ return func(w *Writer) error {
+ w.level = levelBest
+ return nil
+ }
+}
+
+// WriterUncompressed will bypass compression.
+// The stream will be written as uncompressed blocks only.
+// If concurrency is > 1 CRC and output will still be done async.
+func WriterUncompressed() WriterOption {
+ return func(w *Writer) error {
+ w.level = levelUncompressed
+ return nil
+ }
+}
+
+// WriterBufferDone will perform a callback when EncodeBuffer has finished
+// writing a buffer to the output and the buffer can safely be reused.
+// If the buffer was split into several blocks, it will be sent after the last block.
+// Callbacks will not be done concurrently.
+func WriterBufferDone(fn func(b []byte)) WriterOption {
+ return func(w *Writer) error {
+ w.bufferCB = fn
+ return nil
+ }
+}
+
+// WriterBlockSize allows to override the default block size.
+// Blocks will be this size or smaller.
+// Minimum size is 4KB and maximum size is 4MB.
+//
+// Bigger blocks may give bigger throughput on systems with many cores,
+// and will increase compression slightly, but it will limit the possible
+// concurrency for smaller payloads for both encoding and decoding.
+// Default block size is 1MB.
+//
+// When writing Snappy compatible output using WriterSnappyCompat,
+// the maximum block size is 64KB.
+func WriterBlockSize(n int) WriterOption {
+ return func(w *Writer) error {
+ if w.snappy && n > maxSnappyBlockSize || n < minBlockSize {
+ return errors.New("s2: block size too large. Must be <= 64K and >=4KB on for snappy compatible output")
+ }
+ if n > maxBlockSize || n < minBlockSize {
+ return errors.New("s2: block size too large. Must be <= 4MB and >=4KB")
+ }
+ w.blockSize = n
+ return nil
+ }
+}
+
+// WriterPadding will add padding to all output so the size will be a multiple of n.
+// This can be used to obfuscate the exact output size or make blocks of a certain size.
+// The contents will be a skippable frame, so it will be invisible by the decoder.
+// n must be > 0 and <= 4MB.
+// The padded area will be filled with data from crypto/rand.Reader.
+// The padding will be applied whenever Close is called on the writer.
+func WriterPadding(n int) WriterOption {
+ return func(w *Writer) error {
+ if n <= 0 {
+ return fmt.Errorf("s2: padding must be at least 1")
+ }
+ // No need to waste our time.
+ if n == 1 {
+ w.pad = 0
+ }
+ if n > maxBlockSize {
+ return fmt.Errorf("s2: padding must less than 4MB")
+ }
+ w.pad = n
+ return nil
+ }
+}
+
+// WriterPaddingSrc will get random data for padding from the supplied source.
+// By default crypto/rand is used.
+func WriterPaddingSrc(reader io.Reader) WriterOption {
+ return func(w *Writer) error {
+ w.randSrc = reader
+ return nil
+ }
+}
+
+// WriterSnappyCompat will write snappy compatible output.
+// The output can be decompressed using either snappy or s2.
+// If block size is more than 64KB it is set to that.
+func WriterSnappyCompat() WriterOption {
+ return func(w *Writer) error {
+ w.snappy = true
+ if w.blockSize > 64<<10 {
+ // We choose 8 bytes less than 64K, since that will make literal emits slightly more effective.
+ // And allows us to skip some size checks.
+ w.blockSize = (64 << 10) - 8
+ }
+ return nil
+ }
+}
+
+// WriterFlushOnWrite will compress blocks on each call to the Write function.
+//
+// This is quite inefficient as blocks size will depend on the write size.
+//
+// Use WriterConcurrency(1) to also make sure that output is flushed.
+// When Write calls return, otherwise they will be written when compression is done.
+func WriterFlushOnWrite() WriterOption {
+ return func(w *Writer) error {
+ w.flushOnWrite = true
+ return nil
+ }
+}
+
+// WriterCustomEncoder allows to override the encoder for blocks on the stream.
+// The function must compress 'src' into 'dst' and return the bytes used in dst as an integer.
+// Block size (initial varint) should not be added by the encoder.
+// Returning value 0 indicates the block could not be compressed.
+// Returning a negative value indicates that compression should be attempted.
+// The function should expect to be called concurrently.
+func WriterCustomEncoder(fn func(dst, src []byte) int) WriterOption {
+ return func(w *Writer) error {
+ w.customEnc = fn
+ return nil
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/s2sx.mod b/vendor/github.com/klauspost/compress/s2sx.mod
new file mode 100644
index 00000000000..81bda5e2946
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2sx.mod
@@ -0,0 +1,3 @@
+module github.com/klauspost/compress
+
+go 1.22
diff --git a/vendor/github.com/klauspost/compress/s2sx.sum b/vendor/github.com/klauspost/compress/s2sx.sum
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md
new file mode 100644
index 00000000000..c11d7fa28e3
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/README.md
@@ -0,0 +1,441 @@
+# zstd
+
+[Zstandard](https://facebook.github.io/zstd/) is a real-time compression algorithm, providing high compression ratios.
+It offers a very wide range of compression / speed trade-off, while being backed by a very fast decoder.
+A high performance compression algorithm is implemented. For now focused on speed.
+
+This package provides [compression](#Compressor) to and [decompression](#Decompressor) of Zstandard content.
+
+This package is pure Go. Use `noasm` and `nounsafe` to disable relevant features.
+
+The `zstd` package is provided as open source software using a Go standard license.
+
+Currently the package is heavily optimized for 64 bit processors and will be significantly slower on 32 bit processors.
+
+For seekable zstd streams, see [this excellent package](https://github.com/SaveTheRbtz/zstd-seekable-format-go).
+
+## Installation
+
+Install using `go get -u github.com/klauspost/compress`. The package is located in `github.com/klauspost/compress/zstd`.
+
+[](https://pkg.go.dev/github.com/klauspost/compress/zstd)
+
+## Compressor
+
+### Status:
+
+STABLE - there may always be subtle bugs, a wide variety of content has been tested and the library is actively
+used by several projects. This library is being [fuzz-tested](https://github.com/klauspost/compress-fuzz) for all updates.
+
+There may still be specific combinations of data types/size/settings that could lead to edge cases,
+so as always, testing is recommended.
+
+For now, a high speed (fastest) and medium-fast (default) compressor has been implemented.
+
+* The "Fastest" compression ratio is roughly equivalent to zstd level 1.
+* The "Default" compression ratio is roughly equivalent to zstd level 3 (default).
+* The "Better" compression ratio is roughly equivalent to zstd level 7.
+* The "Best" compression ratio is roughly equivalent to zstd level 11.
+
+In terms of speed, it is typically 2x as fast as the stdlib deflate/gzip in its fastest mode.
+The compression ratio compared to stdlib is around level 3, but usually 3x as fast.
+
+
+### Usage
+
+An Encoder can be used for either compressing a stream via the
+`io.WriteCloser` interface supported by the Encoder or as multiple independent
+tasks via the `EncodeAll` function.
+Smaller encodes are encouraged to use the EncodeAll function.
+Use `NewWriter` to create a new instance that can be used for both.
+
+To create a writer with default options, do like this:
+
+```Go
+// Compress input to output.
+func Compress(in io.Reader, out io.Writer) error {
+ enc, err := zstd.NewWriter(out)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(enc, in)
+ if err != nil {
+ enc.Close()
+ return err
+ }
+ return enc.Close()
+}
+```
+
+Now you can encode by writing data to `enc`. The output will be finished writing when `Close()` is called.
+Even if your encode fails, you should still call `Close()` to release any resources that may be held up.
+
+The above is fine for big encodes. However, whenever possible try to *reuse* the writer.
+
+To reuse the encoder, you can use the `Reset(io.Writer)` function to change to another output.
+This will allow the encoder to reuse all resources and avoid wasteful allocations.
+
+Currently stream encoding has 'light' concurrency, meaning up to 2 goroutines can be working on part
+of a stream. This is independent of the `WithEncoderConcurrency(n)`, but that is likely to change
+in the future. So if you want to limit concurrency for future updates, specify the concurrency
+you would like.
+
+If you would like stream encoding to be done without spawning async goroutines, use `WithEncoderConcurrency(1)`
+which will compress input as each block is completed, blocking on writes until each has completed.
+
+You can specify your desired compression level using `WithEncoderLevel()` option. Currently only pre-defined
+compression settings can be specified.
+
+#### Future Compatibility Guarantees
+
+This will be an evolving project. When using this package it is important to note that both the compression efficiency and speed may change.
+
+The goal will be to keep the default efficiency at the default zstd (level 3).
+However the encoding should never be assumed to remain the same,
+and you should not use hashes of compressed output for similarity checks.
+
+The Encoder can be assumed to produce the same output from the exact same code version.
+However, the may be modes in the future that break this,
+although they will not be enabled without an explicit option.
+
+This encoder is not designed to (and will probably never) output the exact same bitstream as the reference encoder.
+
+Also note, that the cgo decompressor currently does not [report all errors on invalid input](https://github.com/DataDog/zstd/issues/59),
+[omits error checks](https://github.com/DataDog/zstd/issues/61), [ignores checksums](https://github.com/DataDog/zstd/issues/43)
+and seems to ignore concatenated streams, even though [it is part of the spec](https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frames).
+
+#### Blocks
+
+For compressing small blocks, the returned encoder has a function called `EncodeAll(src, dst []byte) []byte`.
+
+`EncodeAll` will encode all input in src and append it to dst.
+This function can be called concurrently.
+Each call will only run on a same goroutine as the caller.
+
+Encoded blocks can be concatenated and the result will be the combined input stream.
+Data compressed with EncodeAll can be decoded with the Decoder, using either a stream or `DecodeAll`.
+
+Especially when encoding blocks you should take special care to reuse the encoder.
+This will effectively make it run without allocations after a warmup period.
+To make it run completely without allocations, supply a destination buffer with space for all content.
+
+```Go
+import "github.com/klauspost/compress/zstd"
+
+// Create a writer that caches compressors.
+// For this operation type we supply a nil Reader.
+var encoder, _ = zstd.NewWriter(nil)
+
+// Compress a buffer.
+// If you have a destination buffer, the allocation in the call can also be eliminated.
+func Compress(src []byte) []byte {
+ return encoder.EncodeAll(src, make([]byte, 0, len(src)))
+}
+```
+
+You can control the maximum number of concurrent encodes using the `WithEncoderConcurrency(n)`
+option when creating the writer.
+
+Using the Encoder for both a stream and individual blocks concurrently is safe.
+
+### Performance
+
+I have collected some speed examples to compare speed and compression against other compressors.
+
+* `file` is the input file.
+* `out` is the compressor used. `zskp` is this package. `zstd` is the Datadog cgo library. `gzstd/gzkp` is gzip standard and this library.
+* `level` is the compression level used. For `zskp` level 1 is "fastest", level 2 is "default"; 3 is "better", 4 is "best".
+* `insize`/`outsize` is the input/output size.
+* `millis` is the number of milliseconds used for compression.
+* `mb/s` is megabytes (2^20 bytes) per second.
+
+```
+Silesia Corpus:
+http://sun.aei.polsl.pl/~sdeor/corpus/silesia.zip
+
+This package:
+file out level insize outsize millis mb/s
+silesia.tar zskp 1 211947520 73821326 634 318.47
+silesia.tar zskp 2 211947520 67655404 1508 133.96
+silesia.tar zskp 3 211947520 64746933 3000 67.37
+silesia.tar zskp 4 211947520 60073508 16926 11.94
+
+cgo zstd:
+silesia.tar zstd 1 211947520 73605392 543 371.56
+silesia.tar zstd 3 211947520 66793289 864 233.68
+silesia.tar zstd 6 211947520 62916450 1913 105.66
+silesia.tar zstd 9 211947520 60212393 5063 39.92
+
+gzip, stdlib/this package:
+silesia.tar gzstd 1 211947520 80007735 1498 134.87
+silesia.tar gzkp 1 211947520 80088272 1009 200.31
+
+GOB stream of binary data. Highly compressible.
+https://files.klauspost.com/compress/gob-stream.7z
+
+file out level insize outsize millis mb/s
+gob-stream zskp 1 1911399616 233948096 3230 564.34
+gob-stream zskp 2 1911399616 203997694 4997 364.73
+gob-stream zskp 3 1911399616 173526523 13435 135.68
+gob-stream zskp 4 1911399616 162195235 47559 38.33
+
+gob-stream zstd 1 1911399616 249810424 2637 691.26
+gob-stream zstd 3 1911399616 208192146 3490 522.31
+gob-stream zstd 6 1911399616 193632038 6687 272.56
+gob-stream zstd 9 1911399616 177620386 16175 112.70
+
+gob-stream gzstd 1 1911399616 357382013 9046 201.49
+gob-stream gzkp 1 1911399616 359136669 4885 373.08
+
+The test data for the Large Text Compression Benchmark is the first
+10^9 bytes of the English Wikipedia dump on Mar. 3, 2006.
+http://mattmahoney.net/dc/textdata.html
+
+file out level insize outsize millis mb/s
+enwik9 zskp 1 1000000000 343833605 3687 258.64
+enwik9 zskp 2 1000000000 317001237 7672 124.29
+enwik9 zskp 3 1000000000 291915823 15923 59.89
+enwik9 zskp 4 1000000000 261710291 77697 12.27
+
+enwik9 zstd 1 1000000000 358072021 3110 306.65
+enwik9 zstd 3 1000000000 313734672 4784 199.35
+enwik9 zstd 6 1000000000 295138875 10290 92.68
+enwik9 zstd 9 1000000000 278348700 28549 33.40
+
+enwik9 gzstd 1 1000000000 382578136 8608 110.78
+enwik9 gzkp 1 1000000000 382781160 5628 169.45
+
+Highly compressible JSON file.
+https://files.klauspost.com/compress/github-june-2days-2019.json.zst
+
+file out level insize outsize millis mb/s
+github-june-2days-2019.json zskp 1 6273951764 697439532 9789 611.17
+github-june-2days-2019.json zskp 2 6273951764 610876538 18553 322.49
+github-june-2days-2019.json zskp 3 6273951764 517662858 44186 135.41
+github-june-2days-2019.json zskp 4 6273951764 464617114 165373 36.18
+
+github-june-2days-2019.json zstd 1 6273951764 766284037 8450 708.00
+github-june-2days-2019.json zstd 3 6273951764 661889476 10927 547.57
+github-june-2days-2019.json zstd 6 6273951764 642756859 22996 260.18
+github-june-2days-2019.json zstd 9 6273951764 601974523 52413 114.16
+
+github-june-2days-2019.json gzstd 1 6273951764 1164397768 26793 223.32
+github-june-2days-2019.json gzkp 1 6273951764 1120631856 17693 338.16
+
+VM Image, Linux mint with a few installed applications:
+https://files.klauspost.com/compress/rawstudio-mint14.7z
+
+file out level insize outsize millis mb/s
+rawstudio-mint14.tar zskp 1 8558382592 3718400221 18206 448.29
+rawstudio-mint14.tar zskp 2 8558382592 3326118337 37074 220.15
+rawstudio-mint14.tar zskp 3 8558382592 3163842361 87306 93.49
+rawstudio-mint14.tar zskp 4 8558382592 2970480650 783862 10.41
+
+rawstudio-mint14.tar zstd 1 8558382592 3609250104 17136 476.27
+rawstudio-mint14.tar zstd 3 8558382592 3341679997 29262 278.92
+rawstudio-mint14.tar zstd 6 8558382592 3235846406 77904 104.77
+rawstudio-mint14.tar zstd 9 8558382592 3160778861 140946 57.91
+
+rawstudio-mint14.tar gzstd 1 8558382592 3926234992 51345 158.96
+rawstudio-mint14.tar gzkp 1 8558382592 3960117298 36722 222.26
+
+CSV data:
+https://files.klauspost.com/compress/nyc-taxi-data-10M.csv.zst
+
+file out level insize outsize millis mb/s
+nyc-taxi-data-10M.csv zskp 1 3325605752 641319332 9462 335.17
+nyc-taxi-data-10M.csv zskp 2 3325605752 588976126 17570 180.50
+nyc-taxi-data-10M.csv zskp 3 3325605752 529329260 32432 97.79
+nyc-taxi-data-10M.csv zskp 4 3325605752 474949772 138025 22.98
+
+nyc-taxi-data-10M.csv zstd 1 3325605752 687399637 8233 385.18
+nyc-taxi-data-10M.csv zstd 3 3325605752 598514411 10065 315.07
+nyc-taxi-data-10M.csv zstd 6 3325605752 570522953 20038 158.27
+nyc-taxi-data-10M.csv zstd 9 3325605752 517554797 64565 49.12
+
+nyc-taxi-data-10M.csv gzstd 1 3325605752 928654908 21270 149.11
+nyc-taxi-data-10M.csv gzkp 1 3325605752 922273214 13929 227.68
+```
+
+## Decompressor
+
+Status: STABLE - there may still be subtle bugs, but a wide variety of content has been tested.
+
+This library is being continuously [fuzz-tested](https://github.com/klauspost/compress-fuzz),
+kindly supplied by [fuzzit.dev](https://fuzzit.dev/).
+The main purpose of the fuzz testing is to ensure that it is not possible to crash the decoder,
+or run it past its limits with ANY input provided.
+
+### Usage
+
+The package has been designed for two main usages, big streams of data and smaller in-memory buffers.
+There are two main usages of the package for these. Both of them are accessed by creating a `Decoder`.
+
+For streaming use a simple setup could look like this:
+
+```Go
+import "github.com/klauspost/compress/zstd"
+
+func Decompress(in io.Reader, out io.Writer) error {
+ d, err := zstd.NewReader(in)
+ if err != nil {
+ return err
+ }
+ defer d.Close()
+
+ // Copy content...
+ _, err = io.Copy(out, d)
+ return err
+}
+```
+
+It is important to use the "Close" function when you no longer need the Reader to stop running goroutines,
+when running with default settings.
+Goroutines will exit once an error has been returned, including `io.EOF` at the end of a stream.
+
+Streams are decoded concurrently in 4 asynchronous stages to give the best possible throughput.
+However, if you prefer synchronous decompression, use `WithDecoderConcurrency(1)` which will decompress data
+as it is being requested only.
+
+For decoding buffers, it could look something like this:
+
+```Go
+import "github.com/klauspost/compress/zstd"
+
+// Create a reader that caches decompressors.
+// For this operation type we supply a nil Reader.
+var decoder, _ = zstd.NewReader(nil, zstd.WithDecoderConcurrency(0))
+
+// Decompress a buffer. We don't supply a destination buffer,
+// so it will be allocated by the decoder.
+func Decompress(src []byte) ([]byte, error) {
+ return decoder.DecodeAll(src, nil)
+}
+```
+
+Both of these cases should provide the functionality needed.
+The decoder can be used for *concurrent* decompression of multiple buffers.
+By default 4 decompressors will be created.
+
+It will only allow a certain number of concurrent operations to run.
+To tweak that yourself use the `WithDecoderConcurrency(n)` option when creating the decoder.
+It is possible to use `WithDecoderConcurrency(0)` to create GOMAXPROCS decoders.
+
+### Dictionaries
+
+Data compressed with [dictionaries](https://github.com/facebook/zstd#the-case-for-small-data-compression) can be decompressed.
+
+Dictionaries are added individually to Decoders.
+Dictionaries are generated by the `zstd --train` command and contains an initial state for the decoder.
+To add a dictionary use the `WithDecoderDicts(dicts ...[]byte)` option with the dictionary data.
+Several dictionaries can be added at once.
+
+The dictionary will be used automatically for the data that specifies them.
+A re-used Decoder will still contain the dictionaries registered.
+
+When registering multiple dictionaries with the same ID, the last one will be used.
+
+It is possible to use dictionaries when compressing data.
+
+To enable a dictionary use `WithEncoderDict(dict []byte)`. Here only one dictionary will be used
+and it will likely be used even if it doesn't improve compression.
+
+The used dictionary must be used to decompress the content.
+
+For any real gains, the dictionary should be built with similar data.
+If an unsuitable dictionary is used the output may be slightly larger than using no dictionary.
+Use the [zstd commandline tool](https://github.com/facebook/zstd/releases) to build a dictionary from sample data.
+For information see [zstd dictionary information](https://github.com/facebook/zstd#the-case-for-small-data-compression).
+
+For now there is a fixed startup performance penalty for compressing content with dictionaries.
+This will likely be improved over time. Just be aware to test performance when implementing.
+
+### Allocation-less operation
+
+The decoder has been designed to operate without allocations after a warmup.
+
+This means that you should *store* the decoder for best performance.
+To re-use a stream decoder, use the `Reset(r io.Reader) error` to switch to another stream.
+A decoder can safely be re-used even if the previous stream failed.
+
+To release the resources, you must call the `Close()` function on a decoder.
+After this it can *no longer be reused*, but all running goroutines will be stopped.
+So you *must* use this if you will no longer need the Reader.
+
+For decompressing smaller buffers a single decoder can be used.
+When decoding buffers, you can supply a destination slice with length 0 and your expected capacity.
+In this case no unneeded allocations should be made.
+
+### Concurrency
+
+The buffer decoder does everything on the same goroutine and does nothing concurrently.
+It can however decode several buffers concurrently. Use `WithDecoderConcurrency(n)` to limit that.
+
+The stream decoder will create goroutines that:
+
+1) Reads input and splits the input into blocks.
+2) Decompression of literals.
+3) Decompression of sequences.
+4) Reconstruction of output stream.
+
+So effectively this also means the decoder will "read ahead" and prepare data to always be available for output.
+
+The concurrency level will, for streams, determine how many blocks ahead the compression will start.
+
+Since "blocks" are quite dependent on the output of the previous block stream decoding will only have limited concurrency.
+
+In practice this means that concurrency is often limited to utilizing about 3 cores effectively.
+
+### Benchmarks
+
+The first two are streaming decodes and the last are smaller inputs.
+
+Running on AMD Ryzen 9 3950X 16-Core Processor. AMD64 assembly used.
+
+```
+BenchmarkDecoderSilesia-32 5 206878840 ns/op 1024.50 MB/s 49808 B/op 43 allocs/op
+BenchmarkDecoderEnwik9-32 1 1271809000 ns/op 786.28 MB/s 72048 B/op 52 allocs/op
+
+Concurrent blocks, performance:
+
+BenchmarkDecoder_DecodeAllParallel/kppkn.gtb.zst-32 67356 17857 ns/op 10321.96 MB/s 22.48 pct 102 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/geo.protodata.zst-32 266656 4421 ns/op 26823.21 MB/s 11.89 pct 19 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/plrabn12.txt.zst-32 20992 56842 ns/op 8477.17 MB/s 39.90 pct 754 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/lcet10.txt.zst-32 27456 43932 ns/op 9714.01 MB/s 33.27 pct 524 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/asyoulik.txt.zst-32 78432 15047 ns/op 8319.15 MB/s 40.34 pct 66 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/alice29.txt.zst-32 65800 18436 ns/op 8249.63 MB/s 37.75 pct 88 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/html_x_4.zst-32 102993 11523 ns/op 35546.09 MB/s 3.637 pct 143 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/paper-100k.pdf.zst-32 1000000 1070 ns/op 95720.98 MB/s 80.53 pct 3 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/fireworks.jpeg.zst-32 749802 1752 ns/op 70272.35 MB/s 100.0 pct 5 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/urls.10K.zst-32 22640 52934 ns/op 13263.37 MB/s 26.25 pct 1014 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/html.zst-32 226412 5232 ns/op 19572.27 MB/s 14.49 pct 20 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/comp-data.bin.zst-32 923041 1276 ns/op 3194.71 MB/s 31.26 pct 0 B/op 0 allocs/op
+```
+
+This reflects the performance around May 2022, but this may be out of date.
+
+## Zstd inside ZIP files
+
+It is possible to use zstandard to compress individual files inside zip archives.
+While this isn't widely supported it can be useful for internal files.
+
+To support the compression and decompression of these files you must register a compressor and decompressor.
+
+It is highly recommended registering the (de)compressors on individual zip Reader/Writer and NOT
+use the global registration functions. The main reason for this is that 2 registrations from
+different packages will result in a panic.
+
+It is a good idea to only have a single compressor and decompressor, since they can be used for multiple zip
+files concurrently, and using a single instance will allow reusing some resources.
+
+See [this example](https://pkg.go.dev/github.com/klauspost/compress/zstd#example-ZipCompressor) for
+how to compress and decompress files inside zip archives.
+
+# Contributions
+
+Contributions are always welcome.
+For new features/fixes, remember to add tests and for performance enhancements include benchmarks.
+
+For general feedback and experience reports, feel free to open an issue or write me on [Twitter](https://twitter.com/sh0dan).
+
+This package includes the excellent [`github.com/cespare/xxhash`](https://github.com/cespare/xxhash) package Copyright (c) 2016 Caleb Spare.
diff --git a/vendor/github.com/klauspost/compress/zstd/bitreader.go b/vendor/github.com/klauspost/compress/zstd/bitreader.go
new file mode 100644
index 00000000000..d41e3e1709b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/bitreader.go
@@ -0,0 +1,135 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "math/bits"
+
+ "github.com/klauspost/compress/internal/le"
+)
+
+// bitReader reads a bitstream in reverse.
+// The last set bit indicates the start of the stream and is used
+// for aligning the input.
+type bitReader struct {
+ in []byte
+ value uint64 // Maybe use [16]byte, but shifting is awkward.
+ cursor int // offset where next read should end
+ bitsRead uint8
+}
+
+// init initializes and resets the bit reader.
+func (b *bitReader) init(in []byte) error {
+ if len(in) < 1 {
+ return errors.New("corrupt stream: too short")
+ }
+ b.in = in
+ // The highest bit of the last byte indicates where to start
+ v := in[len(in)-1]
+ if v == 0 {
+ return errors.New("corrupt stream, did not find end of stream")
+ }
+ b.cursor = len(in)
+ b.bitsRead = 64
+ b.value = 0
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
+ b.bitsRead += 8 - uint8(highBits(uint32(v)))
+ return nil
+}
+
+// getBits will return n bits. n can be 0.
+func (b *bitReader) getBits(n uint8) int {
+ if n == 0 /*|| b.bitsRead >= 64 */ {
+ return 0
+ }
+ return int(b.get32BitsFast(n))
+}
+
+// get32BitsFast requires that at least one bit is requested every time.
+// There are no checks if the buffer is filled.
+func (b *bitReader) get32BitsFast(n uint8) uint32 {
+ const regMask = 64 - 1
+ v := uint32((b.value << (b.bitsRead & regMask)) >> ((regMask + 1 - n) & regMask))
+ b.bitsRead += n
+ return v
+}
+
+// fillFast() will make sure at least 32 bits are available.
+// There must be at least 4 bytes available.
+func (b *bitReader) fillFast() {
+ if b.bitsRead < 32 {
+ return
+ }
+ b.cursor -= 4
+ b.value = (b.value << 32) | uint64(le.Load32(b.in, b.cursor))
+ b.bitsRead -= 32
+}
+
+// fillFastStart() assumes the bitreader is empty and there is at least 8 bytes to read.
+func (b *bitReader) fillFastStart() {
+ b.cursor -= 8
+ b.value = le.Load64(b.in, b.cursor)
+ b.bitsRead = 0
+}
+
+// fill() will make sure at least 32 bits are available.
+func (b *bitReader) fill() {
+ if b.bitsRead < 32 {
+ return
+ }
+ if b.cursor >= 4 {
+ b.cursor -= 4
+ b.value = (b.value << 32) | uint64(le.Load32(b.in, b.cursor))
+ b.bitsRead -= 32
+ return
+ }
+
+ b.bitsRead -= uint8(8 * b.cursor)
+ for b.cursor > 0 {
+ b.cursor -= 1
+ b.value = (b.value << 8) | uint64(b.in[b.cursor])
+ }
+}
+
+// finished returns true if all bits have been read from the bit stream.
+func (b *bitReader) finished() bool {
+ return b.cursor == 0 && b.bitsRead >= 64
+}
+
+// overread returns true if more bits have been requested than is on the stream.
+func (b *bitReader) overread() bool {
+ return b.bitsRead > 64
+}
+
+// remain returns the number of bits remaining.
+func (b *bitReader) remain() uint {
+ return 8*uint(b.cursor) + 64 - uint(b.bitsRead)
+}
+
+// close the bitstream and returns an error if out-of-buffer reads occurred.
+func (b *bitReader) close() error {
+ // Release reference.
+ b.in = nil
+ b.cursor = 0
+ if !b.finished() {
+ return fmt.Errorf("%d extra bits on block, should be 0", b.remain())
+ }
+ if b.bitsRead > 64 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+
+func highBits(val uint32) (n uint32) {
+ return uint32(bits.Len32(val) - 1)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/bitwriter.go b/vendor/github.com/klauspost/compress/zstd/bitwriter.go
new file mode 100644
index 00000000000..b22b297e62a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/bitwriter.go
@@ -0,0 +1,112 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package zstd
+
+// bitWriter will write bits.
+// First bit will be LSB of the first byte of output.
+type bitWriter struct {
+ bitContainer uint64
+ nBits uint8
+ out []byte
+}
+
+// bitMask16 is bitmasks. Has extra to avoid bounds check.
+var bitMask16 = [32]uint16{
+ 0, 1, 3, 7, 0xF, 0x1F,
+ 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,
+ 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0xFFFF} /* up to 16 bits */
+
+var bitMask32 = [32]uint32{
+ 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF,
+ 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
+ 0x1ffff, 0x3ffff, 0x7FFFF, 0xfFFFF, 0x1fFFFF, 0x3fFFFF, 0x7fFFFF, 0xffFFFF,
+ 0x1ffFFFF, 0x3ffFFFF, 0x7ffFFFF, 0xfffFFFF, 0x1fffFFFF, 0x3fffFFFF, 0x7fffFFFF,
+} // up to 32 bits
+
+// addBits16NC will add up to 16 bits.
+// It will not check if there is space for them,
+// so the caller must ensure that it has flushed recently.
+func (b *bitWriter) addBits16NC(value uint16, bits uint8) {
+ b.bitContainer |= uint64(value&bitMask16[bits&31]) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// addBits32NC will add up to 31 bits.
+// It will not check if there is space for them,
+// so the caller must ensure that it has flushed recently.
+func (b *bitWriter) addBits32NC(value uint32, bits uint8) {
+ b.bitContainer |= uint64(value&bitMask32[bits&31]) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// addBits64NC will add up to 64 bits.
+// There must be space for 32 bits.
+func (b *bitWriter) addBits64NC(value uint64, bits uint8) {
+ if bits <= 31 {
+ b.addBits32Clean(uint32(value), bits)
+ return
+ }
+ b.addBits32Clean(uint32(value), 32)
+ b.flush32()
+ b.addBits32Clean(uint32(value>>32), bits-32)
+}
+
+// addBits32Clean will add up to 32 bits.
+// It will not check if there is space for them.
+// The input must not contain more bits than specified.
+func (b *bitWriter) addBits32Clean(value uint32, bits uint8) {
+ b.bitContainer |= uint64(value) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated.
+// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
+func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
+ b.bitContainer |= uint64(value) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// flush32 will flush out, so there are at least 32 bits available for writing.
+func (b *bitWriter) flush32() {
+ if b.nBits < 32 {
+ return
+ }
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24))
+ b.nBits -= 32
+ b.bitContainer >>= 32
+}
+
+// flushAlign will flush remaining full bytes and align to next byte boundary.
+func (b *bitWriter) flushAlign() {
+ nbBytes := (b.nBits + 7) >> 3
+ for i := range nbBytes {
+ b.out = append(b.out, byte(b.bitContainer>>(i*8)))
+ }
+ b.nBits = 0
+ b.bitContainer = 0
+}
+
+// close will write the alignment bit and write the final byte(s)
+// to the output.
+func (b *bitWriter) close() {
+ // End mark
+ b.addBits16Clean(1, 1)
+ // flush until next byte.
+ b.flushAlign()
+}
+
+// reset and continue writing by appending to out.
+func (b *bitWriter) reset(out []byte) {
+ b.bitContainer = 0
+ b.nBits = 0
+ b.out = out
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go
new file mode 100644
index 00000000000..2329e996f86
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go
@@ -0,0 +1,712 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "hash/crc32"
+ "io"
+ "sync"
+
+ "github.com/klauspost/compress/huff0"
+ "github.com/klauspost/compress/zstd/internal/xxhash"
+)
+
+type blockType uint8
+
+//go:generate stringer -type=blockType,literalsBlockType,seqCompMode,tableIndex
+
+const (
+ blockTypeRaw blockType = iota
+ blockTypeRLE
+ blockTypeCompressed
+ blockTypeReserved
+)
+
+type literalsBlockType uint8
+
+const (
+ literalsBlockRaw literalsBlockType = iota
+ literalsBlockRLE
+ literalsBlockCompressed
+ literalsBlockTreeless
+)
+
+const (
+ // maxCompressedBlockSize is the biggest allowed compressed block size (128KB)
+ maxCompressedBlockSize = 128 << 10
+
+ compressedBlockOverAlloc = 16
+ maxCompressedBlockSizeAlloc = 128<<10 + compressedBlockOverAlloc
+
+ // Maximum possible block size (all Raw+Uncompressed).
+ maxBlockSize = (1 << 21) - 1
+
+ maxMatchLen = 131074
+ maxSequences = 0x7f00 + 0xffff
+
+ // We support slightly less than the reference decoder to be able to
+ // use ints on 32 bit archs.
+ maxOffsetBits = 30
+)
+
+var (
+ huffDecoderPool = sync.Pool{New: func() any {
+ return &huff0.Scratch{}
+ }}
+
+ fseDecoderPool = sync.Pool{New: func() any {
+ return &fseDecoder{}
+ }}
+)
+
+type blockDec struct {
+ // Raw source data of the block.
+ data []byte
+ dataStorage []byte
+
+ // Destination of the decoded data.
+ dst []byte
+
+ // Buffer for literals data.
+ literalBuf []byte
+
+ // Window size of the block.
+ WindowSize uint64
+
+ err error
+
+ // Check against this crc, if hasCRC is true.
+ checkCRC uint32
+ hasCRC bool
+
+ // Frame to use for singlethreaded decoding.
+ // Should not be used by the decoder itself since parent may be another frame.
+ localFrame *frameDec
+
+ sequence []seqVals
+
+ async struct {
+ newHist *history
+ literals []byte
+ seqData []byte
+ seqSize int // Size of uncompressed sequences
+ fcs uint64
+ }
+
+ // Block is RLE, this is the size.
+ RLESize uint32
+
+ Type blockType
+
+ // Is this the last block of a frame?
+ Last bool
+
+ // Use less memory
+ lowMem bool
+}
+
+func (b *blockDec) String() string {
+ if b == nil {
+ return ""
+ }
+ return fmt.Sprintf("Steam Size: %d, Type: %v, Last: %t, Window: %d", len(b.data), b.Type, b.Last, b.WindowSize)
+}
+
+func newBlockDec(lowMem bool) *blockDec {
+ b := blockDec{
+ lowMem: lowMem,
+ }
+ return &b
+}
+
+// reset will reset the block.
+// Input must be a start of a block and will be at the end of the block when returned.
+func (b *blockDec) reset(br byteBuffer, windowSize uint64) error {
+ b.WindowSize = windowSize
+ tmp, err := br.readSmall(3)
+ if err != nil {
+ println("Reading block header:", err)
+ return err
+ }
+ bh := uint32(tmp[0]) | (uint32(tmp[1]) << 8) | (uint32(tmp[2]) << 16)
+ b.Last = bh&1 != 0
+ b.Type = blockType((bh >> 1) & 3)
+ // find size.
+ cSize := int(bh >> 3)
+ maxSize := maxCompressedBlockSizeAlloc
+ switch b.Type {
+ case blockTypeReserved:
+ return ErrReservedBlockType
+ case blockTypeRLE:
+ if cSize > maxCompressedBlockSize || cSize > int(b.WindowSize) {
+ if debugDecoder {
+ printf("rle block too big: csize:%d block: %+v\n", uint64(cSize), b)
+ }
+ return ErrWindowSizeExceeded
+ }
+ b.RLESize = uint32(cSize)
+ if b.lowMem {
+ maxSize = cSize
+ }
+ cSize = 1
+ case blockTypeCompressed:
+ if debugDecoder {
+ println("Data size on stream:", cSize)
+ }
+ b.RLESize = 0
+ maxSize = maxCompressedBlockSizeAlloc
+ if windowSize < maxCompressedBlockSize && b.lowMem {
+ maxSize = int(windowSize) + compressedBlockOverAlloc
+ }
+ if cSize > maxCompressedBlockSize || uint64(cSize) > b.WindowSize {
+ if debugDecoder {
+ printf("compressed block too big: csize:%d block: %+v\n", uint64(cSize), b)
+ }
+ return ErrCompressedSizeTooBig
+ }
+ // Empty compressed blocks must at least be 2 bytes
+ // for Literals_Block_Type and one for Sequences_Section_Header.
+ if cSize < 2 {
+ return ErrBlockTooSmall
+ }
+ case blockTypeRaw:
+ if cSize > maxCompressedBlockSize || cSize > int(b.WindowSize) {
+ if debugDecoder {
+ printf("rle block too big: csize:%d block: %+v\n", uint64(cSize), b)
+ }
+ return ErrWindowSizeExceeded
+ }
+
+ b.RLESize = 0
+ // We do not need a destination for raw blocks.
+ maxSize = -1
+ default:
+ panic("Invalid block type")
+ }
+
+ // Read block data.
+ if _, ok := br.(*byteBuf); !ok && cap(b.dataStorage) < cSize {
+ // byteBuf doesn't need a destination buffer.
+ if b.lowMem || cSize > maxCompressedBlockSize {
+ b.dataStorage = make([]byte, 0, cSize+compressedBlockOverAlloc)
+ } else {
+ b.dataStorage = make([]byte, 0, maxCompressedBlockSizeAlloc)
+ }
+ }
+ b.data, err = br.readBig(cSize, b.dataStorage)
+ if err != nil {
+ if debugDecoder {
+ println("Reading block:", err, "(", cSize, ")", len(b.data))
+ printf("%T", br)
+ }
+ return err
+ }
+ if cap(b.dst) <= maxSize {
+ b.dst = make([]byte, 0, maxSize+1)
+ }
+ return nil
+}
+
+// sendEOF will make the decoder send EOF on this frame.
+func (b *blockDec) sendErr(err error) {
+ b.Last = true
+ b.Type = blockTypeReserved
+ b.err = err
+}
+
+// Close will release resources.
+// Closed blockDec cannot be reset.
+func (b *blockDec) Close() {
+}
+
+// decodeBuf
+func (b *blockDec) decodeBuf(hist *history) error {
+ switch b.Type {
+ case blockTypeRLE:
+ if cap(b.dst) < int(b.RLESize) {
+ if b.lowMem {
+ b.dst = make([]byte, b.RLESize)
+ } else {
+ b.dst = make([]byte, maxCompressedBlockSize)
+ }
+ }
+ b.dst = b.dst[:b.RLESize]
+ v := b.data[0]
+ for i := range b.dst {
+ b.dst[i] = v
+ }
+ hist.appendKeep(b.dst)
+ return nil
+ case blockTypeRaw:
+ hist.appendKeep(b.data)
+ return nil
+ case blockTypeCompressed:
+ saved := b.dst
+ // Append directly to history
+ if hist.ignoreBuffer == 0 {
+ b.dst = hist.b
+ hist.b = nil
+ } else {
+ b.dst = b.dst[:0]
+ }
+ err := b.decodeCompressed(hist)
+ if debugDecoder {
+ println("Decompressed to total", len(b.dst), "bytes, hash:", xxhash.Sum64(b.dst), "error:", err)
+ }
+ if hist.ignoreBuffer == 0 {
+ hist.b = b.dst
+ b.dst = saved
+ } else {
+ hist.appendKeep(b.dst)
+ }
+ return err
+ case blockTypeReserved:
+ // Used for returning errors.
+ return b.err
+ default:
+ panic("Invalid block type")
+ }
+}
+
+func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err error) {
+ // There must be at least one byte for Literals_Block_Type and one for Sequences_Section_Header
+ if len(in) < 2 {
+ return in, ErrBlockTooSmall
+ }
+
+ litType := literalsBlockType(in[0] & 3)
+ var litRegenSize int
+ var litCompSize int
+ sizeFormat := (in[0] >> 2) & 3
+ var fourStreams bool
+ var literals []byte
+ switch litType {
+ case literalsBlockRaw, literalsBlockRLE:
+ switch sizeFormat {
+ case 0, 2:
+ // Regenerated_Size uses 5 bits (0-31). Literals_Section_Header uses 1 byte.
+ litRegenSize = int(in[0] >> 3)
+ in = in[1:]
+ case 1:
+ // Regenerated_Size uses 12 bits (0-4095). Literals_Section_Header uses 2 bytes.
+ litRegenSize = int(in[0]>>4) + (int(in[1]) << 4)
+ in = in[2:]
+ case 3:
+ // Regenerated_Size uses 20 bits (0-1048575). Literals_Section_Header uses 3 bytes.
+ if len(in) < 3 {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, len(in))
+ return in, ErrBlockTooSmall
+ }
+ litRegenSize = int(in[0]>>4) + (int(in[1]) << 4) + (int(in[2]) << 12)
+ in = in[3:]
+ }
+ case literalsBlockCompressed, literalsBlockTreeless:
+ switch sizeFormat {
+ case 0, 1:
+ // Both Regenerated_Size and Compressed_Size use 10 bits (0-1023).
+ if len(in) < 3 {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, len(in))
+ return in, ErrBlockTooSmall
+ }
+ n := uint64(in[0]>>4) + (uint64(in[1]) << 4) + (uint64(in[2]) << 12)
+ litRegenSize = int(n & 1023)
+ litCompSize = int(n >> 10)
+ fourStreams = sizeFormat == 1
+ in = in[3:]
+ case 2:
+ fourStreams = true
+ if len(in) < 4 {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, len(in))
+ return in, ErrBlockTooSmall
+ }
+ n := uint64(in[0]>>4) + (uint64(in[1]) << 4) + (uint64(in[2]) << 12) + (uint64(in[3]) << 20)
+ litRegenSize = int(n & 16383)
+ litCompSize = int(n >> 14)
+ in = in[4:]
+ case 3:
+ fourStreams = true
+ if len(in) < 5 {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, len(in))
+ return in, ErrBlockTooSmall
+ }
+ n := uint64(in[0]>>4) + (uint64(in[1]) << 4) + (uint64(in[2]) << 12) + (uint64(in[3]) << 20) + (uint64(in[4]) << 28)
+ litRegenSize = int(n & 262143)
+ litCompSize = int(n >> 18)
+ in = in[5:]
+ }
+ }
+ if debugDecoder {
+ println("literals type:", litType, "litRegenSize:", litRegenSize, "litCompSize:", litCompSize, "sizeFormat:", sizeFormat, "4X:", fourStreams)
+ }
+ if litRegenSize > int(b.WindowSize) || litRegenSize > maxCompressedBlockSize {
+ return in, ErrWindowSizeExceeded
+ }
+
+ switch litType {
+ case literalsBlockRaw:
+ if len(in) < litRegenSize {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, "remain:", len(in), "want:", litRegenSize)
+ return in, ErrBlockTooSmall
+ }
+ literals = in[:litRegenSize]
+ in = in[litRegenSize:]
+ //printf("Found %d uncompressed literals\n", litRegenSize)
+ case literalsBlockRLE:
+ if len(in) < 1 {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, "remain:", len(in), "want:", 1)
+ return in, ErrBlockTooSmall
+ }
+ if cap(b.literalBuf) < litRegenSize {
+ if b.lowMem {
+ b.literalBuf = make([]byte, litRegenSize, litRegenSize+compressedBlockOverAlloc)
+ } else {
+ b.literalBuf = make([]byte, litRegenSize, maxCompressedBlockSize+compressedBlockOverAlloc)
+ }
+ }
+ literals = b.literalBuf[:litRegenSize]
+ v := in[0]
+ for i := range literals {
+ literals[i] = v
+ }
+ in = in[1:]
+ if debugDecoder {
+ printf("Found %d RLE compressed literals\n", litRegenSize)
+ }
+ case literalsBlockTreeless:
+ if len(in) < litCompSize {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, "remain:", len(in), "want:", litCompSize)
+ return in, ErrBlockTooSmall
+ }
+ // Store compressed literals, so we defer decoding until we get history.
+ literals = in[:litCompSize]
+ in = in[litCompSize:]
+ if debugDecoder {
+ printf("Found %d compressed literals\n", litCompSize)
+ }
+ huff := hist.huffTree
+ if huff == nil {
+ return in, errors.New("literal block was treeless, but no history was defined")
+ }
+ // Ensure we have space to store it.
+ if cap(b.literalBuf) < litRegenSize {
+ if b.lowMem {
+ b.literalBuf = make([]byte, 0, litRegenSize+compressedBlockOverAlloc)
+ } else {
+ b.literalBuf = make([]byte, 0, maxCompressedBlockSize+compressedBlockOverAlloc)
+ }
+ }
+ var err error
+ // Use our out buffer.
+ huff.MaxDecodedSize = litRegenSize
+ if fourStreams {
+ literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals)
+ } else {
+ literals, err = huff.Decoder().Decompress1X(b.literalBuf[:0:litRegenSize], literals)
+ }
+ // Make sure we don't leak our literals buffer
+ if err != nil {
+ println("decompressing literals:", err)
+ return in, err
+ }
+ if len(literals) != litRegenSize {
+ return in, fmt.Errorf("literal output size mismatch want %d, got %d", litRegenSize, len(literals))
+ }
+
+ case literalsBlockCompressed:
+ if len(in) < litCompSize {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, "remain:", len(in), "want:", litCompSize)
+ return in, ErrBlockTooSmall
+ }
+ literals = in[:litCompSize]
+ in = in[litCompSize:]
+ // Ensure we have space to store it.
+ if cap(b.literalBuf) < litRegenSize {
+ if b.lowMem {
+ b.literalBuf = make([]byte, 0, litRegenSize+compressedBlockOverAlloc)
+ } else {
+ b.literalBuf = make([]byte, 0, maxCompressedBlockSize+compressedBlockOverAlloc)
+ }
+ }
+ huff := hist.huffTree
+ if huff == nil || (hist.dict != nil && huff == hist.dict.litEnc) {
+ huff = huffDecoderPool.Get().(*huff0.Scratch)
+ if huff == nil {
+ huff = &huff0.Scratch{}
+ }
+ }
+ var err error
+ if debugDecoder {
+ println("huff table input:", len(literals), "CRC:", crc32.ChecksumIEEE(literals))
+ }
+ huff, literals, err = huff0.ReadTable(literals, huff)
+ if err != nil {
+ println("reading huffman table:", err)
+ return in, err
+ }
+ hist.huffTree = huff
+ huff.MaxDecodedSize = litRegenSize
+ // Use our out buffer.
+ if fourStreams {
+ literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals)
+ } else {
+ literals, err = huff.Decoder().Decompress1X(b.literalBuf[:0:litRegenSize], literals)
+ }
+ if err != nil {
+ println("decoding compressed literals:", err)
+ return in, err
+ }
+ // Make sure we don't leak our literals buffer
+ if len(literals) != litRegenSize {
+ return in, fmt.Errorf("literal output size mismatch want %d, got %d", litRegenSize, len(literals))
+ }
+ // Re-cap to get extra size.
+ literals = b.literalBuf[:len(literals)]
+ if debugDecoder {
+ printf("Decompressed %d literals into %d bytes\n", litCompSize, litRegenSize)
+ }
+ }
+ hist.decoders.literals = literals
+ return in, nil
+}
+
+// decodeCompressed will start decompressing a block.
+func (b *blockDec) decodeCompressed(hist *history) error {
+ in := b.data
+ in, err := b.decodeLiterals(in, hist)
+ if err != nil {
+ return err
+ }
+ err = b.prepareSequences(in, hist)
+ if err != nil {
+ return err
+ }
+ if hist.decoders.nSeqs == 0 {
+ b.dst = append(b.dst, hist.decoders.literals...)
+ return nil
+ }
+ before := len(hist.decoders.out)
+ err = hist.decoders.decodeSync(hist.b[hist.ignoreBuffer:])
+ if err != nil {
+ return err
+ }
+ if hist.decoders.maxSyncLen > 0 {
+ hist.decoders.maxSyncLen += uint64(before)
+ hist.decoders.maxSyncLen -= uint64(len(hist.decoders.out))
+ }
+ b.dst = hist.decoders.out
+ hist.recentOffsets = hist.decoders.prevOffset
+ return nil
+}
+
+func (b *blockDec) prepareSequences(in []byte, hist *history) (err error) {
+ if debugDecoder {
+ printf("prepareSequences: %d byte(s) input\n", len(in))
+ }
+ // Decode Sequences
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#sequences-section
+ if len(in) < 1 {
+ return ErrBlockTooSmall
+ }
+ var nSeqs int
+ seqHeader := in[0]
+ switch {
+ case seqHeader < 128:
+ nSeqs = int(seqHeader)
+ in = in[1:]
+ case seqHeader < 255:
+ if len(in) < 2 {
+ return ErrBlockTooSmall
+ }
+ nSeqs = int(seqHeader-128)<<8 | int(in[1])
+ in = in[2:]
+ case seqHeader == 255:
+ if len(in) < 3 {
+ return ErrBlockTooSmall
+ }
+ nSeqs = 0x7f00 + int(in[1]) + (int(in[2]) << 8)
+ in = in[3:]
+ }
+ if nSeqs == 0 && len(in) != 0 {
+ // When no sequences, there should not be any more data...
+ if debugDecoder {
+ printf("prepareSequences: 0 sequences, but %d byte(s) left on stream\n", len(in))
+ }
+ return ErrUnexpectedBlockSize
+ }
+
+ var seqs = &hist.decoders
+ seqs.nSeqs = nSeqs
+ if nSeqs > 0 {
+ if len(in) < 1 {
+ return ErrBlockTooSmall
+ }
+ br := byteReader{b: in, off: 0}
+ compMode := br.Uint8()
+ br.advance(1)
+ if debugDecoder {
+ printf("Compression modes: 0b%b", compMode)
+ }
+ if compMode&3 != 0 {
+ return errors.New("corrupt block: reserved bits not zero")
+ }
+ for i := range uint(3) {
+ mode := seqCompMode((compMode >> (6 - i*2)) & 3)
+ if debugDecoder {
+ println("Table", tableIndex(i), "is", mode)
+ }
+ var seq *sequenceDec
+ switch tableIndex(i) {
+ case tableLiteralLengths:
+ seq = &seqs.litLengths
+ case tableOffsets:
+ seq = &seqs.offsets
+ case tableMatchLengths:
+ seq = &seqs.matchLengths
+ default:
+ panic("unknown table")
+ }
+ switch mode {
+ case compModePredefined:
+ if seq.fse != nil && !seq.fse.preDefined {
+ fseDecoderPool.Put(seq.fse)
+ }
+ seq.fse = &fsePredef[i]
+ case compModeRLE:
+ if br.remain() < 1 {
+ return ErrBlockTooSmall
+ }
+ v := br.Uint8()
+ br.advance(1)
+ if seq.fse == nil || seq.fse.preDefined {
+ seq.fse = fseDecoderPool.Get().(*fseDecoder)
+ }
+ symb, err := decSymbolValue(v, symbolTableX[i])
+ if err != nil {
+ printf("RLE Transform table (%v) error: %v", tableIndex(i), err)
+ return err
+ }
+ seq.fse.setRLE(symb)
+ if debugDecoder {
+ printf("RLE set to 0x%x, code: %v", symb, v)
+ }
+ case compModeFSE:
+ if debugDecoder {
+ println("Reading table for", tableIndex(i))
+ }
+ if seq.fse == nil || seq.fse.preDefined {
+ seq.fse = fseDecoderPool.Get().(*fseDecoder)
+ }
+ err := seq.fse.readNCount(&br, uint16(maxTableSymbol[i]))
+ if err != nil {
+ println("Read table error:", err)
+ return err
+ }
+ err = seq.fse.transform(symbolTableX[i])
+ if err != nil {
+ println("Transform table error:", err)
+ return err
+ }
+ if debugDecoder {
+ println("Read table ok", "symbolLen:", seq.fse.symbolLen)
+ }
+ case compModeRepeat:
+ seq.repeat = true
+ }
+ if br.overread() {
+ return io.ErrUnexpectedEOF
+ }
+ }
+ in = br.unread()
+ }
+ if debugDecoder {
+ println("Literals:", len(seqs.literals), "hash:", xxhash.Sum64(seqs.literals), "and", seqs.nSeqs, "sequences.")
+ }
+
+ if nSeqs == 0 {
+ if len(b.sequence) > 0 {
+ b.sequence = b.sequence[:0]
+ }
+ return nil
+ }
+ br := seqs.br
+ if br == nil {
+ br = &bitReader{}
+ }
+ if err := br.init(in); err != nil {
+ return err
+ }
+
+ if err := seqs.initialize(br, hist, b.dst); err != nil {
+ println("initializing sequences:", err)
+ return err
+ }
+
+ return nil
+}
+
+func (b *blockDec) decodeSequences(hist *history) error {
+ if cap(b.sequence) < hist.decoders.nSeqs {
+ if b.lowMem {
+ b.sequence = make([]seqVals, 0, hist.decoders.nSeqs)
+ } else {
+ b.sequence = make([]seqVals, 0, 0x7F00+0xffff)
+ }
+ }
+ b.sequence = b.sequence[:hist.decoders.nSeqs]
+ if hist.decoders.nSeqs == 0 {
+ hist.decoders.seqSize = len(hist.decoders.literals)
+ return nil
+ }
+ hist.decoders.windowSize = hist.windowSize
+ hist.decoders.prevOffset = hist.recentOffsets
+
+ err := hist.decoders.decode(b.sequence)
+ hist.recentOffsets = hist.decoders.prevOffset
+ return err
+}
+
+func (b *blockDec) executeSequences(hist *history) error {
+ hbytes := hist.b
+ if len(hbytes) > hist.windowSize {
+ hbytes = hbytes[len(hbytes)-hist.windowSize:]
+ // We do not need history anymore.
+ if hist.dict != nil {
+ hist.dict.content = nil
+ }
+ }
+ hist.decoders.windowSize = hist.windowSize
+ hist.decoders.out = b.dst[:0]
+ err := hist.decoders.execute(b.sequence, hbytes)
+ if err != nil {
+ return err
+ }
+ return b.updateHistory(hist)
+}
+
+func (b *blockDec) updateHistory(hist *history) error {
+ if len(b.data) > maxCompressedBlockSize {
+ return fmt.Errorf("compressed block size too large (%d)", len(b.data))
+ }
+ // Set output and release references.
+ b.dst = hist.decoders.out
+ hist.recentOffsets = hist.decoders.prevOffset
+
+ if b.Last {
+ // if last block we don't care about history.
+ println("Last block, no history returned")
+ hist.b = hist.b[:0]
+ return nil
+ } else {
+ hist.append(b.dst)
+ if debugDecoder {
+ println("Finished block with ", len(b.sequence), "sequences. Added", len(b.dst), "to history, now length", len(hist.b))
+ }
+ }
+ hist.decoders.out, hist.decoders.literals = nil, nil
+
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/blockenc.go b/vendor/github.com/klauspost/compress/zstd/blockenc.go
new file mode 100644
index 00000000000..0e33aea4422
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/blockenc.go
@@ -0,0 +1,893 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "math"
+ "math/bits"
+ "slices"
+
+ "github.com/klauspost/compress/huff0"
+)
+
+type blockEnc struct {
+ size int
+ literals []byte
+ sequences []seq
+ coders seqCoders
+ litEnc *huff0.Scratch
+ dictLitEnc *huff0.Scratch
+ wr bitWriter
+
+ extraLits int
+ output []byte
+ recentOffsets [3]uint32
+ prevRecentOffsets [3]uint32
+
+ last bool
+ lowMem bool
+}
+
+// init should be used once the block has been created.
+// If called more than once, the effect is the same as calling reset.
+func (b *blockEnc) init() {
+ if b.lowMem {
+ // 1K literals
+ if cap(b.literals) < 1<<10 {
+ b.literals = make([]byte, 0, 1<<10)
+ }
+ const defSeqs = 20
+ if cap(b.sequences) < defSeqs {
+ b.sequences = make([]seq, 0, defSeqs)
+ }
+ // 1K
+ if cap(b.output) < 1<<10 {
+ b.output = make([]byte, 0, 1<<10)
+ }
+ } else {
+ if cap(b.literals) < maxCompressedBlockSize {
+ b.literals = make([]byte, 0, maxCompressedBlockSize)
+ }
+ const defSeqs = 2000
+ if cap(b.sequences) < defSeqs {
+ b.sequences = make([]seq, 0, defSeqs)
+ }
+ if cap(b.output) < maxCompressedBlockSize {
+ b.output = make([]byte, 0, maxCompressedBlockSize)
+ }
+ }
+
+ if b.coders.mlEnc == nil {
+ b.coders.mlEnc = &fseEncoder{}
+ b.coders.mlPrev = &fseEncoder{}
+ b.coders.ofEnc = &fseEncoder{}
+ b.coders.ofPrev = &fseEncoder{}
+ b.coders.llEnc = &fseEncoder{}
+ b.coders.llPrev = &fseEncoder{}
+ }
+ b.litEnc = &huff0.Scratch{WantLogLess: 4}
+ b.reset(nil)
+}
+
+// initNewEncode can be used to reset offsets and encoders to the initial state.
+func (b *blockEnc) initNewEncode() {
+ b.recentOffsets = [3]uint32{1, 4, 8}
+ b.litEnc.Reuse = huff0.ReusePolicyNone
+ b.coders.setPrev(nil, nil, nil)
+ b.dictLitEnc = nil
+}
+
+// reset will reset the block for a new encode, but in the same stream,
+// meaning that state will be carried over, but the block content is reset.
+// If a previous block is provided, the recent offsets are carried over.
+func (b *blockEnc) reset(prev *blockEnc) {
+ b.extraLits = 0
+ b.literals = b.literals[:0]
+ b.size = 0
+ b.sequences = b.sequences[:0]
+ b.output = b.output[:0]
+ b.last = false
+ if prev != nil {
+ b.recentOffsets = prev.prevRecentOffsets
+ }
+ b.dictLitEnc = nil
+}
+
+// reset will reset the block for a new encode, but in the same stream,
+// meaning that state will be carried over, but the block content is reset.
+// If a previous block is provided, the recent offsets are carried over.
+func (b *blockEnc) swapEncoders(prev *blockEnc) {
+ b.coders.swap(&prev.coders)
+ b.litEnc, prev.litEnc = prev.litEnc, b.litEnc
+}
+
+// blockHeader contains the information for a block header.
+type blockHeader uint32
+
+// setLast sets the 'last' indicator on a block.
+func (h *blockHeader) setLast(b bool) {
+ if b {
+ *h = *h | 1
+ } else {
+ const mask = (1 << 24) - 2
+ *h = *h & mask
+ }
+}
+
+// setSize will store the compressed size of a block.
+func (h *blockHeader) setSize(v uint32) {
+ const mask = 7
+ *h = (*h)&mask | blockHeader(v<<3)
+}
+
+// setType sets the block type.
+func (h *blockHeader) setType(t blockType) {
+ const mask = 1 | (((1 << 24) - 1) ^ 7)
+ *h = (*h & mask) | blockHeader(t<<1)
+}
+
+// appendTo will append the block header to a slice.
+func (h blockHeader) appendTo(b []byte) []byte {
+ return append(b, uint8(h), uint8(h>>8), uint8(h>>16))
+}
+
+// String returns a string representation of the block.
+func (h blockHeader) String() string {
+ return fmt.Sprintf("Type: %d, Size: %d, Last:%t", (h>>1)&3, h>>3, h&1 == 1)
+}
+
+// literalsHeader contains literals header information.
+type literalsHeader uint64
+
+// setType can be used to set the type of literal block.
+func (h *literalsHeader) setType(t literalsBlockType) {
+ const mask = math.MaxUint64 - 3
+ *h = (*h & mask) | literalsHeader(t)
+}
+
+// setSize can be used to set a single size, for uncompressed and RLE content.
+func (h *literalsHeader) setSize(regenLen int) {
+ inBits := bits.Len32(uint32(regenLen))
+ // Only retain 2 bits
+ const mask = 3
+ lh := uint64(*h & mask)
+ switch {
+ case inBits < 5:
+ lh |= (uint64(regenLen) << 3) | (1 << 60)
+ if debugEncoder {
+ got := int(lh>>3) & 0xff
+ if got != regenLen {
+ panic(fmt.Sprint("litRegenSize = ", regenLen, "(want) != ", got, "(got)"))
+ }
+ }
+ case inBits < 12:
+ lh |= (1 << 2) | (uint64(regenLen) << 4) | (2 << 60)
+ case inBits < 20:
+ lh |= (3 << 2) | (uint64(regenLen) << 4) | (3 << 60)
+ default:
+ panic(fmt.Errorf("internal error: block too big (%d)", regenLen))
+ }
+ *h = literalsHeader(lh)
+}
+
+// setSizes will set the size of a compressed literals section and the input length.
+func (h *literalsHeader) setSizes(compLen, inLen int, single bool) {
+ compBits, inBits := bits.Len32(uint32(compLen)), bits.Len32(uint32(inLen))
+ // Only retain 2 bits
+ const mask = 3
+ lh := uint64(*h & mask)
+ switch {
+ case compBits <= 10 && inBits <= 10:
+ if !single {
+ lh |= 1 << 2
+ }
+ lh |= (uint64(inLen) << 4) | (uint64(compLen) << (10 + 4)) | (3 << 60)
+ if debugEncoder {
+ const mmask = (1 << 24) - 1
+ n := (lh >> 4) & mmask
+ if int(n&1023) != inLen {
+ panic(fmt.Sprint("regensize:", int(n&1023), "!=", inLen, inBits))
+ }
+ if int(n>>10) != compLen {
+ panic(fmt.Sprint("compsize:", int(n>>10), "!=", compLen, compBits))
+ }
+ }
+ case compBits <= 14 && inBits <= 14:
+ lh |= (2 << 2) | (uint64(inLen) << 4) | (uint64(compLen) << (14 + 4)) | (4 << 60)
+ if single {
+ panic("single stream used with more than 10 bits length.")
+ }
+ case compBits <= 18 && inBits <= 18:
+ lh |= (3 << 2) | (uint64(inLen) << 4) | (uint64(compLen) << (18 + 4)) | (5 << 60)
+ if single {
+ panic("single stream used with more than 10 bits length.")
+ }
+ default:
+ panic("internal error: block too big")
+ }
+ *h = literalsHeader(lh)
+}
+
+// appendTo will append the literals header to a byte slice.
+func (h literalsHeader) appendTo(b []byte) []byte {
+ size := uint8(h >> 60)
+ switch size {
+ case 1:
+ b = append(b, uint8(h))
+ case 2:
+ b = append(b, uint8(h), uint8(h>>8))
+ case 3:
+ b = append(b, uint8(h), uint8(h>>8), uint8(h>>16))
+ case 4:
+ b = append(b, uint8(h), uint8(h>>8), uint8(h>>16), uint8(h>>24))
+ case 5:
+ b = append(b, uint8(h), uint8(h>>8), uint8(h>>16), uint8(h>>24), uint8(h>>32))
+ default:
+ panic(fmt.Errorf("internal error: literalsHeader has invalid size (%d)", size))
+ }
+ return b
+}
+
+// size returns the output size with currently set values.
+func (h literalsHeader) size() int {
+ return int(h >> 60)
+}
+
+func (h literalsHeader) String() string {
+ return fmt.Sprintf("Type: %d, SizeFormat: %d, Size: 0x%d, Bytes:%d", literalsBlockType(h&3), (h>>2)&3, h&((1<<60)-1)>>4, h>>60)
+}
+
+// pushOffsets will push the recent offsets to the backup store.
+func (b *blockEnc) pushOffsets() {
+ b.prevRecentOffsets = b.recentOffsets
+}
+
+// pushOffsets will push the recent offsets to the backup store.
+func (b *blockEnc) popOffsets() {
+ b.recentOffsets = b.prevRecentOffsets
+}
+
+// matchOffset will adjust recent offsets and return the adjusted one,
+// if it matches a previous offset.
+func (b *blockEnc) matchOffset(offset, lits uint32) uint32 {
+ // Check if offset is one of the recent offsets.
+ // Adjusts the output offset accordingly.
+ // Gives a tiny bit of compression, typically around 1%.
+ if true {
+ if lits > 0 {
+ switch offset {
+ case b.recentOffsets[0]:
+ offset = 1
+ case b.recentOffsets[1]:
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset = 2
+ case b.recentOffsets[2]:
+ b.recentOffsets[2] = b.recentOffsets[1]
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset = 3
+ default:
+ b.recentOffsets[2] = b.recentOffsets[1]
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset += 3
+ }
+ } else {
+ switch offset {
+ case b.recentOffsets[1]:
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset = 1
+ case b.recentOffsets[2]:
+ b.recentOffsets[2] = b.recentOffsets[1]
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset = 2
+ case b.recentOffsets[0] - 1:
+ b.recentOffsets[2] = b.recentOffsets[1]
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset = 3
+ default:
+ b.recentOffsets[2] = b.recentOffsets[1]
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset += 3
+ }
+ }
+ } else {
+ offset += 3
+ }
+ return offset
+}
+
+// encodeRaw can be used to set the output to a raw representation of supplied bytes.
+func (b *blockEnc) encodeRaw(a []byte) {
+ var bh blockHeader
+ bh.setLast(b.last)
+ bh.setSize(uint32(len(a)))
+ bh.setType(blockTypeRaw)
+ b.output = bh.appendTo(b.output[:0])
+ b.output = append(b.output, a...)
+ if debugEncoder {
+ println("Adding RAW block, length", len(a), "last:", b.last)
+ }
+}
+
+// encodeRaw can be used to set the output to a raw representation of supplied bytes.
+func (b *blockEnc) encodeRawTo(dst, src []byte) []byte {
+ var bh blockHeader
+ bh.setLast(b.last)
+ bh.setSize(uint32(len(src)))
+ bh.setType(blockTypeRaw)
+ dst = bh.appendTo(dst)
+ dst = append(dst, src...)
+ if debugEncoder {
+ println("Adding RAW block, length", len(src), "last:", b.last)
+ }
+ return dst
+}
+
+// encodeLits can be used if the block is only litLen.
+func (b *blockEnc) encodeLits(lits []byte, raw bool) error {
+ var bh blockHeader
+ bh.setLast(b.last)
+ bh.setSize(uint32(len(lits)))
+
+ // Don't compress extremely small blocks
+ if len(lits) < 8 || (len(lits) < 32 && b.dictLitEnc == nil) || raw {
+ if debugEncoder {
+ println("Adding RAW block, length", len(lits), "last:", b.last)
+ }
+ bh.setType(blockTypeRaw)
+ b.output = bh.appendTo(b.output)
+ b.output = append(b.output, lits...)
+ return nil
+ }
+
+ var (
+ out []byte
+ reUsed, single bool
+ err error
+ )
+ if b.dictLitEnc != nil {
+ b.litEnc.TransferCTable(b.dictLitEnc)
+ b.litEnc.Reuse = huff0.ReusePolicyAllow
+ b.dictLitEnc = nil
+ }
+ if len(lits) >= 1024 {
+ // Use 4 Streams.
+ out, reUsed, err = huff0.Compress4X(lits, b.litEnc)
+ } else if len(lits) > 16 {
+ // Use 1 stream
+ single = true
+ out, reUsed, err = huff0.Compress1X(lits, b.litEnc)
+ } else {
+ err = huff0.ErrIncompressible
+ }
+ if err == nil && len(out)+5 > len(lits) {
+ // If we are close, we may still be worse or equal to raw.
+ var lh literalsHeader
+ lh.setSizes(len(out), len(lits), single)
+ if len(out)+lh.size() >= len(lits) {
+ err = huff0.ErrIncompressible
+ }
+ }
+ switch err {
+ case huff0.ErrIncompressible:
+ if debugEncoder {
+ println("Adding RAW block, length", len(lits), "last:", b.last)
+ }
+ bh.setType(blockTypeRaw)
+ b.output = bh.appendTo(b.output)
+ b.output = append(b.output, lits...)
+ return nil
+ case huff0.ErrUseRLE:
+ if debugEncoder {
+ println("Adding RLE block, length", len(lits))
+ }
+ bh.setType(blockTypeRLE)
+ b.output = bh.appendTo(b.output)
+ b.output = append(b.output, lits[0])
+ return nil
+ case nil:
+ default:
+ return err
+ }
+ // Compressed...
+ // Now, allow reuse
+ b.litEnc.Reuse = huff0.ReusePolicyAllow
+ bh.setType(blockTypeCompressed)
+ var lh literalsHeader
+ if reUsed {
+ if debugEncoder {
+ println("Reused tree, compressed to", len(out))
+ }
+ lh.setType(literalsBlockTreeless)
+ } else {
+ if debugEncoder {
+ println("New tree, compressed to", len(out), "tree size:", len(b.litEnc.OutTable))
+ }
+ lh.setType(literalsBlockCompressed)
+ }
+ // Set sizes
+ lh.setSizes(len(out), len(lits), single)
+ bh.setSize(uint32(len(out) + lh.size() + 1))
+
+ // Write block headers.
+ b.output = bh.appendTo(b.output)
+ b.output = lh.appendTo(b.output)
+ // Add compressed data.
+ b.output = append(b.output, out...)
+ // No sequences.
+ b.output = append(b.output, 0)
+ return nil
+}
+
+// encodeRLE will encode an RLE block.
+func (b *blockEnc) encodeRLE(val byte, length uint32) {
+ var bh blockHeader
+ bh.setLast(b.last)
+ bh.setSize(length)
+ bh.setType(blockTypeRLE)
+ b.output = bh.appendTo(b.output)
+ b.output = append(b.output, val)
+}
+
+// fuzzFseEncoder can be used to fuzz the FSE encoder.
+func fuzzFseEncoder(data []byte) int {
+ if len(data) > maxSequences || len(data) < 2 {
+ return 0
+ }
+ enc := fseEncoder{}
+ hist := enc.Histogram()
+ maxSym := uint8(0)
+ for i, v := range data {
+ v = v & 63
+ data[i] = v
+ hist[v]++
+ if v > maxSym {
+ maxSym = v
+ }
+ }
+ if maxSym == 0 {
+ // All 0
+ return 0
+ }
+ cnt := int(slices.Max(hist[:maxSym]))
+ if cnt == len(data) {
+ // RLE
+ return 0
+ }
+ enc.HistogramFinished(maxSym, cnt)
+ err := enc.normalizeCount(len(data))
+ if err != nil {
+ return 0
+ }
+ _, err = enc.writeCount(nil)
+ if err != nil {
+ panic(err)
+ }
+ return 1
+}
+
+// encode will encode the block and append the output in b.output.
+// Previous offset codes must be pushed if more blocks are expected.
+func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error {
+ if len(b.sequences) == 0 {
+ return b.encodeLits(b.literals, rawAllLits)
+ }
+ if len(b.sequences) == 1 && len(org) > 0 && len(b.literals) <= 1 {
+ // Check common RLE cases.
+ seq := b.sequences[0]
+ if seq.litLen == uint32(len(b.literals)) && seq.offset-3 == 1 {
+ // Offset == 1 and 0 or 1 literals.
+ b.encodeRLE(org[0], b.sequences[0].matchLen+zstdMinMatch+seq.litLen)
+ return nil
+ }
+ }
+
+ // We want some difference to at least account for the headers.
+ saved := b.size - len(b.literals) - (b.size >> 6)
+ if saved < 16 {
+ if org == nil {
+ return errIncompressible
+ }
+ b.popOffsets()
+ return b.encodeLits(org, rawAllLits)
+ }
+
+ var bh blockHeader
+ var lh literalsHeader
+ bh.setLast(b.last)
+ bh.setType(blockTypeCompressed)
+ // Store offset of the block header. Needed when we know the size.
+ bhOffset := len(b.output)
+ b.output = bh.appendTo(b.output)
+
+ var (
+ out []byte
+ reUsed, single bool
+ err error
+ )
+ if b.dictLitEnc != nil {
+ b.litEnc.TransferCTable(b.dictLitEnc)
+ b.litEnc.Reuse = huff0.ReusePolicyAllow
+ b.dictLitEnc = nil
+ }
+ if len(b.literals) >= 1024 && !raw {
+ // Use 4 Streams.
+ out, reUsed, err = huff0.Compress4X(b.literals, b.litEnc)
+ } else if len(b.literals) > 16 && !raw {
+ // Use 1 stream
+ single = true
+ out, reUsed, err = huff0.Compress1X(b.literals, b.litEnc)
+ } else {
+ err = huff0.ErrIncompressible
+ }
+
+ if err == nil && len(out)+5 > len(b.literals) {
+ // If we are close, we may still be worse or equal to raw.
+ var lh literalsHeader
+ lh.setSize(len(b.literals))
+ szRaw := lh.size()
+ lh.setSizes(len(out), len(b.literals), single)
+ szComp := lh.size()
+ if len(out)+szComp >= len(b.literals)+szRaw {
+ err = huff0.ErrIncompressible
+ }
+ }
+ switch err {
+ case huff0.ErrIncompressible:
+ lh.setType(literalsBlockRaw)
+ lh.setSize(len(b.literals))
+ b.output = lh.appendTo(b.output)
+ b.output = append(b.output, b.literals...)
+ if debugEncoder {
+ println("Adding literals RAW, length", len(b.literals))
+ }
+ case huff0.ErrUseRLE:
+ lh.setType(literalsBlockRLE)
+ lh.setSize(len(b.literals))
+ b.output = lh.appendTo(b.output)
+ b.output = append(b.output, b.literals[0])
+ if debugEncoder {
+ println("Adding literals RLE")
+ }
+ case nil:
+ // Compressed litLen...
+ if reUsed {
+ if debugEncoder {
+ println("reused tree")
+ }
+ lh.setType(literalsBlockTreeless)
+ } else {
+ if debugEncoder {
+ println("new tree, size:", len(b.litEnc.OutTable))
+ }
+ lh.setType(literalsBlockCompressed)
+ if debugEncoder {
+ _, _, err := huff0.ReadTable(out, nil)
+ if err != nil {
+ panic(err)
+ }
+ }
+ }
+ lh.setSizes(len(out), len(b.literals), single)
+ if debugEncoder {
+ printf("Compressed %d literals to %d bytes", len(b.literals), len(out))
+ println("Adding literal header:", lh)
+ }
+ b.output = lh.appendTo(b.output)
+ b.output = append(b.output, out...)
+ b.litEnc.Reuse = huff0.ReusePolicyAllow
+ if debugEncoder {
+ println("Adding literals compressed")
+ }
+ default:
+ if debugEncoder {
+ println("Adding literals ERROR:", err)
+ }
+ return err
+ }
+ // Sequence compression
+
+ // Write the number of sequences
+ switch {
+ case len(b.sequences) < 128:
+ b.output = append(b.output, uint8(len(b.sequences)))
+ case len(b.sequences) < 0x7f00: // TODO: this could be wrong
+ n := len(b.sequences)
+ b.output = append(b.output, 128+uint8(n>>8), uint8(n))
+ default:
+ n := len(b.sequences) - 0x7f00
+ b.output = append(b.output, 255, uint8(n), uint8(n>>8))
+ }
+ if debugEncoder {
+ println("Encoding", len(b.sequences), "sequences")
+ }
+ b.genCodes()
+ llEnc := b.coders.llEnc
+ ofEnc := b.coders.ofEnc
+ mlEnc := b.coders.mlEnc
+ err = llEnc.normalizeCount(len(b.sequences))
+ if err != nil {
+ return err
+ }
+ err = ofEnc.normalizeCount(len(b.sequences))
+ if err != nil {
+ return err
+ }
+ err = mlEnc.normalizeCount(len(b.sequences))
+ if err != nil {
+ return err
+ }
+
+ // Choose the best compression mode for each type.
+ // Will evaluate the new vs predefined and previous.
+ chooseComp := func(cur, prev, preDef *fseEncoder) (*fseEncoder, seqCompMode) {
+ // See if predefined/previous is better
+ hist := cur.count[:cur.symbolLen]
+ nSize := cur.approxSize(hist) + cur.maxHeaderSize()
+ predefSize := preDef.approxSize(hist)
+ prevSize := prev.approxSize(hist)
+
+ // Add a small penalty for new encoders.
+ // Don't bother with extremely small (<2 byte gains).
+ nSize = nSize + (nSize+2*8*16)>>4
+ switch {
+ case predefSize <= prevSize && predefSize <= nSize || forcePreDef:
+ if debugEncoder {
+ println("Using predefined", predefSize>>3, "<=", nSize>>3)
+ }
+ return preDef, compModePredefined
+ case prevSize <= nSize:
+ if debugEncoder {
+ println("Using previous", prevSize>>3, "<=", nSize>>3)
+ }
+ return prev, compModeRepeat
+ default:
+ if debugEncoder {
+ println("Using new, predef", predefSize>>3, ". previous:", prevSize>>3, ">", nSize>>3, "header max:", cur.maxHeaderSize()>>3, "bytes")
+ println("tl:", cur.actualTableLog, "symbolLen:", cur.symbolLen, "norm:", cur.norm[:cur.symbolLen], "hist", cur.count[:cur.symbolLen])
+ }
+ return cur, compModeFSE
+ }
+ }
+
+ // Write compression mode
+ var mode uint8
+ if llEnc.useRLE {
+ mode |= uint8(compModeRLE) << 6
+ llEnc.setRLE(b.sequences[0].llCode)
+ if debugEncoder {
+ println("llEnc.useRLE")
+ }
+ } else {
+ var m seqCompMode
+ llEnc, m = chooseComp(llEnc, b.coders.llPrev, &fsePredefEnc[tableLiteralLengths])
+ mode |= uint8(m) << 6
+ }
+ if ofEnc.useRLE {
+ mode |= uint8(compModeRLE) << 4
+ ofEnc.setRLE(b.sequences[0].ofCode)
+ if debugEncoder {
+ println("ofEnc.useRLE")
+ }
+ } else {
+ var m seqCompMode
+ ofEnc, m = chooseComp(ofEnc, b.coders.ofPrev, &fsePredefEnc[tableOffsets])
+ mode |= uint8(m) << 4
+ }
+
+ if mlEnc.useRLE {
+ mode |= uint8(compModeRLE) << 2
+ mlEnc.setRLE(b.sequences[0].mlCode)
+ if debugEncoder {
+ println("mlEnc.useRLE, code: ", b.sequences[0].mlCode, "value", b.sequences[0].matchLen)
+ }
+ } else {
+ var m seqCompMode
+ mlEnc, m = chooseComp(mlEnc, b.coders.mlPrev, &fsePredefEnc[tableMatchLengths])
+ mode |= uint8(m) << 2
+ }
+ b.output = append(b.output, mode)
+ if debugEncoder {
+ printf("Compression modes: 0b%b", mode)
+ }
+ b.output, err = llEnc.writeCount(b.output)
+ if err != nil {
+ return err
+ }
+ start := len(b.output)
+ b.output, err = ofEnc.writeCount(b.output)
+ if err != nil {
+ return err
+ }
+ if false {
+ println("block:", b.output[start:], "tablelog", ofEnc.actualTableLog, "maxcount:", ofEnc.maxCount)
+ fmt.Printf("selected TableLog: %d, Symbol length: %d\n", ofEnc.actualTableLog, ofEnc.symbolLen)
+ for i, v := range ofEnc.norm[:ofEnc.symbolLen] {
+ fmt.Printf("%3d: %5d -> %4d \n", i, ofEnc.count[i], v)
+ }
+ }
+ b.output, err = mlEnc.writeCount(b.output)
+ if err != nil {
+ return err
+ }
+
+ // Maybe in block?
+ wr := &b.wr
+ wr.reset(b.output)
+
+ var ll, of, ml cState
+
+ // Current sequence
+ seq := len(b.sequences) - 1
+ s := b.sequences[seq]
+ llEnc.setBits(llBitsTable[:])
+ mlEnc.setBits(mlBitsTable[:])
+ ofEnc.setBits(nil)
+
+ llTT, ofTT, mlTT := llEnc.ct.symbolTT[:256], ofEnc.ct.symbolTT[:256], mlEnc.ct.symbolTT[:256]
+
+ // We have 3 bounds checks here (and in the loop).
+ // Since we are iterating backwards it is kinda hard to avoid.
+ llB, ofB, mlB := llTT[s.llCode], ofTT[s.ofCode], mlTT[s.mlCode]
+ ll.init(wr, &llEnc.ct, llB)
+ of.init(wr, &ofEnc.ct, ofB)
+ wr.flush32()
+ ml.init(wr, &mlEnc.ct, mlB)
+
+ // Each of these lookups also generates a bounds check.
+ wr.addBits32NC(s.litLen, llB.outBits)
+ wr.addBits32NC(s.matchLen, mlB.outBits)
+ wr.flush32()
+ wr.addBits32NC(s.offset, ofB.outBits)
+ if debugSequences {
+ println("Encoded seq", seq, s, "codes:", s.llCode, s.mlCode, s.ofCode, "states:", ll.state, ml.state, of.state, "bits:", llB, mlB, ofB)
+ }
+ seq--
+ // Store sequences in reverse...
+ for seq >= 0 {
+ s = b.sequences[seq]
+
+ ofB := ofTT[s.ofCode]
+ wr.flush32() // tablelog max is below 8 for each, so it will fill max 24 bits.
+ //of.encode(ofB)
+ nbBitsOut := (uint32(of.state) + ofB.deltaNbBits) >> 16
+ dstState := int32(of.state>>(nbBitsOut&15)) + int32(ofB.deltaFindState)
+ wr.addBits16NC(of.state, uint8(nbBitsOut))
+ of.state = of.stateTable[dstState]
+
+ // Accumulate extra bits.
+ outBits := ofB.outBits & 31
+ extraBits := uint64(s.offset & bitMask32[outBits])
+ extraBitsN := outBits
+
+ mlB := mlTT[s.mlCode]
+ //ml.encode(mlB)
+ nbBitsOut = (uint32(ml.state) + mlB.deltaNbBits) >> 16
+ dstState = int32(ml.state>>(nbBitsOut&15)) + int32(mlB.deltaFindState)
+ wr.addBits16NC(ml.state, uint8(nbBitsOut))
+ ml.state = ml.stateTable[dstState]
+
+ outBits = mlB.outBits & 31
+ extraBits = extraBits<> 16
+ dstState = int32(ll.state>>(nbBitsOut&15)) + int32(llB.deltaFindState)
+ wr.addBits16NC(ll.state, uint8(nbBitsOut))
+ ll.state = ll.stateTable[dstState]
+
+ outBits = llB.outBits & 31
+ extraBits = extraBits<= b.size {
+ // Discard and encode as raw block.
+ b.output = b.encodeRawTo(b.output[:bhOffset], org)
+ b.popOffsets()
+ b.litEnc.Reuse = huff0.ReusePolicyNone
+ return nil
+ }
+
+ // Size is output minus block header.
+ bh.setSize(uint32(len(b.output)-bhOffset) - 3)
+ if debugEncoder {
+ println("Rewriting block header", bh)
+ }
+ _ = bh.appendTo(b.output[bhOffset:bhOffset])
+ b.coders.setPrev(llEnc, mlEnc, ofEnc)
+ return nil
+}
+
+var errIncompressible = errors.New("incompressible")
+
+func (b *blockEnc) genCodes() {
+ if len(b.sequences) == 0 {
+ // nothing to do
+ return
+ }
+ if len(b.sequences) > math.MaxUint16 {
+ panic("can only encode up to 64K sequences")
+ }
+ // No bounds checks after here:
+ llH := b.coders.llEnc.Histogram()
+ ofH := b.coders.ofEnc.Histogram()
+ mlH := b.coders.mlEnc.Histogram()
+ for i := range llH {
+ llH[i] = 0
+ }
+ for i := range ofH {
+ ofH[i] = 0
+ }
+ for i := range mlH {
+ mlH[i] = 0
+ }
+
+ var llMax, ofMax, mlMax uint8
+ for i := range b.sequences {
+ seq := &b.sequences[i]
+ v := llCode(seq.litLen)
+ seq.llCode = v
+ llH[v]++
+ if v > llMax {
+ llMax = v
+ }
+
+ v = ofCode(seq.offset)
+ seq.ofCode = v
+ ofH[v]++
+ if v > ofMax {
+ ofMax = v
+ }
+
+ v = mlCode(seq.matchLen)
+ seq.mlCode = v
+ mlH[v]++
+ if v > mlMax {
+ mlMax = v
+ if debugAsserts && mlMax > maxMatchLengthSymbol {
+ panic(fmt.Errorf("mlMax > maxMatchLengthSymbol (%d), matchlen: %d", mlMax, seq.matchLen))
+ }
+ }
+ }
+ if debugAsserts && mlMax > maxMatchLengthSymbol {
+ panic(fmt.Errorf("mlMax > maxMatchLengthSymbol (%d)", mlMax))
+ }
+ if debugAsserts && ofMax > maxOffsetBits {
+ panic(fmt.Errorf("ofMax > maxOffsetBits (%d)", ofMax))
+ }
+ if debugAsserts && llMax > maxLiteralLengthSymbol {
+ panic(fmt.Errorf("llMax > maxLiteralLengthSymbol (%d)", llMax))
+ }
+
+ b.coders.mlEnc.HistogramFinished(mlMax, int(slices.Max(mlH[:mlMax+1])))
+ b.coders.ofEnc.HistogramFinished(ofMax, int(slices.Max(ofH[:ofMax+1])))
+ b.coders.llEnc.HistogramFinished(llMax, int(slices.Max(llH[:llMax+1])))
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/blocktype_string.go b/vendor/github.com/klauspost/compress/zstd/blocktype_string.go
new file mode 100644
index 00000000000..01a01e486e1
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/blocktype_string.go
@@ -0,0 +1,85 @@
+// Code generated by "stringer -type=blockType,literalsBlockType,seqCompMode,tableIndex"; DO NOT EDIT.
+
+package zstd
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[blockTypeRaw-0]
+ _ = x[blockTypeRLE-1]
+ _ = x[blockTypeCompressed-2]
+ _ = x[blockTypeReserved-3]
+}
+
+const _blockType_name = "blockTypeRawblockTypeRLEblockTypeCompressedblockTypeReserved"
+
+var _blockType_index = [...]uint8{0, 12, 24, 43, 60}
+
+func (i blockType) String() string {
+ if i >= blockType(len(_blockType_index)-1) {
+ return "blockType(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _blockType_name[_blockType_index[i]:_blockType_index[i+1]]
+}
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[literalsBlockRaw-0]
+ _ = x[literalsBlockRLE-1]
+ _ = x[literalsBlockCompressed-2]
+ _ = x[literalsBlockTreeless-3]
+}
+
+const _literalsBlockType_name = "literalsBlockRawliteralsBlockRLEliteralsBlockCompressedliteralsBlockTreeless"
+
+var _literalsBlockType_index = [...]uint8{0, 16, 32, 55, 76}
+
+func (i literalsBlockType) String() string {
+ if i >= literalsBlockType(len(_literalsBlockType_index)-1) {
+ return "literalsBlockType(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _literalsBlockType_name[_literalsBlockType_index[i]:_literalsBlockType_index[i+1]]
+}
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[compModePredefined-0]
+ _ = x[compModeRLE-1]
+ _ = x[compModeFSE-2]
+ _ = x[compModeRepeat-3]
+}
+
+const _seqCompMode_name = "compModePredefinedcompModeRLEcompModeFSEcompModeRepeat"
+
+var _seqCompMode_index = [...]uint8{0, 18, 29, 40, 54}
+
+func (i seqCompMode) String() string {
+ if i >= seqCompMode(len(_seqCompMode_index)-1) {
+ return "seqCompMode(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _seqCompMode_name[_seqCompMode_index[i]:_seqCompMode_index[i+1]]
+}
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[tableLiteralLengths-0]
+ _ = x[tableOffsets-1]
+ _ = x[tableMatchLengths-2]
+}
+
+const _tableIndex_name = "tableLiteralLengthstableOffsetstableMatchLengths"
+
+var _tableIndex_index = [...]uint8{0, 19, 31, 48}
+
+func (i tableIndex) String() string {
+ if i >= tableIndex(len(_tableIndex_index)-1) {
+ return "tableIndex(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _tableIndex_name[_tableIndex_index[i]:_tableIndex_index[i+1]]
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/bytebuf.go b/vendor/github.com/klauspost/compress/zstd/bytebuf.go
new file mode 100644
index 00000000000..55a388553df
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/bytebuf.go
@@ -0,0 +1,131 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "fmt"
+ "io"
+)
+
+type byteBuffer interface {
+ // Read up to 8 bytes.
+ // Returns io.ErrUnexpectedEOF if this cannot be satisfied.
+ readSmall(n int) ([]byte, error)
+
+ // Read >8 bytes.
+ // MAY use the destination slice.
+ readBig(n int, dst []byte) ([]byte, error)
+
+ // Read a single byte.
+ readByte() (byte, error)
+
+ // Skip n bytes.
+ skipN(n int64) error
+}
+
+// in-memory buffer
+type byteBuf []byte
+
+func (b *byteBuf) readSmall(n int) ([]byte, error) {
+ if debugAsserts && n > 8 {
+ panic(fmt.Errorf("small read > 8 (%d). use readBig", n))
+ }
+ bb := *b
+ if len(bb) < n {
+ return nil, io.ErrUnexpectedEOF
+ }
+ r := bb[:n]
+ *b = bb[n:]
+ return r, nil
+}
+
+func (b *byteBuf) readBig(n int, dst []byte) ([]byte, error) {
+ bb := *b
+ if len(bb) < n {
+ return nil, io.ErrUnexpectedEOF
+ }
+ r := bb[:n]
+ *b = bb[n:]
+ return r, nil
+}
+
+func (b *byteBuf) readByte() (byte, error) {
+ bb := *b
+ if len(bb) < 1 {
+ return 0, io.ErrUnexpectedEOF
+ }
+ r := bb[0]
+ *b = bb[1:]
+ return r, nil
+}
+
+func (b *byteBuf) skipN(n int64) error {
+ bb := *b
+ if n < 0 {
+ return fmt.Errorf("negative skip (%d) requested", n)
+ }
+ if int64(len(bb)) < n {
+ return io.ErrUnexpectedEOF
+ }
+ *b = bb[n:]
+ return nil
+}
+
+// wrapper around a reader.
+type readerWrapper struct {
+ r io.Reader
+ tmp [8]byte
+}
+
+func (r *readerWrapper) readSmall(n int) ([]byte, error) {
+ if debugAsserts && n > 8 {
+ panic(fmt.Errorf("small read > 8 (%d). use readBig", n))
+ }
+ n2, err := io.ReadFull(r.r, r.tmp[:n])
+ // We only really care about the actual bytes read.
+ if err != nil {
+ if err == io.EOF {
+ return nil, io.ErrUnexpectedEOF
+ }
+ if debugDecoder {
+ println("readSmall: got", n2, "want", n, "err", err)
+ }
+ return nil, err
+ }
+ return r.tmp[:n], nil
+}
+
+func (r *readerWrapper) readBig(n int, dst []byte) ([]byte, error) {
+ if cap(dst) < n {
+ dst = make([]byte, n)
+ }
+ n2, err := io.ReadFull(r.r, dst[:n])
+ if err == io.EOF && n > 0 {
+ err = io.ErrUnexpectedEOF
+ }
+ return dst[:n2], err
+}
+
+func (r *readerWrapper) readByte() (byte, error) {
+ n2, err := io.ReadFull(r.r, r.tmp[:1])
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return 0, err
+ }
+ if n2 != 1 {
+ return 0, io.ErrUnexpectedEOF
+ }
+ return r.tmp[0], nil
+}
+
+func (r *readerWrapper) skipN(n int64) error {
+ n2, err := io.CopyN(io.Discard, r.r, n)
+ if n2 != n {
+ err = io.ErrUnexpectedEOF
+ }
+ return err
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/bytereader.go b/vendor/github.com/klauspost/compress/zstd/bytereader.go
new file mode 100644
index 00000000000..0e59a242d8d
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/bytereader.go
@@ -0,0 +1,82 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+// byteReader provides a byte reader that reads
+// little endian values from a byte stream.
+// The input stream is manually advanced.
+// The reader performs no bounds checks.
+type byteReader struct {
+ b []byte
+ off int
+}
+
+// advance the stream b n bytes.
+func (b *byteReader) advance(n uint) {
+ b.off += int(n)
+}
+
+// overread returns whether we have advanced too far.
+func (b *byteReader) overread() bool {
+ return b.off > len(b.b)
+}
+
+// Int32 returns a little endian int32 starting at current offset.
+func (b byteReader) Int32() int32 {
+ b2 := b.b[b.off:]
+ b2 = b2[:4]
+ v3 := int32(b2[3])
+ v2 := int32(b2[2])
+ v1 := int32(b2[1])
+ v0 := int32(b2[0])
+ return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24)
+}
+
+// Uint8 returns the next byte
+func (b *byteReader) Uint8() uint8 {
+ v := b.b[b.off]
+ return v
+}
+
+// Uint32 returns a little endian uint32 starting at current offset.
+func (b byteReader) Uint32() uint32 {
+ if r := b.remain(); r < 4 {
+ // Very rare
+ v := uint32(0)
+ for i := 1; i <= r; i++ {
+ v = (v << 8) | uint32(b.b[len(b.b)-i])
+ }
+ return v
+ }
+ b2 := b.b[b.off:]
+ b2 = b2[:4]
+ v3 := uint32(b2[3])
+ v2 := uint32(b2[2])
+ v1 := uint32(b2[1])
+ v0 := uint32(b2[0])
+ return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24)
+}
+
+// Uint32NC returns a little endian uint32 starting at current offset.
+// The caller must be sure if there are at least 4 bytes left.
+func (b byteReader) Uint32NC() uint32 {
+ b2 := b.b[b.off:]
+ b2 = b2[:4]
+ v3 := uint32(b2[3])
+ v2 := uint32(b2[2])
+ v1 := uint32(b2[1])
+ v0 := uint32(b2[0])
+ return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24)
+}
+
+// unread returns the unread portion of the input.
+func (b byteReader) unread() []byte {
+ return b.b[b.off:]
+}
+
+// remain will return the number of bytes remaining.
+func (b byteReader) remain() int {
+ return len(b.b) - b.off
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/decodeheader.go b/vendor/github.com/klauspost/compress/zstd/decodeheader.go
new file mode 100644
index 00000000000..6a5a2988b6f
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/decodeheader.go
@@ -0,0 +1,261 @@
+// Copyright 2020+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+
+package zstd
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+)
+
+// HeaderMaxSize is the maximum size of a Frame and Block Header.
+// If less is sent to Header.Decode it *may* still contain enough information.
+const HeaderMaxSize = 14 + 3
+
+// Header contains information about the first frame and block within that.
+type Header struct {
+ // SingleSegment specifies whether the data is to be decompressed into a
+ // single contiguous memory segment.
+ // It implies that WindowSize is invalid and that FrameContentSize is valid.
+ SingleSegment bool
+
+ // WindowSize is the window of data to keep while decoding.
+ // Will only be set if SingleSegment is false.
+ WindowSize uint64
+
+ // Dictionary ID.
+ // If 0, no dictionary.
+ DictionaryID uint32
+
+ // HasFCS specifies whether FrameContentSize has a valid value.
+ HasFCS bool
+
+ // FrameContentSize is the expected uncompressed size of the entire frame.
+ FrameContentSize uint64
+
+ // Skippable will be true if the frame is meant to be skipped.
+ // This implies that FirstBlock.OK is false.
+ Skippable bool
+
+ // SkippableID is the user-specific ID for the skippable frame.
+ // Valid values are between 0 to 15, inclusive.
+ SkippableID int
+
+ // SkippableSize is the length of the user data to skip following
+ // the header.
+ SkippableSize uint32
+
+ // HeaderSize is the raw size of the frame header.
+ //
+ // For normal frames, it includes the size of the magic number and
+ // the size of the header (per section 3.1.1.1).
+ // It does not include the size for any data blocks (section 3.1.1.2) nor
+ // the size for the trailing content checksum.
+ //
+ // For skippable frames, this counts the size of the magic number
+ // along with the size of the size field of the payload.
+ // It does not include the size of the skippable payload itself.
+ // The total frame size is the HeaderSize plus the SkippableSize.
+ HeaderSize int
+
+ // First block information.
+ FirstBlock struct {
+ // OK will be set if first block could be decoded.
+ OK bool
+
+ // Is this the last block of a frame?
+ Last bool
+
+ // Is the data compressed?
+ // If true CompressedSize will be populated.
+ // Unfortunately DecompressedSize cannot be determined
+ // without decoding the blocks.
+ Compressed bool
+
+ // DecompressedSize is the expected decompressed size of the block.
+ // Will be 0 if it cannot be determined.
+ DecompressedSize int
+
+ // CompressedSize of the data in the block.
+ // Does not include the block header.
+ // Will be equal to DecompressedSize if not Compressed.
+ CompressedSize int
+ }
+
+ // If set there is a checksum present for the block content.
+ // The checksum field at the end is always 4 bytes long.
+ HasCheckSum bool
+}
+
+// Decode the header from the beginning of the stream.
+// This will decode the frame header and the first block header if enough bytes are provided.
+// It is recommended to provide at least HeaderMaxSize bytes.
+// If the frame header cannot be read an error will be returned.
+// If there isn't enough input, io.ErrUnexpectedEOF is returned.
+// The FirstBlock.OK will indicate if enough information was available to decode the first block header.
+func (h *Header) Decode(in []byte) error {
+ _, err := h.DecodeAndStrip(in)
+ return err
+}
+
+// DecodeAndStrip will decode the header from the beginning of the stream
+// and on success return the remaining bytes.
+// This will decode the frame header and the first block header if enough bytes are provided.
+// It is recommended to provide at least HeaderMaxSize bytes.
+// If the frame header cannot be read an error will be returned.
+// If there isn't enough input, io.ErrUnexpectedEOF is returned.
+// The FirstBlock.OK will indicate if enough information was available to decode the first block header.
+func (h *Header) DecodeAndStrip(in []byte) (remain []byte, err error) {
+ *h = Header{}
+ if len(in) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ h.HeaderSize += 4
+ b, in := in[:4], in[4:]
+ if string(b) != frameMagic {
+ if string(b[1:4]) != skippableFrameMagic || b[0]&0xf0 != 0x50 {
+ return nil, ErrMagicMismatch
+ }
+ if len(in) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ h.HeaderSize += 4
+ h.Skippable = true
+ h.SkippableID = int(b[0] & 0xf)
+ h.SkippableSize = binary.LittleEndian.Uint32(in)
+ return in[4:], nil
+ }
+
+ // Read Window_Descriptor
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor
+ if len(in) < 1 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ fhd, in := in[0], in[1:]
+ h.HeaderSize++
+ h.SingleSegment = fhd&(1<<5) != 0
+ h.HasCheckSum = fhd&(1<<2) != 0
+ if fhd&(1<<3) != 0 {
+ return nil, errors.New("reserved bit set on frame header")
+ }
+
+ if !h.SingleSegment {
+ if len(in) < 1 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ var wd byte
+ wd, in = in[0], in[1:]
+ h.HeaderSize++
+ windowLog := 10 + (wd >> 3)
+ windowBase := uint64(1) << windowLog
+ windowAdd := (windowBase / 8) * uint64(wd&0x7)
+ h.WindowSize = windowBase + windowAdd
+ }
+
+ // Read Dictionary_ID
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_id
+ if size := fhd & 3; size != 0 {
+ if size == 3 {
+ size = 4
+ }
+ if len(in) < int(size) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b, in = in[:size], in[size:]
+ h.HeaderSize += int(size)
+ switch len(b) {
+ case 1:
+ h.DictionaryID = uint32(b[0])
+ case 2:
+ h.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8)
+ case 4:
+ h.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ }
+ }
+
+ // Read Frame_Content_Size
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frame_content_size
+ var fcsSize int
+ v := fhd >> 6
+ switch v {
+ case 0:
+ if h.SingleSegment {
+ fcsSize = 1
+ }
+ default:
+ fcsSize = 1 << v
+ }
+
+ if fcsSize > 0 {
+ h.HasFCS = true
+ if len(in) < fcsSize {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b, in = in[:fcsSize], in[fcsSize:]
+ h.HeaderSize += int(fcsSize)
+ switch len(b) {
+ case 1:
+ h.FrameContentSize = uint64(b[0])
+ case 2:
+ // When FCS_Field_Size is 2, the offset of 256 is added.
+ h.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) + 256
+ case 4:
+ h.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) | (uint64(b[2]) << 16) | (uint64(b[3]) << 24)
+ case 8:
+ d1 := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ d2 := uint32(b[4]) | (uint32(b[5]) << 8) | (uint32(b[6]) << 16) | (uint32(b[7]) << 24)
+ h.FrameContentSize = uint64(d1) | (uint64(d2) << 32)
+ }
+ }
+
+ // Frame Header done, we will not fail from now on.
+ if len(in) < 3 {
+ return in, nil
+ }
+ tmp := in[:3]
+ bh := uint32(tmp[0]) | (uint32(tmp[1]) << 8) | (uint32(tmp[2]) << 16)
+ h.FirstBlock.Last = bh&1 != 0
+ blockType := blockType((bh >> 1) & 3)
+ // find size.
+ cSize := int(bh >> 3)
+ switch blockType {
+ case blockTypeReserved:
+ return in, nil
+ case blockTypeRLE:
+ h.FirstBlock.Compressed = true
+ h.FirstBlock.DecompressedSize = cSize
+ h.FirstBlock.CompressedSize = 1
+ case blockTypeCompressed:
+ h.FirstBlock.Compressed = true
+ h.FirstBlock.CompressedSize = cSize
+ case blockTypeRaw:
+ h.FirstBlock.DecompressedSize = cSize
+ h.FirstBlock.CompressedSize = cSize
+ default:
+ panic("Invalid block type")
+ }
+
+ h.FirstBlock.OK = true
+ return in, nil
+}
+
+// AppendTo will append the encoded header to the dst slice.
+// There is no error checking performed on the header values.
+func (h *Header) AppendTo(dst []byte) ([]byte, error) {
+ if h.Skippable {
+ magic := [4]byte{0x50, 0x2a, 0x4d, 0x18}
+ magic[0] |= byte(h.SkippableID & 0xf)
+ dst = append(dst, magic[:]...)
+ f := h.SkippableSize
+ return append(dst, uint8(f), uint8(f>>8), uint8(f>>16), uint8(f>>24)), nil
+ }
+ f := frameHeader{
+ ContentSize: h.FrameContentSize,
+ WindowSize: uint32(h.WindowSize),
+ SingleSegment: h.SingleSegment,
+ Checksum: h.HasCheckSum,
+ DictID: h.DictionaryID,
+ }
+ return f.appendTo(dst), nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go
new file mode 100644
index 00000000000..c7e500f02a9
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/decoder.go
@@ -0,0 +1,957 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "context"
+ "encoding/binary"
+ "io"
+ "sync"
+
+ "github.com/klauspost/compress/zstd/internal/xxhash"
+)
+
+// Decoder provides decoding of zstandard streams.
+// The decoder has been designed to operate without allocations after a warmup.
+// This means that you should store the decoder for best performance.
+// To re-use a stream decoder, use the Reset(r io.Reader) error to switch to another stream.
+// A decoder can safely be re-used even if the previous stream failed.
+// To release the resources, you must call the Close() function on a decoder.
+type Decoder struct {
+ o decoderOptions
+
+ // Unreferenced decoders, ready for use.
+ decoders chan *blockDec
+
+ // Current read position used for Reader functionality.
+ current decoderState
+
+ // sync stream decoding
+ syncStream struct {
+ decodedFrame uint64
+ br readerWrapper
+ enabled bool
+ inFrame bool
+ dstBuf []byte
+ }
+
+ frame *frameDec
+
+ // streamWg is the waitgroup for all streams
+ streamWg sync.WaitGroup
+}
+
+// decoderState is used for maintaining state when the decoder
+// is used for streaming.
+type decoderState struct {
+ // current block being written to stream.
+ decodeOutput
+
+ // output in order to be written to stream.
+ output chan decodeOutput
+
+ // cancel remaining output.
+ cancel context.CancelFunc
+
+ // crc of current frame
+ crc *xxhash.Digest
+
+ flushed bool
+}
+
+var (
+ // Check the interfaces we want to support.
+ _ = io.WriterTo(&Decoder{})
+ _ = io.Reader(&Decoder{})
+)
+
+// NewReader creates a new decoder.
+// A nil Reader can be provided in which case Reset can be used to start a decode.
+//
+// A Decoder can be used in two modes:
+//
+// 1) As a stream, or
+// 2) For stateless decoding using DecodeAll.
+//
+// Only a single stream can be decoded concurrently, but the same decoder
+// can run multiple concurrent stateless decodes. It is even possible to
+// use stateless decodes while a stream is being decoded.
+//
+// The Reset function can be used to initiate a new stream, which will considerably
+// reduce the allocations normally caused by NewReader.
+func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) {
+ initPredefined()
+ var d Decoder
+ d.o.setDefault()
+ for _, o := range opts {
+ err := o(&d.o)
+ if err != nil {
+ return nil, err
+ }
+ }
+ d.current.crc = xxhash.New()
+ d.current.flushed = true
+
+ if r == nil {
+ d.current.err = ErrDecoderNilInput
+ }
+
+ // Initialize dict map if needed.
+ if d.o.dicts == nil {
+ d.o.dicts = make(map[uint32]*dict)
+ }
+
+ // Create decoders
+ d.decoders = make(chan *blockDec, d.o.concurrent)
+ for i := 0; i < d.o.concurrent; i++ {
+ dec := newBlockDec(d.o.lowMem)
+ dec.localFrame = newFrameDec(d.o)
+ d.decoders <- dec
+ }
+
+ if r == nil {
+ return &d, nil
+ }
+ return &d, d.Reset(r)
+}
+
+// Read bytes from the decompressed stream into p.
+// Returns the number of bytes read and any error that occurred.
+// When the stream is done, io.EOF will be returned.
+func (d *Decoder) Read(p []byte) (int, error) {
+ var n int
+ for {
+ if len(d.current.b) > 0 {
+ filled := copy(p, d.current.b)
+ p = p[filled:]
+ d.current.b = d.current.b[filled:]
+ n += filled
+ }
+ if len(p) == 0 {
+ break
+ }
+ if len(d.current.b) == 0 {
+ // We have an error and no more data
+ if d.current.err != nil {
+ break
+ }
+ if !d.nextBlock(n == 0) {
+ return n, d.current.err
+ }
+ }
+ }
+ if len(d.current.b) > 0 {
+ if debugDecoder {
+ println("returning", n, "still bytes left:", len(d.current.b))
+ }
+ // Only return error at end of block
+ return n, nil
+ }
+ if d.current.err != nil {
+ d.drainOutput()
+ }
+ if debugDecoder {
+ println("returning", n, d.current.err, len(d.decoders))
+ }
+ return n, d.current.err
+}
+
+// Reset will reset the decoder the supplied stream after the current has finished processing.
+// Note that this functionality cannot be used after Close has been called.
+// Reset can be called with a nil reader to release references to the previous reader.
+// After being called with a nil reader, no other operations than Reset or DecodeAll or Close
+// should be used.
+func (d *Decoder) Reset(r io.Reader) error {
+ if d.current.err == ErrDecoderClosed {
+ return d.current.err
+ }
+
+ d.drainOutput()
+
+ d.syncStream.br.r = nil
+ if r == nil {
+ d.current.err = ErrDecoderNilInput
+ if len(d.current.b) > 0 {
+ d.current.b = d.current.b[:0]
+ }
+ d.current.flushed = true
+ return nil
+ }
+
+ // If bytes buffer and < 5MB, do sync decoding anyway.
+ if bb, ok := r.(byter); ok && bb.Len() < d.o.decodeBufsBelow && !d.o.limitToCap {
+ bb2 := bb
+ if debugDecoder {
+ println("*bytes.Buffer detected, doing sync decode, len:", bb.Len())
+ }
+ b := bb2.Bytes()
+ var dst []byte
+ if cap(d.syncStream.dstBuf) > 0 {
+ dst = d.syncStream.dstBuf[:0]
+ }
+
+ dst, err := d.DecodeAll(b, dst)
+ if err == nil {
+ err = io.EOF
+ }
+ // Save output buffer
+ d.syncStream.dstBuf = dst
+ d.current.b = dst
+ d.current.err = err
+ d.current.flushed = true
+ if debugDecoder {
+ println("sync decode to", len(dst), "bytes, err:", err)
+ }
+ return nil
+ }
+ // Remove current block.
+ d.stashDecoder()
+ d.current.decodeOutput = decodeOutput{}
+ d.current.err = nil
+ d.current.flushed = false
+ d.current.d = nil
+ d.syncStream.dstBuf = nil
+
+ // Ensure no-one else is still running...
+ d.streamWg.Wait()
+ if d.frame == nil {
+ d.frame = newFrameDec(d.o)
+ }
+
+ if d.o.concurrent == 1 {
+ return d.startSyncDecoder(r)
+ }
+
+ d.current.output = make(chan decodeOutput, d.o.concurrent)
+ ctx, cancel := context.WithCancel(context.Background())
+ d.current.cancel = cancel
+ d.streamWg.Add(1)
+ go d.startStreamDecoder(ctx, r, d.current.output)
+
+ return nil
+}
+
+// ResetWithOptions will reset the decoder and apply the given options
+// for the next stream or DecodeAll operation.
+// Options are applied on top of the existing options.
+// Some options cannot be changed on reset and will return an error.
+func (d *Decoder) ResetWithOptions(r io.Reader, opts ...DOption) error {
+ d.o.resetOpt = true
+ defer func() { d.o.resetOpt = false }()
+ for _, o := range opts {
+ if err := o(&d.o); err != nil {
+ return err
+ }
+ }
+ return d.Reset(r)
+}
+
+// drainOutput will drain the output until errEndOfStream is sent.
+func (d *Decoder) drainOutput() {
+ if d.current.cancel != nil {
+ if debugDecoder {
+ println("cancelling current")
+ }
+ d.current.cancel()
+ d.current.cancel = nil
+ }
+ if d.current.d != nil {
+ if debugDecoder {
+ printf("re-adding current decoder %p, decoders: %d", d.current.d, len(d.decoders))
+ }
+ d.decoders <- d.current.d
+ d.current.d = nil
+ d.current.b = nil
+ }
+ if d.current.output == nil || d.current.flushed {
+ println("current already flushed")
+ return
+ }
+ for v := range d.current.output {
+ if v.d != nil {
+ if debugDecoder {
+ printf("re-adding decoder %p", v.d)
+ }
+ d.decoders <- v.d
+ }
+ }
+ d.current.output = nil
+ d.current.flushed = true
+}
+
+// WriteTo writes data to w until there's no more data to write or when an error occurs.
+// The return value n is the number of bytes written.
+// Any error encountered during the write is also returned.
+func (d *Decoder) WriteTo(w io.Writer) (int64, error) {
+ var n int64
+ for {
+ if len(d.current.b) > 0 {
+ n2, err2 := w.Write(d.current.b)
+ n += int64(n2)
+ if err2 != nil && (d.current.err == nil || d.current.err == io.EOF) {
+ d.current.err = err2
+ } else if n2 != len(d.current.b) {
+ d.current.err = io.ErrShortWrite
+ }
+ }
+ if d.current.err != nil {
+ break
+ }
+ d.nextBlock(true)
+ }
+ err := d.current.err
+ if err != nil {
+ d.drainOutput()
+ }
+ if err == io.EOF {
+ err = nil
+ }
+ return n, err
+}
+
+// DecodeAll allows stateless decoding of a blob of bytes.
+// Output will be appended to dst, so if the destination size is known
+// you can pre-allocate the destination slice to avoid allocations.
+// DecodeAll can be used concurrently.
+// The Decoder concurrency limits will be respected.
+func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) {
+ if d.decoders == nil {
+ return dst, ErrDecoderClosed
+ }
+
+ // Grab a block decoder and frame decoder.
+ block := <-d.decoders
+ frame := block.localFrame
+ initialSize := len(dst)
+ defer func() {
+ if debugDecoder {
+ printf("re-adding decoder: %p", block)
+ }
+ frame.rawInput = nil
+ frame.bBuf = nil
+ if frame.history.decoders.br != nil {
+ frame.history.decoders.br.in = nil
+ frame.history.decoders.br.cursor = 0
+ }
+ d.decoders <- block
+ }()
+ frame.bBuf = input
+
+ for {
+ frame.history.reset()
+ err := frame.reset(&frame.bBuf)
+ if err != nil {
+ if err == io.EOF {
+ if debugDecoder {
+ println("frame reset return EOF")
+ }
+ return dst, nil
+ }
+ return dst, err
+ }
+ if err = d.setDict(frame); err != nil {
+ return nil, err
+ }
+ if frame.WindowSize > d.o.maxWindowSize {
+ if debugDecoder {
+ println("window size exceeded:", frame.WindowSize, ">", d.o.maxWindowSize)
+ }
+ return dst, ErrWindowSizeExceeded
+ }
+ if frame.FrameContentSize != fcsUnknown {
+ if frame.FrameContentSize > d.o.maxDecodedSize-uint64(len(dst)-initialSize) {
+ if debugDecoder {
+ println("decoder size exceeded; fcs:", frame.FrameContentSize, "> mcs:", d.o.maxDecodedSize-uint64(len(dst)-initialSize), "len:", len(dst))
+ }
+ return dst, ErrDecoderSizeExceeded
+ }
+ if d.o.limitToCap && frame.FrameContentSize > uint64(cap(dst)-len(dst)) {
+ if debugDecoder {
+ println("decoder size exceeded; fcs:", frame.FrameContentSize, "> (cap-len)", cap(dst)-len(dst))
+ }
+ return dst, ErrDecoderSizeExceeded
+ }
+ if cap(dst)-len(dst) < int(frame.FrameContentSize) {
+ dst2 := make([]byte, len(dst), len(dst)+int(frame.FrameContentSize)+compressedBlockOverAlloc)
+ copy(dst2, dst)
+ dst = dst2
+ }
+ }
+
+ if cap(dst) == 0 && !d.o.limitToCap {
+ // Allocate len(input) * 2 by default if nothing is provided
+ // and we didn't get frame content size.
+ size := min(
+ // Cap to 1 MB.
+ len(input)*2, 1<<20)
+ if uint64(size) > d.o.maxDecodedSize {
+ size = int(d.o.maxDecodedSize)
+ }
+ dst = make([]byte, 0, size)
+ }
+
+ dst, err = frame.runDecoder(dst, block)
+ if err != nil {
+ return dst, err
+ }
+ if uint64(len(dst)-initialSize) > d.o.maxDecodedSize {
+ return dst, ErrDecoderSizeExceeded
+ }
+ if len(frame.bBuf) == 0 {
+ if debugDecoder {
+ println("frame dbuf empty")
+ }
+ break
+ }
+ }
+ return dst, nil
+}
+
+// nextBlock returns the next block.
+// If an error occurs d.err will be set.
+// Optionally the function can block for new output.
+// If non-blocking mode is used the returned boolean will be false
+// if no data was available without blocking.
+func (d *Decoder) nextBlock(blocking bool) (ok bool) {
+ if d.current.err != nil {
+ // Keep error state.
+ return false
+ }
+ d.current.b = d.current.b[:0]
+
+ // SYNC:
+ if d.syncStream.enabled {
+ if !blocking {
+ return false
+ }
+ ok = d.nextBlockSync()
+ if !ok {
+ d.stashDecoder()
+ }
+ return ok
+ }
+
+ //ASYNC:
+ d.stashDecoder()
+ if blocking {
+ d.current.decodeOutput, ok = <-d.current.output
+ } else {
+ select {
+ case d.current.decodeOutput, ok = <-d.current.output:
+ default:
+ return false
+ }
+ }
+ if !ok {
+ // This should not happen, so signal error state...
+ d.current.err = io.ErrUnexpectedEOF
+ return false
+ }
+ next := d.current.decodeOutput
+ if next.d != nil && next.d.async.newHist != nil {
+ d.current.crc.Reset()
+ }
+ if debugDecoder {
+ var tmp [4]byte
+ binary.LittleEndian.PutUint32(tmp[:], uint32(xxhash.Sum64(next.b)))
+ println("got", len(d.current.b), "bytes, error:", d.current.err, "data crc:", tmp)
+ }
+
+ if d.o.ignoreChecksum {
+ return true
+ }
+
+ if len(next.b) > 0 {
+ d.current.crc.Write(next.b)
+ }
+ if next.err == nil && next.d != nil && next.d.hasCRC {
+ got := uint32(d.current.crc.Sum64())
+ if got != next.d.checkCRC {
+ if debugDecoder {
+ printf("CRC Check Failed: %08x (got) != %08x (on stream)\n", got, next.d.checkCRC)
+ }
+ d.current.err = ErrCRCMismatch
+ } else {
+ if debugDecoder {
+ printf("CRC ok %08x\n", got)
+ }
+ }
+ }
+
+ return true
+}
+
+func (d *Decoder) nextBlockSync() (ok bool) {
+ if d.current.d == nil {
+ d.current.d = <-d.decoders
+ }
+ for len(d.current.b) == 0 {
+ if !d.syncStream.inFrame {
+ d.frame.history.reset()
+ d.current.err = d.frame.reset(&d.syncStream.br)
+ if d.current.err == nil {
+ d.current.err = d.setDict(d.frame)
+ }
+ if d.current.err != nil {
+ return false
+ }
+ if d.frame.WindowSize > d.o.maxDecodedSize || d.frame.WindowSize > d.o.maxWindowSize {
+ d.current.err = ErrDecoderSizeExceeded
+ return false
+ }
+
+ d.syncStream.decodedFrame = 0
+ d.syncStream.inFrame = true
+ }
+ d.current.err = d.frame.next(d.current.d)
+ if d.current.err != nil {
+ return false
+ }
+ d.frame.history.ensureBlock()
+ if debugDecoder {
+ println("History trimmed:", len(d.frame.history.b), "decoded already:", d.syncStream.decodedFrame)
+ }
+ histBefore := len(d.frame.history.b)
+ d.current.err = d.current.d.decodeBuf(&d.frame.history)
+
+ if d.current.err != nil {
+ println("error after:", d.current.err)
+ return false
+ }
+ d.current.b = d.frame.history.b[histBefore:]
+ if debugDecoder {
+ println("history after:", len(d.frame.history.b))
+ }
+
+ // Check frame size (before CRC)
+ d.syncStream.decodedFrame += uint64(len(d.current.b))
+ if d.syncStream.decodedFrame > d.frame.FrameContentSize {
+ if debugDecoder {
+ printf("DecodedFrame (%d) > FrameContentSize (%d)\n", d.syncStream.decodedFrame, d.frame.FrameContentSize)
+ }
+ d.current.err = ErrFrameSizeExceeded
+ return false
+ }
+
+ // Check FCS
+ if d.current.d.Last && d.frame.FrameContentSize != fcsUnknown && d.syncStream.decodedFrame != d.frame.FrameContentSize {
+ if debugDecoder {
+ printf("DecodedFrame (%d) != FrameContentSize (%d)\n", d.syncStream.decodedFrame, d.frame.FrameContentSize)
+ }
+ d.current.err = ErrFrameSizeMismatch
+ return false
+ }
+
+ // Update/Check CRC
+ if d.frame.HasCheckSum {
+ if !d.o.ignoreChecksum {
+ d.frame.crc.Write(d.current.b)
+ }
+ if d.current.d.Last {
+ if !d.o.ignoreChecksum {
+ d.current.err = d.frame.checkCRC()
+ } else {
+ d.current.err = d.frame.consumeCRC()
+ }
+ if d.current.err != nil {
+ println("CRC error:", d.current.err)
+ return false
+ }
+ }
+ }
+ d.syncStream.inFrame = !d.current.d.Last
+ }
+ return true
+}
+
+func (d *Decoder) stashDecoder() {
+ if d.current.d != nil {
+ if debugDecoder {
+ printf("re-adding current decoder %p", d.current.d)
+ }
+ d.decoders <- d.current.d
+ d.current.d = nil
+ }
+}
+
+// Close will release all resources.
+// It is NOT possible to reuse the decoder after this.
+func (d *Decoder) Close() {
+ if d.current.err == ErrDecoderClosed {
+ return
+ }
+ d.drainOutput()
+ if d.current.cancel != nil {
+ d.current.cancel()
+ d.streamWg.Wait()
+ d.current.cancel = nil
+ }
+ if d.decoders != nil {
+ close(d.decoders)
+ for dec := range d.decoders {
+ dec.Close()
+ }
+ d.decoders = nil
+ }
+ if d.current.d != nil {
+ d.current.d.Close()
+ d.current.d = nil
+ }
+ d.current.err = ErrDecoderClosed
+}
+
+// IOReadCloser returns the decoder as an io.ReadCloser for convenience.
+// Any changes to the decoder will be reflected, so the returned ReadCloser
+// can be reused along with the decoder.
+// io.WriterTo is also supported by the returned ReadCloser.
+func (d *Decoder) IOReadCloser() io.ReadCloser {
+ return closeWrapper{d: d}
+}
+
+// closeWrapper wraps a function call as a closer.
+type closeWrapper struct {
+ d *Decoder
+}
+
+// WriteTo forwards WriteTo calls to the decoder.
+func (c closeWrapper) WriteTo(w io.Writer) (n int64, err error) {
+ return c.d.WriteTo(w)
+}
+
+// Read forwards read calls to the decoder.
+func (c closeWrapper) Read(p []byte) (n int, err error) {
+ return c.d.Read(p)
+}
+
+// Close closes the decoder.
+func (c closeWrapper) Close() error {
+ c.d.Close()
+ return nil
+}
+
+type decodeOutput struct {
+ d *blockDec
+ b []byte
+ err error
+}
+
+func (d *Decoder) startSyncDecoder(r io.Reader) error {
+ d.frame.history.reset()
+ d.syncStream.br = readerWrapper{r: r}
+ d.syncStream.inFrame = false
+ d.syncStream.enabled = true
+ d.syncStream.decodedFrame = 0
+ return nil
+}
+
+// Create Decoder:
+// ASYNC:
+// Spawn 3 go routines.
+// 0: Read frames and decode block literals.
+// 1: Decode sequences.
+// 2: Execute sequences, send to output.
+func (d *Decoder) startStreamDecoder(ctx context.Context, r io.Reader, output chan decodeOutput) {
+ defer d.streamWg.Done()
+ br := readerWrapper{r: r}
+
+ var seqDecode = make(chan *blockDec, d.o.concurrent)
+ var seqExecute = make(chan *blockDec, d.o.concurrent)
+
+ // Async 1: Decode sequences...
+ go func() {
+ var hist history
+ var hasErr bool
+
+ for block := range seqDecode {
+ if hasErr {
+ if block != nil {
+ seqExecute <- block
+ }
+ continue
+ }
+ if block.async.newHist != nil {
+ if debugDecoder {
+ println("Async 1: new history, recent:", block.async.newHist.recentOffsets)
+ }
+ hist.reset()
+ hist.decoders = block.async.newHist.decoders
+ hist.recentOffsets = block.async.newHist.recentOffsets
+ hist.windowSize = block.async.newHist.windowSize
+ if block.async.newHist.dict != nil {
+ hist.setDict(block.async.newHist.dict)
+ }
+ }
+ if block.err != nil || block.Type != blockTypeCompressed {
+ hasErr = block.err != nil
+ seqExecute <- block
+ continue
+ }
+
+ hist.decoders.literals = block.async.literals
+ block.err = block.prepareSequences(block.async.seqData, &hist)
+ if debugDecoder && block.err != nil {
+ println("prepareSequences returned:", block.err)
+ }
+ hasErr = block.err != nil
+ if block.err == nil {
+ block.err = block.decodeSequences(&hist)
+ if debugDecoder && block.err != nil {
+ println("decodeSequences returned:", block.err)
+ }
+ hasErr = block.err != nil
+ // block.async.sequence = hist.decoders.seq[:hist.decoders.nSeqs]
+ block.async.seqSize = hist.decoders.seqSize
+ }
+ seqExecute <- block
+ }
+ close(seqExecute)
+ hist.reset()
+ }()
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+
+ // Async 3: Execute sequences...
+ frameHistCache := d.frame.history.b
+ go func() {
+ var hist history
+ var decodedFrame uint64
+ var fcs uint64
+ var hasErr bool
+ for block := range seqExecute {
+ out := decodeOutput{err: block.err, d: block}
+ if block.err != nil || hasErr {
+ hasErr = true
+ output <- out
+ continue
+ }
+ if block.async.newHist != nil {
+ if debugDecoder {
+ println("Async 2: new history")
+ }
+ hist.reset()
+ hist.windowSize = block.async.newHist.windowSize
+ hist.allocFrameBuffer = block.async.newHist.allocFrameBuffer
+ if block.async.newHist.dict != nil {
+ hist.setDict(block.async.newHist.dict)
+ }
+
+ if cap(hist.b) < hist.allocFrameBuffer {
+ if cap(frameHistCache) >= hist.allocFrameBuffer {
+ hist.b = frameHistCache
+ } else {
+ hist.b = make([]byte, 0, hist.allocFrameBuffer)
+ println("Alloc history sized", hist.allocFrameBuffer)
+ }
+ }
+ hist.b = hist.b[:0]
+ fcs = block.async.fcs
+ decodedFrame = 0
+ }
+ do := decodeOutput{err: block.err, d: block}
+ switch block.Type {
+ case blockTypeRLE:
+ if debugDecoder {
+ println("add rle block length:", block.RLESize)
+ }
+
+ if cap(block.dst) < int(block.RLESize) {
+ if block.lowMem {
+ block.dst = make([]byte, block.RLESize)
+ } else {
+ block.dst = make([]byte, maxCompressedBlockSize)
+ }
+ }
+ block.dst = block.dst[:block.RLESize]
+ v := block.data[0]
+ for i := range block.dst {
+ block.dst[i] = v
+ }
+ hist.append(block.dst)
+ do.b = block.dst
+ case blockTypeRaw:
+ if debugDecoder {
+ println("add raw block length:", len(block.data))
+ }
+ hist.append(block.data)
+ do.b = block.data
+ case blockTypeCompressed:
+ if debugDecoder {
+ println("execute with history length:", len(hist.b), "window:", hist.windowSize)
+ }
+ hist.decoders.seqSize = block.async.seqSize
+ hist.decoders.literals = block.async.literals
+ do.err = block.executeSequences(&hist)
+ hasErr = do.err != nil
+ if debugDecoder && hasErr {
+ println("executeSequences returned:", do.err)
+ }
+ do.b = block.dst
+ }
+ if !hasErr {
+ decodedFrame += uint64(len(do.b))
+ if decodedFrame > fcs {
+ println("fcs exceeded", block.Last, fcs, decodedFrame)
+ do.err = ErrFrameSizeExceeded
+ hasErr = true
+ } else if block.Last && fcs != fcsUnknown && decodedFrame != fcs {
+ do.err = ErrFrameSizeMismatch
+ hasErr = true
+ } else {
+ if debugDecoder {
+ println("fcs ok", block.Last, fcs, decodedFrame)
+ }
+ }
+ }
+ output <- do
+ }
+ close(output)
+ frameHistCache = hist.b
+ wg.Done()
+ if debugDecoder {
+ println("decoder goroutines finished")
+ }
+ hist.reset()
+ }()
+
+ var hist history
+decodeStream:
+ for {
+ var hasErr bool
+ hist.reset()
+ decodeBlock := func(block *blockDec) {
+ if hasErr {
+ if block != nil {
+ seqDecode <- block
+ }
+ return
+ }
+ if block.err != nil || block.Type != blockTypeCompressed {
+ hasErr = block.err != nil
+ seqDecode <- block
+ return
+ }
+
+ remain, err := block.decodeLiterals(block.data, &hist)
+ block.err = err
+ hasErr = block.err != nil
+ if err == nil {
+ block.async.literals = hist.decoders.literals
+ block.async.seqData = remain
+ } else if debugDecoder {
+ println("decodeLiterals error:", err)
+ }
+ seqDecode <- block
+ }
+ frame := d.frame
+ if debugDecoder {
+ println("New frame...")
+ }
+ var historySent bool
+ frame.history.reset()
+ err := frame.reset(&br)
+ if debugDecoder && err != nil {
+ println("Frame decoder returned", err)
+ }
+ if err == nil {
+ err = d.setDict(frame)
+ }
+ if err == nil && d.frame.WindowSize > d.o.maxWindowSize {
+ if debugDecoder {
+ println("decoder size exceeded, fws:", d.frame.WindowSize, "> mws:", d.o.maxWindowSize)
+ }
+
+ err = ErrDecoderSizeExceeded
+ }
+ if err != nil {
+ select {
+ case <-ctx.Done():
+ case dec := <-d.decoders:
+ dec.sendErr(err)
+ decodeBlock(dec)
+ }
+ break decodeStream
+ }
+
+ // Go through all blocks of the frame.
+ for {
+ var dec *blockDec
+ select {
+ case <-ctx.Done():
+ break decodeStream
+ case dec = <-d.decoders:
+ // Once we have a decoder, we MUST return it.
+ }
+ err := frame.next(dec)
+ if !historySent {
+ h := frame.history
+ if debugDecoder {
+ println("Alloc History:", h.allocFrameBuffer)
+ }
+ hist.reset()
+ if h.dict != nil {
+ hist.setDict(h.dict)
+ }
+ dec.async.newHist = &h
+ dec.async.fcs = frame.FrameContentSize
+ historySent = true
+ } else {
+ dec.async.newHist = nil
+ }
+ if debugDecoder && err != nil {
+ println("next block returned error:", err)
+ }
+ dec.err = err
+ dec.hasCRC = false
+ if dec.Last && frame.HasCheckSum && err == nil {
+ crc, err := frame.rawInput.readSmall(4)
+ if len(crc) < 4 {
+ if err == nil {
+ err = io.ErrUnexpectedEOF
+
+ }
+ println("CRC missing?", err)
+ dec.err = err
+ } else {
+ dec.checkCRC = binary.LittleEndian.Uint32(crc)
+ dec.hasCRC = true
+ if debugDecoder {
+ printf("found crc to check: %08x\n", dec.checkCRC)
+ }
+ }
+ }
+ err = dec.err
+ last := dec.Last
+ decodeBlock(dec)
+ if err != nil {
+ break decodeStream
+ }
+ if last {
+ break
+ }
+ }
+ }
+ close(seqDecode)
+ wg.Wait()
+ hist.reset()
+ d.frame.history.b = frameHistCache
+}
+
+func (d *Decoder) setDict(frame *frameDec) (err error) {
+ dict, ok := d.o.dicts[frame.DictionaryID]
+ if ok {
+ if debugDecoder {
+ println("setting dict", frame.DictionaryID)
+ }
+ frame.history.setDict(dict)
+ } else if frame.DictionaryID != 0 {
+ // A zero or missing dictionary id is ambiguous:
+ // either dictionary zero, or no dictionary. In particular,
+ // zstd --patch-from uses this id for the source file,
+ // so only return an error if the dictionary id is not zero.
+ err = ErrUnknownDictionary
+ }
+ return err
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder_options.go b/vendor/github.com/klauspost/compress/zstd/decoder_options.go
new file mode 100644
index 00000000000..537627a0789
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/decoder_options.go
@@ -0,0 +1,213 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "math/bits"
+ "runtime"
+)
+
+// DOption is an option for creating a decoder.
+type DOption func(*decoderOptions) error
+
+// options retains accumulated state of multiple options.
+type decoderOptions struct {
+ lowMem bool
+ concurrent int
+ maxDecodedSize uint64
+ maxWindowSize uint64
+ dicts map[uint32]*dict
+ ignoreChecksum bool
+ limitToCap bool
+ decodeBufsBelow int
+ resetOpt bool
+}
+
+func (o *decoderOptions) setDefault() {
+ *o = decoderOptions{
+ // use less ram: true for now, but may change.
+ lowMem: true,
+ concurrent: runtime.GOMAXPROCS(0),
+ maxWindowSize: MaxWindowSize,
+ decodeBufsBelow: 128 << 10,
+ }
+ if o.concurrent > 4 {
+ o.concurrent = 4
+ }
+ o.maxDecodedSize = 64 << 30
+}
+
+// WithDecoderLowmem will set whether to use a lower amount of memory,
+// but possibly have to allocate more while running.
+// Cannot be changed with ResetWithOptions.
+func WithDecoderLowmem(b bool) DOption {
+ return func(o *decoderOptions) error {
+ if o.resetOpt && b != o.lowMem {
+ return errors.New("WithDecoderLowmem cannot be changed on Reset")
+ }
+ o.lowMem = b
+ return nil
+ }
+}
+
+// WithDecoderConcurrency sets the number of created decoders.
+// When decoding block with DecodeAll, this will limit the number
+// of possible concurrently running decodes.
+// When decoding streams, this will limit the number of
+// inflight blocks.
+// When decoding streams and setting maximum to 1,
+// no async decoding will be done.
+// The value supplied must be at least 0.
+// When a value of 0 is provided GOMAXPROCS will be used.
+// By default this will be set to 4 or GOMAXPROCS, whatever is lower.
+// Cannot be changed with ResetWithOptions.
+func WithDecoderConcurrency(n int) DOption {
+ return func(o *decoderOptions) error {
+ if n < 0 {
+ return errors.New("concurrency must be at least 0")
+ }
+ newVal := n
+ if n == 0 {
+ newVal = runtime.GOMAXPROCS(0)
+ }
+ if o.resetOpt && newVal != o.concurrent {
+ return errors.New("WithDecoderConcurrency cannot be changed on Reset")
+ }
+ o.concurrent = newVal
+ return nil
+ }
+}
+
+// WithDecoderMaxMemory allows to set a maximum decoded size for in-memory
+// non-streaming operations or maximum window size for streaming operations.
+// This can be used to control memory usage of potentially hostile content.
+// Maximum is 1 << 63 bytes. Default is 64GiB.
+// Can be changed with ResetWithOptions.
+func WithDecoderMaxMemory(n uint64) DOption {
+ return func(o *decoderOptions) error {
+ if n == 0 {
+ return errors.New("WithDecoderMaxMemory must be at least 1")
+ }
+ if n > 1<<63 {
+ return errors.New("WithDecoderMaxmemory must be less than 1 << 63")
+ }
+ o.maxDecodedSize = n
+ return nil
+ }
+}
+
+// WithDecoderDicts allows to register one or more dictionaries for the decoder.
+//
+// Each slice in dict must be in the [dictionary format] produced by
+// "zstd --train" from the Zstandard reference implementation.
+//
+// If several dictionaries with the same ID are provided, the last one will be used.
+// Can be changed with ResetWithOptions.
+//
+// [dictionary format]: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format
+func WithDecoderDicts(dicts ...[]byte) DOption {
+ return func(o *decoderOptions) error {
+ if o.dicts == nil {
+ o.dicts = make(map[uint32]*dict)
+ }
+ for _, b := range dicts {
+ d, err := loadDict(b)
+ if err != nil {
+ return err
+ }
+ o.dicts[d.id] = d
+ }
+ return nil
+ }
+}
+
+// WithDecoderDictRaw registers a dictionary that may be used by the decoder.
+// The slice content can be arbitrary data.
+// Can be changed with ResetWithOptions.
+func WithDecoderDictRaw(id uint32, content []byte) DOption {
+ return func(o *decoderOptions) error {
+ if bits.UintSize > 32 && uint(len(content)) > dictMaxLength {
+ return fmt.Errorf("dictionary of size %d > 2GiB too large", len(content))
+ }
+ if o.dicts == nil {
+ o.dicts = make(map[uint32]*dict)
+ }
+ o.dicts[id] = &dict{id: id, content: content, offsets: [3]int{1, 4, 8}}
+ return nil
+ }
+}
+
+// WithDecoderMaxWindow allows to set a maximum window size for decodes.
+// This allows rejecting packets that will cause big memory usage.
+// The Decoder will likely allocate more memory based on the WithDecoderLowmem setting.
+// If WithDecoderMaxMemory is set to a lower value, that will be used.
+// Default is 512MB, Maximum is ~3.75 TB as per zstandard spec.
+// Can be changed with ResetWithOptions.
+func WithDecoderMaxWindow(size uint64) DOption {
+ return func(o *decoderOptions) error {
+ if size < MinWindowSize {
+ return errors.New("WithMaxWindowSize must be at least 1KB, 1024 bytes")
+ }
+ if size > (1<<41)+7*(1<<38) {
+ return errors.New("WithMaxWindowSize must be less than (1<<41) + 7*(1<<38) ~ 3.75TB")
+ }
+ o.maxWindowSize = size
+ return nil
+ }
+}
+
+// WithDecodeAllCapLimit will limit DecodeAll to decoding cap(dst)-len(dst) bytes,
+// or any size set in WithDecoderMaxMemory.
+// This can be used to limit decoding to a specific maximum output size.
+// Disabled by default.
+// Can be changed with ResetWithOptions.
+func WithDecodeAllCapLimit(b bool) DOption {
+ return func(o *decoderOptions) error {
+ o.limitToCap = b
+ return nil
+ }
+}
+
+// WithDecodeBuffersBelow will fully decode readers that have a
+// `Bytes() []byte` and `Len() int` interface similar to bytes.Buffer.
+// This typically uses less allocations but will have the full decompressed object in memory.
+// Note that DecodeAllCapLimit will disable this, as well as giving a size of 0 or less.
+// Default is 128KiB.
+// Cannot be changed with ResetWithOptions.
+func WithDecodeBuffersBelow(size int) DOption {
+ return func(o *decoderOptions) error {
+ if o.resetOpt && size != o.decodeBufsBelow {
+ return errors.New("WithDecodeBuffersBelow cannot be changed on Reset")
+ }
+ o.decodeBufsBelow = size
+ return nil
+ }
+}
+
+// IgnoreChecksum allows to forcibly ignore checksum checking.
+// Can be changed with ResetWithOptions.
+func IgnoreChecksum(b bool) DOption {
+ return func(o *decoderOptions) error {
+ o.ignoreChecksum = b
+ return nil
+ }
+}
+
+// WithDecoderDictDelete removes dictionaries by ID.
+// If no ids are passed, all dictionaries are deleted.
+// Should be used with ResetWithOptions.
+func WithDecoderDictDelete(ids ...uint32) DOption {
+ return func(o *decoderOptions) error {
+ if len(ids) == 0 {
+ clear(o.dicts)
+ }
+ for _, id := range ids {
+ delete(o.dicts, id)
+ }
+ return nil
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/dict.go b/vendor/github.com/klauspost/compress/zstd/dict.go
new file mode 100644
index 00000000000..2ffbfdf379e
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/dict.go
@@ -0,0 +1,559 @@
+package zstd
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "sort"
+
+ "github.com/klauspost/compress/huff0"
+)
+
+type dict struct {
+ id uint32
+
+ litEnc *huff0.Scratch
+ llDec, ofDec, mlDec sequenceDec
+ offsets [3]int
+ content []byte
+}
+
+const dictMagic = "\x37\xa4\x30\xec"
+
+// Maximum dictionary size for the reference implementation (1.5.3) is 2 GiB.
+const dictMaxLength = 1 << 31
+
+// ID returns the dictionary id or 0 if d is nil.
+func (d *dict) ID() uint32 {
+ if d == nil {
+ return 0
+ }
+ return d.id
+}
+
+// ContentSize returns the dictionary content size or 0 if d is nil.
+func (d *dict) ContentSize() int {
+ if d == nil {
+ return 0
+ }
+ return len(d.content)
+}
+
+// Content returns the dictionary content.
+func (d *dict) Content() []byte {
+ if d == nil {
+ return nil
+ }
+ return d.content
+}
+
+// Offsets returns the initial offsets.
+func (d *dict) Offsets() [3]int {
+ if d == nil {
+ return [3]int{}
+ }
+ return d.offsets
+}
+
+// LitEncoder returns the literal encoder.
+func (d *dict) LitEncoder() *huff0.Scratch {
+ if d == nil {
+ return nil
+ }
+ return d.litEnc
+}
+
+// Load a dictionary as described in
+// https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
+func loadDict(b []byte) (*dict, error) {
+ // Check static field size.
+ if len(b) <= 8+(3*4) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ d := dict{
+ llDec: sequenceDec{fse: &fseDecoder{}},
+ ofDec: sequenceDec{fse: &fseDecoder{}},
+ mlDec: sequenceDec{fse: &fseDecoder{}},
+ }
+ if string(b[:4]) != dictMagic {
+ return nil, ErrMagicMismatch
+ }
+ d.id = binary.LittleEndian.Uint32(b[4:8])
+ if d.id == 0 {
+ return nil, errors.New("dictionaries cannot have ID 0")
+ }
+
+ // Read literal table
+ var err error
+ d.litEnc, b, err = huff0.ReadTable(b[8:], nil)
+ if err != nil {
+ return nil, fmt.Errorf("loading literal table: %w", err)
+ }
+ d.litEnc.Reuse = huff0.ReusePolicyMust
+
+ br := byteReader{
+ b: b,
+ off: 0,
+ }
+ readDec := func(i tableIndex, dec *fseDecoder) error {
+ if err := dec.readNCount(&br, uint16(maxTableSymbol[i])); err != nil {
+ return err
+ }
+ if br.overread() {
+ return io.ErrUnexpectedEOF
+ }
+ err = dec.transform(symbolTableX[i])
+ if err != nil {
+ println("Transform table error:", err)
+ return err
+ }
+ if debugDecoder || debugEncoder {
+ println("Read table ok", "symbolLen:", dec.symbolLen)
+ }
+ // Set decoders as predefined so they aren't reused.
+ dec.preDefined = true
+ return nil
+ }
+
+ if err := readDec(tableOffsets, d.ofDec.fse); err != nil {
+ return nil, err
+ }
+ if err := readDec(tableMatchLengths, d.mlDec.fse); err != nil {
+ return nil, err
+ }
+ if err := readDec(tableLiteralLengths, d.llDec.fse); err != nil {
+ return nil, err
+ }
+ if br.remain() < 12 {
+ return nil, io.ErrUnexpectedEOF
+ }
+
+ d.offsets[0] = int(br.Uint32())
+ br.advance(4)
+ d.offsets[1] = int(br.Uint32())
+ br.advance(4)
+ d.offsets[2] = int(br.Uint32())
+ br.advance(4)
+ if d.offsets[0] <= 0 || d.offsets[1] <= 0 || d.offsets[2] <= 0 {
+ return nil, errors.New("invalid offset in dictionary")
+ }
+ d.content = make([]byte, br.remain())
+ copy(d.content, br.unread())
+ if d.offsets[0] > len(d.content) || d.offsets[1] > len(d.content) || d.offsets[2] > len(d.content) {
+ return nil, fmt.Errorf("initial offset bigger than dictionary content size %d, offsets: %v", len(d.content), d.offsets)
+ }
+
+ return &d, nil
+}
+
+// InspectDictionary loads a zstd dictionary and provides functions to inspect the content.
+func InspectDictionary(b []byte) (interface {
+ ID() uint32
+ ContentSize() int
+ Content() []byte
+ Offsets() [3]int
+ LitEncoder() *huff0.Scratch
+}, error) {
+ initPredefined()
+ d, err := loadDict(b)
+ return d, err
+}
+
+type BuildDictOptions struct {
+ // Dictionary ID.
+ ID uint32
+
+ // Content to use to create dictionary tables.
+ Contents [][]byte
+
+ // History to use for all blocks.
+ History []byte
+
+ // Offsets to use.
+ Offsets [3]int
+
+ // CompatV155 will make the dictionary compatible with Zstd v1.5.5 and earlier.
+ // See https://github.com/facebook/zstd/issues/3724
+ CompatV155 bool
+
+ // Use the specified encoder level.
+ // The dictionary will be built using the specified encoder level,
+ // which will reflect speed and make the dictionary tailored for that level.
+ // If not set SpeedBestCompression will be used.
+ Level EncoderLevel
+
+ // DebugOut will write stats and other details here if set.
+ DebugOut io.Writer
+}
+
+func BuildDict(o BuildDictOptions) ([]byte, error) {
+ initPredefined()
+ hist := o.History
+ contents := o.Contents
+ debug := o.DebugOut != nil
+ println := func(args ...any) {
+ if o.DebugOut != nil {
+ fmt.Fprintln(o.DebugOut, args...)
+ }
+ }
+ printf := func(s string, args ...any) {
+ if o.DebugOut != nil {
+ fmt.Fprintf(o.DebugOut, s, args...)
+ }
+ }
+ print := func(args ...any) {
+ if o.DebugOut != nil {
+ fmt.Fprint(o.DebugOut, args...)
+ }
+ }
+
+ if int64(len(hist)) > dictMaxLength {
+ return nil, fmt.Errorf("dictionary of size %d > %d", len(hist), int64(dictMaxLength))
+ }
+ if len(hist) < 8 {
+ return nil, fmt.Errorf("dictionary of size %d < %d", len(hist), 8)
+ }
+ if len(contents) == 0 {
+ return nil, errors.New("no content provided")
+ }
+ d := dict{
+ id: o.ID,
+ litEnc: nil,
+ llDec: sequenceDec{},
+ ofDec: sequenceDec{},
+ mlDec: sequenceDec{},
+ offsets: o.Offsets,
+ content: hist,
+ }
+ block := blockEnc{lowMem: false}
+ block.init()
+ enc := encoder(&bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(maxMatchLen), bufferReset: math.MaxInt32 - int32(maxMatchLen*2), lowMem: false}})
+ if o.Level != 0 {
+ eOpts := encoderOptions{
+ level: o.Level,
+ blockSize: maxMatchLen,
+ windowSize: maxMatchLen,
+ dict: &d,
+ lowMem: false,
+ }
+ enc = eOpts.encoder()
+ } else {
+ o.Level = SpeedBestCompression
+ }
+ var (
+ remain [256]int
+ ll [256]int
+ ml [256]int
+ of [256]int
+ )
+ addValues := func(dst *[256]int, src []byte) {
+ for _, v := range src {
+ dst[v]++
+ }
+ }
+ addHist := func(dst *[256]int, src *[256]uint32) {
+ for i, v := range src {
+ dst[i] += int(v)
+ }
+ }
+ seqs := 0
+ nUsed := 0
+ litTotal := 0
+ newOffsets := make(map[uint32]int, 1000)
+ for _, b := range contents {
+ block.reset(nil)
+ if len(b) < 8 {
+ continue
+ }
+ nUsed++
+ enc.Reset(&d, true)
+ enc.Encode(&block, b)
+ addValues(&remain, block.literals)
+ litTotal += len(block.literals)
+ if len(block.sequences) == 0 {
+ continue
+ }
+ seqs += len(block.sequences)
+ block.genCodes()
+ addHist(&ll, block.coders.llEnc.Histogram())
+ addHist(&ml, block.coders.mlEnc.Histogram())
+ addHist(&of, block.coders.ofEnc.Histogram())
+ for i, seq := range block.sequences {
+ if i > 3 {
+ break
+ }
+ offset := seq.offset
+ if offset == 0 {
+ continue
+ }
+ if int(offset) >= len(o.History) {
+ continue
+ }
+ if offset > 3 {
+ newOffsets[offset-3]++
+ } else {
+ newOffsets[uint32(o.Offsets[offset-1])]++
+ }
+ }
+ }
+ // Find most used offsets.
+ var sortedOffsets []uint32
+ for k := range newOffsets {
+ sortedOffsets = append(sortedOffsets, k)
+ }
+ sort.Slice(sortedOffsets, func(i, j int) bool {
+ a, b := sortedOffsets[i], sortedOffsets[j]
+ if a == b {
+ // Prefer the longer offset
+ return sortedOffsets[i] > sortedOffsets[j]
+ }
+ return newOffsets[sortedOffsets[i]] > newOffsets[sortedOffsets[j]]
+ })
+ if len(sortedOffsets) > 3 {
+ if debug {
+ print("Offsets:")
+ for i, v := range sortedOffsets {
+ if i > 20 {
+ break
+ }
+ printf("[%d: %d],", v, newOffsets[v])
+ }
+ println("")
+ }
+
+ sortedOffsets = sortedOffsets[:3]
+ }
+ for i, v := range sortedOffsets {
+ o.Offsets[i] = int(v)
+ }
+ if debug {
+ println("New repeat offsets", o.Offsets)
+ }
+
+ if nUsed == 0 || seqs == 0 {
+ return nil, fmt.Errorf("%d blocks, %d sequences found", nUsed, seqs)
+ }
+ if debug {
+ println("Sequences:", seqs, "Blocks:", nUsed, "Literals:", litTotal)
+ }
+ if seqs/nUsed < 512 {
+ // Use 512 as minimum.
+ nUsed = seqs / 512
+ if nUsed == 0 {
+ nUsed = 1
+ }
+ }
+ copyHist := func(dst *fseEncoder, src *[256]int) ([]byte, error) {
+ hist := dst.Histogram()
+ var maxSym uint8
+ var maxCount int
+ var fakeLength int
+ for i, v := range src {
+ if v > 0 {
+ v = v / nUsed
+ if v == 0 {
+ v = 1
+ }
+ }
+ if v > maxCount {
+ maxCount = v
+ }
+ if v != 0 {
+ maxSym = uint8(i)
+ }
+ fakeLength += v
+ hist[i] = uint32(v)
+ }
+
+ // Ensure we aren't trying to represent RLE.
+ if maxCount == fakeLength {
+ for i := range hist {
+ if uint8(i) == maxSym {
+ fakeLength++
+ maxSym++
+ hist[i+1] = 1
+ if maxSym > 1 {
+ break
+ }
+ }
+ if hist[0] == 0 {
+ fakeLength++
+ hist[i] = 1
+ if maxSym > 1 {
+ break
+ }
+ }
+ }
+ }
+
+ dst.HistogramFinished(maxSym, maxCount)
+ dst.reUsed = false
+ dst.useRLE = false
+ err := dst.normalizeCount(fakeLength)
+ if err != nil {
+ return nil, err
+ }
+ if debug {
+ println("RAW:", dst.count[:maxSym+1], "NORM:", dst.norm[:maxSym+1], "LEN:", fakeLength)
+ }
+ return dst.writeCount(nil)
+ }
+ if debug {
+ print("Literal lengths: ")
+ }
+ llTable, err := copyHist(block.coders.llEnc, &ll)
+ if err != nil {
+ return nil, err
+ }
+ if debug {
+ print("Match lengths: ")
+ }
+ mlTable, err := copyHist(block.coders.mlEnc, &ml)
+ if err != nil {
+ return nil, err
+ }
+ if debug {
+ print("Offsets: ")
+ }
+ ofTable, err := copyHist(block.coders.ofEnc, &of)
+ if err != nil {
+ return nil, err
+ }
+
+ // Literal table
+ avgSize := min(litTotal, huff0.BlockSizeMax/2)
+ huffBuff := make([]byte, 0, avgSize)
+ // Target size
+ div := max(litTotal/avgSize, 1)
+ if debug {
+ println("Huffman weights:")
+ }
+ for i, n := range remain[:] {
+ if n > 0 {
+ n = n / div
+ // Allow all entries to be represented.
+ if n == 0 {
+ n = 1
+ }
+ huffBuff = append(huffBuff, bytes.Repeat([]byte{byte(i)}, n)...)
+ if debug {
+ printf("[%d: %d], ", i, n)
+ }
+ }
+ }
+ if o.CompatV155 && remain[255]/div == 0 {
+ huffBuff = append(huffBuff, 255)
+ }
+ scratch := &huff0.Scratch{TableLog: 11}
+ for tries := range 255 {
+ scratch = &huff0.Scratch{TableLog: 11}
+ _, _, err = huff0.Compress1X(huffBuff, scratch)
+ if err == nil {
+ break
+ }
+ if debug {
+ printf("Try %d: Huffman error: %v\n", tries+1, err)
+ }
+ huffBuff = huffBuff[:0]
+ if tries == 250 {
+ if debug {
+ println("Huffman: Bailing out with predefined table")
+ }
+
+ // Bail out.... Just generate something
+ huffBuff = append(huffBuff, bytes.Repeat([]byte{255}, 10000)...)
+ for i := range 128 {
+ huffBuff = append(huffBuff, byte(i))
+ }
+ continue
+ }
+ if errors.Is(err, huff0.ErrIncompressible) {
+ // Try truncating least common.
+ for i, n := range remain[:] {
+ if n > 0 {
+ n = n / (div * (i + 1))
+ if n > 0 {
+ huffBuff = append(huffBuff, bytes.Repeat([]byte{byte(i)}, n)...)
+ }
+ }
+ }
+ if o.CompatV155 && len(huffBuff) > 0 && huffBuff[len(huffBuff)-1] != 255 {
+ huffBuff = append(huffBuff, 255)
+ }
+ if len(huffBuff) == 0 {
+ huffBuff = append(huffBuff, 0, 255)
+ }
+ }
+ if errors.Is(err, huff0.ErrUseRLE) {
+ for i, n := range remain[:] {
+ n = n / (div * (i + 1))
+ // Allow all entries to be represented.
+ if n == 0 {
+ n = 1
+ }
+ huffBuff = append(huffBuff, bytes.Repeat([]byte{byte(i)}, n)...)
+ }
+ }
+ }
+
+ var out bytes.Buffer
+ out.Write([]byte(dictMagic))
+ out.Write(binary.LittleEndian.AppendUint32(nil, o.ID))
+ out.Write(scratch.OutTable)
+ if debug {
+ println("huff table:", len(scratch.OutTable), "bytes")
+ println("of table:", len(ofTable), "bytes")
+ println("ml table:", len(mlTable), "bytes")
+ println("ll table:", len(llTable), "bytes")
+ }
+ out.Write(ofTable)
+ out.Write(mlTable)
+ out.Write(llTable)
+ out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[0])))
+ out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[1])))
+ out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[2])))
+ out.Write(hist)
+ if debug {
+ _, err := loadDict(out.Bytes())
+ if err != nil {
+ panic(err)
+ }
+ i, err := InspectDictionary(out.Bytes())
+ if err != nil {
+ panic(err)
+ }
+ println("ID:", i.ID())
+ println("Content size:", i.ContentSize())
+ println("Encoder:", i.LitEncoder() != nil)
+ println("Offsets:", i.Offsets())
+ var totalSize int
+ for _, b := range contents {
+ totalSize += len(b)
+ }
+
+ encWith := func(opts ...EOption) int {
+ enc, err := NewWriter(nil, opts...)
+ if err != nil {
+ panic(err)
+ }
+ defer enc.Close()
+ var dst []byte
+ var totalSize int
+ for _, b := range contents {
+ dst = enc.EncodeAll(b, dst[:0])
+ totalSize += len(dst)
+ }
+ return totalSize
+ }
+ plain := encWith(WithEncoderLevel(o.Level))
+ withDict := encWith(WithEncoderLevel(o.Level), WithEncoderDict(out.Bytes()))
+ println("Input size:", totalSize)
+ println("Plain Compressed:", plain)
+ println("Dict Compressed:", withDict)
+ println("Saved:", plain-withDict, (plain-withDict)/len(contents), "bytes per input (rounded down)")
+ }
+ return out.Bytes(), nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_base.go b/vendor/github.com/klauspost/compress/zstd/enc_base.go
new file mode 100644
index 00000000000..c4de134a7a4
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_base.go
@@ -0,0 +1,171 @@
+package zstd
+
+import (
+ "fmt"
+ "math/bits"
+
+ "github.com/klauspost/compress/zstd/internal/xxhash"
+)
+
+const (
+ dictShardBits = 7
+)
+
+type fastBase struct {
+ // cur is the offset at the start of hist
+ cur int32
+ // maximum offset. Should be at least 2x block size.
+ maxMatchOff int32
+ bufferReset int32
+ hist []byte
+ crc *xxhash.Digest
+ tmp [8]byte
+ blk *blockEnc
+ lastDict *dict
+ lowMem bool
+}
+
+// CRC returns the underlying CRC writer.
+func (e *fastBase) CRC() *xxhash.Digest {
+ return e.crc
+}
+
+// AppendCRC will append the CRC to the destination slice and return it.
+func (e *fastBase) AppendCRC(dst []byte) []byte {
+ crc := e.crc.Sum(e.tmp[:0])
+ dst = append(dst, crc[7], crc[6], crc[5], crc[4])
+ return dst
+}
+
+// WindowSize returns the window size of the encoder,
+// or a window size small enough to contain the input size, if > 0.
+func (e *fastBase) WindowSize(size int64) int32 {
+ if size > 0 && size < int64(e.maxMatchOff) {
+ b := max(
+ // Keep minimum window.
+ int32(1)< e.bufferReset {
+ panic(fmt.Sprintf("ecur (%d) > buffer reset (%d)", e.cur, e.bufferReset))
+ }
+ // check if we have space already
+ if len(e.hist)+len(src) > cap(e.hist) {
+ if cap(e.hist) == 0 {
+ e.ensureHist(len(src))
+ } else {
+ if cap(e.hist) < int(e.maxMatchOff+maxCompressedBlockSize) {
+ panic(fmt.Errorf("unexpected buffer cap %d, want at least %d with window %d", cap(e.hist), e.maxMatchOff+maxCompressedBlockSize, e.maxMatchOff))
+ }
+ // Move down
+ offset := int32(len(e.hist)) - e.maxMatchOff
+ copy(e.hist[0:e.maxMatchOff], e.hist[offset:])
+ e.cur += offset
+ e.hist = e.hist[:e.maxMatchOff]
+ }
+ }
+ s := int32(len(e.hist))
+ e.hist = append(e.hist, src...)
+ return s
+}
+
+// ensureHist will ensure that history can keep at least this many bytes.
+func (e *fastBase) ensureHist(n int) {
+ if cap(e.hist) >= n {
+ return
+ }
+ l := e.maxMatchOff
+ if (e.lowMem && e.maxMatchOff > maxCompressedBlockSize) || e.maxMatchOff <= maxCompressedBlockSize {
+ l += maxCompressedBlockSize
+ } else {
+ l += e.maxMatchOff
+ }
+ // Make it at least 1MB.
+ if l < 1<<20 && !e.lowMem {
+ l = 1 << 20
+ }
+ // Make it at least the requested size.
+ if l < int32(n) {
+ l = int32(n)
+ }
+ e.hist = make([]byte, 0, l)
+}
+
+// useBlock will replace the block with the provided one,
+// but transfer recent offsets from the previous.
+func (e *fastBase) UseBlock(enc *blockEnc) {
+ enc.reset(e.blk)
+ e.blk = enc
+}
+
+func (e *fastBase) matchlen(s, t int32, src []byte) int32 {
+ if debugAsserts {
+ if s < 0 {
+ err := fmt.Sprintf("s (%d) < 0", s)
+ panic(err)
+ }
+ if t < 0 {
+ err := fmt.Sprintf("t (%d) < 0", t)
+ panic(err)
+ }
+ if s-t > e.maxMatchOff {
+ err := fmt.Sprintf("s (%d) - t (%d) > maxMatchOff (%d)", s, t, e.maxMatchOff)
+ panic(err)
+ }
+ if len(src)-int(s) > maxCompressedBlockSize {
+ panic(fmt.Sprintf("len(src)-s (%d) > maxCompressedBlockSize (%d)", len(src)-int(s), maxCompressedBlockSize))
+ }
+ }
+ return int32(matchLen(src[s:], src[t:]))
+}
+
+// Reset the encoding table.
+func (e *fastBase) resetBase(d *dict, singleBlock bool) {
+ if e.blk == nil {
+ e.blk = &blockEnc{lowMem: e.lowMem}
+ e.blk.init()
+ } else {
+ e.blk.reset(nil)
+ }
+ e.blk.initNewEncode()
+ if e.crc == nil {
+ e.crc = xxhash.New()
+ } else {
+ e.crc.Reset()
+ }
+ e.blk.dictLitEnc = nil
+ if d != nil {
+ low := e.lowMem
+ if singleBlock {
+ e.lowMem = true
+ }
+ e.ensureHist(d.ContentSize() + maxCompressedBlockSize)
+ e.lowMem = low
+ }
+
+ // We offset current position so everything will be out of reach.
+ // If above reset line, history will be purged.
+ if e.cur < e.bufferReset {
+ e.cur += e.maxMatchOff + int32(len(e.hist))
+ }
+ e.hist = e.hist[:0]
+ if d != nil {
+ // Set offsets (currently not used)
+ for i, off := range d.offsets {
+ e.blk.recentOffsets[i] = uint32(off)
+ e.blk.prevRecentOffsets[i] = e.blk.recentOffsets[i]
+ }
+ // Transfer litenc.
+ e.blk.dictLitEnc = d.litEnc
+ e.hist = append(e.hist, d.content...)
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_best.go b/vendor/github.com/klauspost/compress/zstd/enc_best.go
new file mode 100644
index 00000000000..851799322bd
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_best.go
@@ -0,0 +1,553 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/klauspost/compress"
+)
+
+const (
+ bestLongTableBits = 22 // Bits used in the long match table
+ bestLongTableSize = 1 << bestLongTableBits // Size of the table
+ bestLongLen = 8 // Bytes used for table hash
+
+ // Note: Increasing the short table bits or making the hash shorter
+ // can actually lead to compression degradation since it will 'steal' more from the
+ // long match table and match offsets are quite big.
+ // This greatly depends on the type of input.
+ bestShortTableBits = 18 // Bits used in the short match table
+ bestShortTableSize = 1 << bestShortTableBits // Size of the table
+ bestShortLen = 4 // Bytes used for table hash
+
+)
+
+type match struct {
+ offset int32
+ s int32
+ length int32
+ rep int32
+ est int32
+}
+
+const highScore = maxMatchLen * 8
+
+// estBits will estimate output bits from predefined tables.
+func (m *match) estBits(bitsPerByte int32) {
+ mlc := mlCode(uint32(m.length - zstdMinMatch))
+ var ofc uint8
+ if m.rep < 0 {
+ ofc = ofCode(uint32(m.s-m.offset) + 3)
+ } else {
+ ofc = ofCode(uint32(m.rep) & 3)
+ }
+ // Cost, excluding
+ ofTT, mlTT := fsePredefEnc[tableOffsets].ct.symbolTT[ofc], fsePredefEnc[tableMatchLengths].ct.symbolTT[mlc]
+
+ // Add cost of match encoding...
+ m.est = int32(ofTT.outBits + mlTT.outBits)
+ m.est += int32(ofTT.deltaNbBits>>16 + mlTT.deltaNbBits>>16)
+ // Subtract savings compared to literal encoding...
+ m.est -= (m.length * bitsPerByte) >> 10
+ if m.est > 0 {
+ // Unlikely gain..
+ m.length = 0
+ m.est = highScore
+ }
+}
+
+// bestFastEncoder uses 2 tables, one for short matches (5 bytes) and one for long matches.
+// The long match table contains the previous entry with the same hash,
+// effectively making it a "chain" of length 2.
+// When we find a long match we choose between the two values and select the longest.
+// When we find a short match, after checking the long, we check if we can find a long at n+1
+// and that it is longer (lazy matching).
+type bestFastEncoder struct {
+ fastBase
+ table [bestShortTableSize]prevEntry
+ longTable [bestLongTableSize]prevEntry
+ dictTable []prevEntry
+ dictLongTable []prevEntry
+}
+
+// Encode improves compression...
+func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 4
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ e.table = [bestShortTableSize]prevEntry{}
+ e.longTable = [bestLongTableSize]prevEntry{}
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ v2 := e.table[i].prev
+ if v < minOff {
+ v = 0
+ v2 = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ if v2 < minOff {
+ v2 = 0
+ } else {
+ v2 = v2 - e.cur + e.maxMatchOff
+ }
+ }
+ e.table[i] = prevEntry{
+ offset: v,
+ prev: v2,
+ }
+ }
+ for i := range e.longTable[:] {
+ v := e.longTable[i].offset
+ v2 := e.longTable[i].prev
+ if v < minOff {
+ v = 0
+ v2 = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ if v2 < minOff {
+ v2 = 0
+ } else {
+ v2 = v2 - e.cur + e.maxMatchOff
+ }
+ }
+ e.longTable[i] = prevEntry{
+ offset: v,
+ prev: v2,
+ }
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ // Add block to history
+ s := e.addBlock(src)
+ blk.size = len(src)
+
+ // Check RLE first
+ if len(src) > zstdMinMatch {
+ ml := matchLen(src[1:], src)
+ if ml == len(src)-1 {
+ blk.literals = append(blk.literals, src[0])
+ blk.sequences = append(blk.sequences, seq{litLen: 1, matchLen: uint32(len(src)-1) - zstdMinMatch, offset: 1 + 3})
+ return
+ }
+ }
+
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Use this to estimate literal cost.
+ // Scaled by 10 bits.
+ bitsPerByte := max(
+ // Huffman can never go < 1 bit/byte
+ int32((compress.ShannonEntropyBits(src)*1024)/len(src)), 1024)
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ const kSearchStrength = 10
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+ offset3 := int32(blk.recentOffsets[2])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ // We allow the encoder to optionally turn off repeat offsets across blocks
+ canRepeat := len(blk.sequences) > 2
+
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ const goodEnough = 250
+
+ cv := load6432(src, s)
+
+ nextHashL := hashLen(cv, bestLongTableBits, bestLongLen)
+ nextHashS := hashLen(cv, bestShortTableBits, bestShortLen)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ // Set m to a match at offset if it looks like that will improve compression.
+ improve := func(m *match, offset int32, s int32, first uint32, rep int32) {
+ delta := s - offset
+ if delta >= e.maxMatchOff || delta <= 0 || load3232(src, offset) != first {
+ return
+ }
+ // Try to quick reject if we already have a long match.
+ if m.length > 16 {
+ left := len(src) - int(m.s+m.length)
+ // If we are too close to the end, keep as is.
+ if left <= 0 {
+ return
+ }
+ checkLen := m.length - (s - m.s) - 8
+ if left > 2 && checkLen > 4 {
+ // Check 4 bytes, 4 bytes from the end of the current match.
+ a := load3232(src, offset+checkLen)
+ b := load3232(src, s+checkLen)
+ if a != b {
+ return
+ }
+ }
+ }
+ l := 4 + e.matchlen(s+4, offset+4, src)
+ if m.rep <= 0 {
+ // Extend candidate match backwards as far as possible.
+ // Do not extend repeats as we can assume they are optimal
+ // and offsets change if s == nextEmit.
+ tMin := max(s-e.maxMatchOff, 0)
+ for offset > tMin && s > nextEmit && src[offset-1] == src[s-1] && l < maxMatchLength {
+ s--
+ offset--
+ l++
+ }
+ }
+ if debugAsserts {
+ if offset >= s {
+ panic(fmt.Sprintf("offset: %d - s:%d - rep: %d - cur :%d - max: %d", offset, s, rep, e.cur, e.maxMatchOff))
+ }
+ if !bytes.Equal(src[s:s+l], src[offset:offset+l]) {
+ panic(fmt.Sprintf("second match mismatch: %v != %v, first: %08x", src[s:s+4], src[offset:offset+4], first))
+ }
+ }
+ cand := match{offset: offset, s: s, length: l, rep: rep}
+ cand.estBits(bitsPerByte)
+ if m.est >= highScore || cand.est-m.est+(cand.s-m.s)*bitsPerByte>>10 < 0 {
+ *m = cand
+ }
+ }
+
+ best := match{s: s, est: highScore}
+ improve(&best, candidateL.offset-e.cur, s, uint32(cv), -1)
+ improve(&best, candidateL.prev-e.cur, s, uint32(cv), -1)
+ improve(&best, candidateS.offset-e.cur, s, uint32(cv), -1)
+ improve(&best, candidateS.prev-e.cur, s, uint32(cv), -1)
+
+ if canRepeat && best.length < goodEnough {
+ if s == nextEmit {
+ // Check repeats straight after a match.
+ improve(&best, s-offset2, s, uint32(cv), 1|4)
+ improve(&best, s-offset3, s, uint32(cv), 2|4)
+ if offset1 > 1 {
+ improve(&best, s-(offset1-1), s, uint32(cv), 3|4)
+ }
+ }
+
+ // If either no match or a non-repeat match, check at + 1
+ if best.rep <= 0 {
+ cv32 := uint32(cv >> 8)
+ spp := s + 1
+ improve(&best, spp-offset1, spp, cv32, 1)
+ improve(&best, spp-offset2, spp, cv32, 2)
+ improve(&best, spp-offset3, spp, cv32, 3)
+ if best.rep < 0 {
+ cv32 = uint32(cv >> 24)
+ spp += 2
+ improve(&best, spp-offset1, spp, cv32, 1)
+ improve(&best, spp-offset2, spp, cv32, 2)
+ improve(&best, spp-offset3, spp, cv32, 3)
+ }
+ }
+ }
+ // Load next and check...
+ e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: candidateL.offset}
+ e.table[nextHashS] = prevEntry{offset: s + e.cur, prev: candidateS.offset}
+ index0 := s + 1
+
+ // Look far ahead, unless we have a really long match already...
+ if best.length < goodEnough {
+ // No match found, move forward on input, no need to check forward...
+ if best.length < 4 {
+ s += 1 + (s-nextEmit)>>(kSearchStrength-1)
+ if s >= sLimit {
+ break encodeLoop
+ }
+ continue
+ }
+
+ candidateS = e.table[hashLen(cv>>8, bestShortTableBits, bestShortLen)]
+ cv = load6432(src, s+1)
+ cv2 := load6432(src, s+2)
+ candidateL = e.longTable[hashLen(cv, bestLongTableBits, bestLongLen)]
+ candidateL2 := e.longTable[hashLen(cv2, bestLongTableBits, bestLongLen)]
+
+ // Short at s+1
+ improve(&best, candidateS.offset-e.cur, s+1, uint32(cv), -1)
+ // Long at s+1, s+2
+ improve(&best, candidateL.offset-e.cur, s+1, uint32(cv), -1)
+ improve(&best, candidateL.prev-e.cur, s+1, uint32(cv), -1)
+ improve(&best, candidateL2.offset-e.cur, s+2, uint32(cv2), -1)
+ improve(&best, candidateL2.prev-e.cur, s+2, uint32(cv2), -1)
+ if false {
+ // Short at s+3.
+ // Too often worse...
+ improve(&best, e.table[hashLen(cv2>>8, bestShortTableBits, bestShortLen)].offset-e.cur, s+3, uint32(cv2>>8), -1)
+ }
+
+ // Start check at a fixed offset to allow for a few mismatches.
+ // For this compression level 2 yields the best results.
+ // We cannot do this if we have already indexed this position.
+ const skipBeginning = 2
+ if best.s > s-skipBeginning {
+ // See if we can find a better match by checking where the current best ends.
+ // Use that offset to see if we can find a better full match.
+ if sAt := best.s + best.length; sAt < sLimit {
+ nextHashL := hashLen(load6432(src, sAt), bestLongTableBits, bestLongLen)
+ candidateEnd := e.longTable[nextHashL]
+
+ if off := candidateEnd.offset - e.cur - best.length + skipBeginning; off >= 0 {
+ improve(&best, off, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
+ if off := candidateEnd.prev - e.cur - best.length + skipBeginning; off >= 0 {
+ improve(&best, off, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
+ }
+ }
+ }
+ }
+ }
+
+ if debugAsserts {
+ if best.offset >= best.s {
+ panic(fmt.Sprintf("best.offset > s: %d >= %d", best.offset, best.s))
+ }
+ if best.s < nextEmit {
+ panic(fmt.Sprintf("s %d < nextEmit %d", best.s, nextEmit))
+ }
+ if best.offset < s-e.maxMatchOff {
+ panic(fmt.Sprintf("best.offset < s-e.maxMatchOff: %d < %d", best.offset, s-e.maxMatchOff))
+ }
+ if !bytes.Equal(src[best.s:best.s+best.length], src[best.offset:best.offset+best.length]) {
+ panic(fmt.Sprintf("match mismatch: %v != %v", src[best.s:best.s+best.length], src[best.offset:best.offset+best.length]))
+ }
+ }
+
+ // We have a match, we can store the forward value
+ s = best.s
+ if best.rep > 0 {
+ var seq seq
+ seq.matchLen = uint32(best.length - zstdMinMatch)
+ addLiterals(&seq, best.s)
+
+ // Repeat. If bit 4 is set, this is a non-lit repeat.
+ seq.offset = uint32(best.rep & 3)
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", best.s, "off:", best.s-best.offset)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Index old s + 1 -> s - 1
+ s = best.s + best.length
+ nextEmit = s
+
+ // Index skipped...
+ end := min(s, sLimit+4)
+ off := index0 + e.cur
+ for index0 < end {
+ cv0 := load6432(src, index0)
+ h0 := hashLen(cv0, bestLongTableBits, bestLongLen)
+ h1 := hashLen(cv0, bestShortTableBits, bestShortLen)
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.table[h1] = prevEntry{offset: off, prev: e.table[h1].offset}
+ off++
+ index0++
+ }
+
+ switch best.rep {
+ case 2, 4 | 1:
+ offset1, offset2 = offset2, offset1
+ case 3, 4 | 2:
+ offset1, offset2, offset3 = offset3, offset1, offset2
+ case 4 | 3:
+ offset1, offset2, offset3 = offset1-1, offset1, offset2
+ }
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, best.length)
+ }
+ break encodeLoop
+ }
+ continue
+ }
+
+ // A 4-byte match has been found. Update recent offsets.
+ // We'll later see if more than 4 bytes.
+ t := best.offset
+ offset1, offset2, offset3 = s-t, offset1, offset2
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Write our sequence
+ var seq seq
+ l := best.length
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+
+ // Index old s + 1 -> s - 1 or sLimit
+ end := min(s, sLimit-4)
+
+ off := index0 + e.cur
+ for index0 < end {
+ cv0 := load6432(src, index0)
+ h0 := hashLen(cv0, bestLongTableBits, bestLongLen)
+ h1 := hashLen(cv0, bestShortTableBits, bestShortLen)
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.table[h1] = prevEntry{offset: off, prev: e.table[h1].offset}
+ index0++
+ off++
+ }
+ if s >= sLimit {
+ break encodeLoop
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ blk.recentOffsets[2] = uint32(offset3)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// EncodeNoHist will encode a block with no history and no following blocks.
+// Most notable difference is that src will not be copied for history and
+// we do not need to check for max match length.
+func (e *bestFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
+ e.ensureHist(len(src))
+ e.Encode(blk, src)
+}
+
+// Reset will reset and set a dictionary if not nil
+func (e *bestFastEncoder) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d == nil {
+ return
+ }
+ dictChanged := d != e.lastDict
+ // Init or copy dict table
+ if len(e.dictTable) != len(e.table) || dictChanged {
+ if len(e.dictTable) != len(e.table) {
+ e.dictTable = make([]prevEntry, len(e.table))
+ } else {
+ clear(e.dictTable)
+ }
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ for i := e.maxMatchOff; i < end; i += 4 {
+ const hashLog = bestShortTableBits
+
+ cv := load6432(d.content, i-e.maxMatchOff)
+ nextHash := hashLen(cv, hashLog, bestShortLen) // 0 -> 4
+ nextHash1 := hashLen(cv>>8, hashLog, bestShortLen) // 1 -> 5
+ nextHash2 := hashLen(cv>>16, hashLog, bestShortLen) // 2 -> 6
+ nextHash3 := hashLen(cv>>24, hashLog, bestShortLen) // 3 -> 7
+ e.dictTable[nextHash] = prevEntry{
+ prev: e.dictTable[nextHash].offset,
+ offset: i,
+ }
+ e.dictTable[nextHash1] = prevEntry{
+ prev: e.dictTable[nextHash1].offset,
+ offset: i + 1,
+ }
+ e.dictTable[nextHash2] = prevEntry{
+ prev: e.dictTable[nextHash2].offset,
+ offset: i + 2,
+ }
+ e.dictTable[nextHash3] = prevEntry{
+ prev: e.dictTable[nextHash3].offset,
+ offset: i + 3,
+ }
+ }
+ }
+
+ // Init or copy dict long table
+ if len(e.dictLongTable) != len(e.longTable) || dictChanged {
+ if len(e.dictLongTable) != len(e.longTable) {
+ e.dictLongTable = make([]prevEntry, len(e.longTable))
+ } else {
+ clear(e.dictLongTable)
+ }
+ if len(d.content) >= 8 {
+ cv := load6432(d.content, 0)
+ h := hashLen(cv, bestLongTableBits, bestLongLen)
+ e.dictLongTable[h] = prevEntry{
+ offset: e.maxMatchOff,
+ prev: e.dictLongTable[h].offset,
+ }
+
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ off := 8 // First to read
+ for i := e.maxMatchOff + 1; i < end; i++ {
+ cv = cv>>8 | (uint64(d.content[off]) << 56)
+ h := hashLen(cv, bestLongTableBits, bestLongLen)
+ e.dictLongTable[h] = prevEntry{
+ offset: i,
+ prev: e.dictLongTable[h].offset,
+ }
+ off++
+ }
+ }
+ }
+ e.lastDict = d
+ // Reset table to initial state
+ copy(e.longTable[:], e.dictLongTable)
+
+ e.cur = e.maxMatchOff
+ // Reset table to initial state
+ copy(e.table[:], e.dictTable)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_better.go b/vendor/github.com/klauspost/compress/zstd/enc_better.go
new file mode 100644
index 00000000000..3305f09248c
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_better.go
@@ -0,0 +1,1238 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import "fmt"
+
+const (
+ betterLongTableBits = 19 // Bits used in the long match table
+ betterLongTableSize = 1 << betterLongTableBits // Size of the table
+ betterLongLen = 8 // Bytes used for table hash
+
+ // Note: Increasing the short table bits or making the hash shorter
+ // can actually lead to compression degradation since it will 'steal' more from the
+ // long match table and match offsets are quite big.
+ // This greatly depends on the type of input.
+ betterShortTableBits = 13 // Bits used in the short match table
+ betterShortTableSize = 1 << betterShortTableBits // Size of the table
+ betterShortLen = 5 // Bytes used for table hash
+
+ betterLongTableShardCnt = 1 << (betterLongTableBits - dictShardBits) // Number of shards in the table
+ betterLongTableShardSize = betterLongTableSize / betterLongTableShardCnt // Size of an individual shard
+
+ betterShortTableShardCnt = 1 << (betterShortTableBits - dictShardBits) // Number of shards in the table
+ betterShortTableShardSize = betterShortTableSize / betterShortTableShardCnt // Size of an individual shard
+)
+
+type prevEntry struct {
+ offset int32
+ prev int32
+}
+
+// betterFastEncoder uses 2 tables, one for short matches (5 bytes) and one for long matches.
+// The long match table contains the previous entry with the same hash,
+// effectively making it a "chain" of length 2.
+// When we find a long match we choose between the two values and select the longest.
+// When we find a short match, after checking the long, we check if we can find a long at n+1
+// and that it is longer (lazy matching).
+type betterFastEncoder struct {
+ fastBase
+ table [betterShortTableSize]tableEntry
+ longTable [betterLongTableSize]prevEntry
+}
+
+type betterFastEncoderDict struct {
+ betterFastEncoder
+ dictTable []tableEntry
+ dictLongTable []prevEntry
+ shortTableShardDirty [betterShortTableShardCnt]bool
+ longTableShardDirty [betterLongTableShardCnt]bool
+ allDirty bool
+}
+
+// Encode improves compression...
+func (e *betterFastEncoder) Encode(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 2
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ e.table = [betterShortTableSize]tableEntry{}
+ e.longTable = [betterLongTableSize]prevEntry{}
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.table[i].offset = v
+ }
+ for i := range e.longTable[:] {
+ v := e.longTable[i].offset
+ v2 := e.longTable[i].prev
+ if v < minOff {
+ v = 0
+ v2 = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ if v2 < minOff {
+ v2 = 0
+ } else {
+ v2 = v2 - e.cur + e.maxMatchOff
+ }
+ }
+ e.longTable[i] = prevEntry{
+ offset: v,
+ prev: v2,
+ }
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Add block to history
+ s := e.addBlock(src)
+ blk.size = len(src)
+
+ // Check RLE first
+ if len(src) > zstdMinMatch {
+ ml := matchLen(src[1:], src)
+ if ml == len(src)-1 {
+ blk.literals = append(blk.literals, src[0])
+ blk.sequences = append(blk.sequences, seq{litLen: 1, matchLen: uint32(len(src)-1) - zstdMinMatch, offset: 1 + 3})
+ return
+ }
+ }
+
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 1.
+ const stepSize = 1
+
+ const kSearchStrength = 9
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ var t int32
+ // We allow the encoder to optionally turn off repeat offsets across blocks
+ canRepeat := len(blk.sequences) > 2
+ var matched, index0 int32
+
+ for {
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ nextHashL := hashLen(cv, betterLongTableBits, betterLongLen)
+ nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ const repOff = 1
+ repIndex := s - offset1 + repOff
+ off := s + e.cur
+ e.longTable[nextHashL] = prevEntry{offset: off, prev: candidateL.offset}
+ e.table[nextHashS] = tableEntry{offset: off, val: uint32(cv)}
+ index0 = s + 1
+
+ if canRepeat {
+ if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Index match start+1 (long) -> s - 1
+ index0 := s + repOff
+ s += length + repOff
+
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ // Index skipped...
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ cv1 := cv0 >> 8
+ h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
+ off := index0 + e.cur
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.table[hashLen(cv1, betterShortTableBits, betterShortLen)] = tableEntry{offset: off + 1, val: uint32(cv1)}
+ index0 += 2
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ const repOff2 = 1
+
+ // We deviate from the reference encoder and also check offset 2.
+ // Still slower and not much better, so disabled.
+ // repIndex = s - offset2 + repOff2
+ if false && repIndex >= 0 && load6432(src, repIndex) == load6432(src, s+repOff) {
+ // Consider history as well.
+ var seq seq
+ length := 8 + e.matchlen(s+8+repOff2, repIndex+8, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff2
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 2
+ seq.offset = 2
+ if debugSequences {
+ println("repeat sequence 2", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ s += length + repOff2
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+
+ // Index skipped...
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ cv1 := cv0 >> 8
+ h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
+ off := index0 + e.cur
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.table[hashLen(cv1, betterShortTableBits, betterShortLen)] = tableEntry{offset: off + 1, val: uint32(cv1)}
+ index0 += 2
+ }
+ cv = load6432(src, s)
+ // Swap offsets
+ offset1, offset2 = offset2, offset1
+ continue
+ }
+ }
+ // Find the offsets of our two matches.
+ coffsetL := candidateL.offset - e.cur
+ coffsetLP := candidateL.prev - e.cur
+
+ // Check if we have a long match.
+ if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) {
+ // Found a long match, at least 8 bytes.
+ matched = e.matchlen(s+8, coffsetL+8, src) + 8
+ t = coffsetL
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+
+ if s-coffsetLP < e.maxMatchOff && cv == load6432(src, coffsetLP) {
+ // Found a long match, at least 8 bytes.
+ prevMatch := e.matchlen(s+8, coffsetLP+8, src) + 8
+ if prevMatch > matched {
+ matched = prevMatch
+ t = coffsetLP
+ }
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ }
+ break
+ }
+
+ // Check if we have a long match on prev.
+ if s-coffsetLP < e.maxMatchOff && cv == load6432(src, coffsetLP) {
+ // Found a long match, at least 8 bytes.
+ matched = e.matchlen(s+8, coffsetLP+8, src) + 8
+ t = coffsetLP
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ break
+ }
+
+ coffsetS := candidateS.offset - e.cur
+
+ // Check if we have a short match.
+ if s-coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
+ // found a regular match
+ matched = e.matchlen(s+4, coffsetS+4, src) + 4
+
+ // See if we can find a long match at s+1
+ const checkAt = 1
+ cv := load6432(src, s+checkAt)
+ nextHashL = hashLen(cv, betterLongTableBits, betterLongLen)
+ candidateL = e.longTable[nextHashL]
+ coffsetL = candidateL.offset - e.cur
+
+ // We can store it, since we have at least a 4 byte match.
+ e.longTable[nextHashL] = prevEntry{offset: s + checkAt + e.cur, prev: candidateL.offset}
+ if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) {
+ // Found a long match, at least 8 bytes.
+ matchedNext := e.matchlen(s+8+checkAt, coffsetL+8, src) + 8
+ if matchedNext > matched {
+ t = coffsetL
+ s += checkAt
+ matched = matchedNext
+ if debugMatches {
+ println("long match (after short)")
+ }
+ break
+ }
+ }
+
+ // Check prev long...
+ coffsetL = candidateL.prev - e.cur
+ if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) {
+ // Found a long match, at least 8 bytes.
+ matchedNext := e.matchlen(s+8+checkAt, coffsetL+8, src) + 8
+ if matchedNext > matched {
+ t = coffsetL
+ s += checkAt
+ matched = matchedNext
+ if debugMatches {
+ println("prev long match (after short)")
+ }
+ break
+ }
+ }
+ t = coffsetS
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ if debugMatches {
+ println("short match")
+ }
+ break
+ }
+
+ // No match found, move forward in input.
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+
+ // Try to find a better match by searching for a long match at the end of the current best match
+ if s+matched < sLimit {
+ // Allow some bytes at the beginning to mismatch.
+ // Sweet spot is around 3 bytes, but depends on input.
+ // The skipped bytes are tested in Extend backwards,
+ // and still picked up as part of the match if they do.
+ const skipBeginning = 3
+
+ nextHashL := hashLen(load6432(src, s+matched), betterLongTableBits, betterLongLen)
+ s2 := s + skipBeginning
+ cv := load3232(src, s2)
+ candidateL := e.longTable[nextHashL]
+ coffsetL := candidateL.offset - e.cur - matched + skipBeginning
+ if coffsetL >= 0 && coffsetL < s2 && s2-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) {
+ // Found a long match, at least 4 bytes.
+ matchedNext := e.matchlen(s2+4, coffsetL+4, src) + 4
+ if matchedNext > matched {
+ t = coffsetL
+ s = s2
+ matched = matchedNext
+ if debugMatches {
+ println("long match at end-of-match")
+ }
+ }
+ }
+
+ // Check prev long...
+ if true {
+ coffsetL = candidateL.prev - e.cur - matched + skipBeginning
+ if coffsetL >= 0 && coffsetL < s2 && s2-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) {
+ // Found a long match, at least 4 bytes.
+ matchedNext := e.matchlen(s2+4, coffsetL+4, src) + 4
+ if matchedNext > matched {
+ t = coffsetL
+ s = s2
+ matched = matchedNext
+ if debugMatches {
+ println("prev long match at end-of-match")
+ }
+ }
+ }
+ }
+ }
+ // A match has been found. Update recent offsets.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the n-byte match as long as possible.
+ l := matched
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+
+ // Index match start+1 (long) -> s - 1
+ off := index0 + e.cur
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ cv1 := cv0 >> 8
+ h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.table[hashLen(cv1, betterShortTableBits, betterShortLen)] = tableEntry{offset: off + 1, val: uint32(cv1)}
+ index0 += 2
+ off += 2
+ }
+
+ cv = load6432(src, s)
+ if !canRepeat {
+ continue
+ }
+
+ // Check offset 2
+ for {
+ o2 := s - offset2
+ if load3232(src, o2) != uint32(cv) {
+ // Do regular search
+ break
+ }
+
+ // Store this, since we have it.
+ nextHashL := hashLen(cv, betterLongTableBits, betterLongLen)
+ nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
+
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: e.longTable[nextHashL].offset}
+ e.table[nextHashS] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ // Finished
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// EncodeNoHist will encode a block with no history and no following blocks.
+// Most notable difference is that src will not be copied for history and
+// we do not need to check for max match length.
+func (e *betterFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
+ e.ensureHist(len(src))
+ e.Encode(blk, src)
+}
+
+// Encode improves compression...
+func (e *betterFastEncoderDict) Encode(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 2
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ for i := range e.longTable[:] {
+ e.longTable[i] = prevEntry{}
+ }
+ e.cur = e.maxMatchOff
+ e.allDirty = true
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.table[i].offset = v
+ }
+ for i := range e.longTable[:] {
+ v := e.longTable[i].offset
+ v2 := e.longTable[i].prev
+ if v < minOff {
+ v = 0
+ v2 = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ if v2 < minOff {
+ v2 = 0
+ } else {
+ v2 = v2 - e.cur + e.maxMatchOff
+ }
+ }
+ e.longTable[i] = prevEntry{
+ offset: v,
+ prev: v2,
+ }
+ }
+ e.allDirty = true
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ s := e.addBlock(src)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 1.
+ const stepSize = 1
+
+ const kSearchStrength = 9
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ var t int32
+ // We allow the encoder to optionally turn off repeat offsets across blocks
+ canRepeat := len(blk.sequences) > 2
+ var matched, index0 int32
+
+ for {
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ nextHashL := hashLen(cv, betterLongTableBits, betterLongLen)
+ nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ const repOff = 1
+ repIndex := s - offset1 + repOff
+ off := s + e.cur
+ e.longTable[nextHashL] = prevEntry{offset: off, prev: candidateL.offset}
+ e.markLongShardDirty(nextHashL)
+ e.table[nextHashS] = tableEntry{offset: off, val: uint32(cv)}
+ e.markShortShardDirty(nextHashS)
+ index0 = s + 1
+
+ if canRepeat {
+ if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Index match start+1 (long) -> s - 1
+ s += length + repOff
+
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ // Index skipped...
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ cv1 := cv0 >> 8
+ h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
+ off := index0 + e.cur
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.markLongShardDirty(h0)
+ h1 := hashLen(cv1, betterShortTableBits, betterShortLen)
+ e.table[h1] = tableEntry{offset: off + 1, val: uint32(cv1)}
+ e.markShortShardDirty(h1)
+ index0 += 2
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ const repOff2 = 1
+
+ // We deviate from the reference encoder and also check offset 2.
+ // Still slower and not much better, so disabled.
+ // repIndex = s - offset2 + repOff2
+ if false && repIndex >= 0 && load6432(src, repIndex) == load6432(src, s+repOff) {
+ // Consider history as well.
+ var seq seq
+ length := 8 + e.matchlen(s+8+repOff2, repIndex+8, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff2
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 2
+ seq.offset = 2
+ if debugSequences {
+ println("repeat sequence 2", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ s += length + repOff2
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+
+ // Index skipped...
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ cv1 := cv0 >> 8
+ h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
+ off := index0 + e.cur
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.markLongShardDirty(h0)
+ h1 := hashLen(cv1, betterShortTableBits, betterShortLen)
+ e.table[h1] = tableEntry{offset: off + 1, val: uint32(cv1)}
+ e.markShortShardDirty(h1)
+ index0 += 2
+ }
+ cv = load6432(src, s)
+ // Swap offsets
+ offset1, offset2 = offset2, offset1
+ continue
+ }
+ }
+ // Find the offsets of our two matches.
+ coffsetL := candidateL.offset - e.cur
+ coffsetLP := candidateL.prev - e.cur
+
+ // Check if we have a long match.
+ if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) {
+ // Found a long match, at least 8 bytes.
+ matched = e.matchlen(s+8, coffsetL+8, src) + 8
+ t = coffsetL
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+
+ if s-coffsetLP < e.maxMatchOff && cv == load6432(src, coffsetLP) {
+ // Found a long match, at least 8 bytes.
+ prevMatch := e.matchlen(s+8, coffsetLP+8, src) + 8
+ if prevMatch > matched {
+ matched = prevMatch
+ t = coffsetLP
+ }
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ }
+ break
+ }
+
+ // Check if we have a long match on prev.
+ if s-coffsetLP < e.maxMatchOff && cv == load6432(src, coffsetLP) {
+ // Found a long match, at least 8 bytes.
+ matched = e.matchlen(s+8, coffsetLP+8, src) + 8
+ t = coffsetLP
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ break
+ }
+
+ coffsetS := candidateS.offset - e.cur
+
+ // Check if we have a short match.
+ if s-coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
+ // found a regular match
+ matched = e.matchlen(s+4, coffsetS+4, src) + 4
+
+ // See if we can find a long match at s+1
+ const checkAt = 1
+ cv := load6432(src, s+checkAt)
+ nextHashL = hashLen(cv, betterLongTableBits, betterLongLen)
+ candidateL = e.longTable[nextHashL]
+ coffsetL = candidateL.offset - e.cur
+
+ // We can store it, since we have at least a 4 byte match.
+ e.longTable[nextHashL] = prevEntry{offset: s + checkAt + e.cur, prev: candidateL.offset}
+ e.markLongShardDirty(nextHashL)
+ if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) {
+ // Found a long match, at least 8 bytes.
+ matchedNext := e.matchlen(s+8+checkAt, coffsetL+8, src) + 8
+ if matchedNext > matched {
+ t = coffsetL
+ s += checkAt
+ matched = matchedNext
+ if debugMatches {
+ println("long match (after short)")
+ }
+ break
+ }
+ }
+
+ // Check prev long...
+ coffsetL = candidateL.prev - e.cur
+ if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) {
+ // Found a long match, at least 8 bytes.
+ matchedNext := e.matchlen(s+8+checkAt, coffsetL+8, src) + 8
+ if matchedNext > matched {
+ t = coffsetL
+ s += checkAt
+ matched = matchedNext
+ if debugMatches {
+ println("prev long match (after short)")
+ }
+ break
+ }
+ }
+ t = coffsetS
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ if debugMatches {
+ println("short match")
+ }
+ break
+ }
+
+ // No match found, move forward in input.
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ // Try to find a better match by searching for a long match at the end of the current best match
+ if s+matched < sLimit {
+ nextHashL := hashLen(load6432(src, s+matched), betterLongTableBits, betterLongLen)
+ cv := load3232(src, s)
+ candidateL := e.longTable[nextHashL]
+ coffsetL := candidateL.offset - e.cur - matched
+ if coffsetL >= 0 && coffsetL < s && s-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) {
+ // Found a long match, at least 4 bytes.
+ matchedNext := e.matchlen(s+4, coffsetL+4, src) + 4
+ if matchedNext > matched {
+ t = coffsetL
+ matched = matchedNext
+ if debugMatches {
+ println("long match at end-of-match")
+ }
+ }
+ }
+
+ // Check prev long...
+ if true {
+ coffsetL = candidateL.prev - e.cur - matched
+ if coffsetL >= 0 && coffsetL < s && s-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) {
+ // Found a long match, at least 4 bytes.
+ matchedNext := e.matchlen(s+4, coffsetL+4, src) + 4
+ if matchedNext > matched {
+ t = coffsetL
+ matched = matchedNext
+ if debugMatches {
+ println("prev long match at end-of-match")
+ }
+ }
+ }
+ }
+ }
+ // A match has been found. Update recent offsets.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the n-byte match as long as possible.
+ l := matched
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+
+ // Index match start+1 (long) -> s - 1
+ off := index0 + e.cur
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ cv1 := cv0 >> 8
+ h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.markLongShardDirty(h0)
+ h1 := hashLen(cv1, betterShortTableBits, betterShortLen)
+ e.table[h1] = tableEntry{offset: off + 1, val: uint32(cv1)}
+ e.markShortShardDirty(h1)
+ index0 += 2
+ off += 2
+ }
+
+ cv = load6432(src, s)
+ if !canRepeat {
+ continue
+ }
+
+ // Check offset 2
+ for {
+ o2 := s - offset2
+ if load3232(src, o2) != uint32(cv) {
+ // Do regular search
+ break
+ }
+
+ // Store this, since we have it.
+ nextHashL := hashLen(cv, betterLongTableBits, betterLongLen)
+ nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
+
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: e.longTable[nextHashL].offset}
+ e.markLongShardDirty(nextHashL)
+ e.table[nextHashS] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.markShortShardDirty(nextHashS)
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ // Finished
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *betterFastEncoder) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d != nil {
+ panic("betterFastEncoder: Reset with dict")
+ }
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *betterFastEncoderDict) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d == nil {
+ return
+ }
+ dictChanged := d != e.lastDict
+ // Init or copy dict table
+ if len(e.dictTable) != len(e.table) || dictChanged {
+ if len(e.dictTable) != len(e.table) {
+ e.dictTable = make([]tableEntry, len(e.table))
+ } else {
+ clear(e.dictTable)
+ }
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ for i := e.maxMatchOff; i < end; i += 4 {
+ const hashLog = betterShortTableBits
+
+ cv := load6432(d.content, i-e.maxMatchOff)
+ nextHash := hashLen(cv, hashLog, betterShortLen) // 0 -> 4
+ nextHash1 := hashLen(cv>>8, hashLog, betterShortLen) // 1 -> 5
+ nextHash2 := hashLen(cv>>16, hashLog, betterShortLen) // 2 -> 6
+ nextHash3 := hashLen(cv>>24, hashLog, betterShortLen) // 3 -> 7
+ e.dictTable[nextHash] = tableEntry{
+ val: uint32(cv),
+ offset: i,
+ }
+ e.dictTable[nextHash1] = tableEntry{
+ val: uint32(cv >> 8),
+ offset: i + 1,
+ }
+ e.dictTable[nextHash2] = tableEntry{
+ val: uint32(cv >> 16),
+ offset: i + 2,
+ }
+ e.dictTable[nextHash3] = tableEntry{
+ val: uint32(cv >> 24),
+ offset: i + 3,
+ }
+ }
+ e.allDirty = true
+ }
+
+ // Init or copy dict long table
+ if len(e.dictLongTable) != len(e.longTable) || dictChanged {
+ if len(e.dictLongTable) != len(e.longTable) {
+ e.dictLongTable = make([]prevEntry, len(e.longTable))
+ } else {
+ clear(e.dictLongTable)
+ }
+ if len(d.content) >= 8 {
+ cv := load6432(d.content, 0)
+ h := hashLen(cv, betterLongTableBits, betterLongLen)
+ e.dictLongTable[h] = prevEntry{
+ offset: e.maxMatchOff,
+ prev: e.dictLongTable[h].offset,
+ }
+
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ off := 8 // First to read
+ for i := e.maxMatchOff + 1; i < end; i++ {
+ cv = cv>>8 | (uint64(d.content[off]) << 56)
+ h := hashLen(cv, betterLongTableBits, betterLongLen)
+ e.dictLongTable[h] = prevEntry{
+ offset: i,
+ prev: e.dictLongTable[h].offset,
+ }
+ off++
+ }
+ }
+ e.allDirty = true
+ }
+ e.lastDict = d
+
+ // Reset table to initial state
+ {
+ dirtyShardCnt := 0
+ if !e.allDirty {
+ for i := range e.shortTableShardDirty {
+ if e.shortTableShardDirty[i] {
+ dirtyShardCnt++
+ }
+ }
+ }
+ const shardCnt = betterShortTableShardCnt
+ const shardSize = betterShortTableShardSize
+ if e.allDirty || dirtyShardCnt > shardCnt*4/6 {
+ copy(e.table[:], e.dictTable)
+ for i := range e.shortTableShardDirty {
+ e.shortTableShardDirty[i] = false
+ }
+ } else {
+ for i := range e.shortTableShardDirty {
+ if !e.shortTableShardDirty[i] {
+ continue
+ }
+
+ copy(e.table[i*shardSize:(i+1)*shardSize], e.dictTable[i*shardSize:(i+1)*shardSize])
+ e.shortTableShardDirty[i] = false
+ }
+ }
+ }
+ {
+ dirtyShardCnt := 0
+ if !e.allDirty {
+ for i := range e.shortTableShardDirty {
+ if e.shortTableShardDirty[i] {
+ dirtyShardCnt++
+ }
+ }
+ }
+ const shardCnt = betterLongTableShardCnt
+ const shardSize = betterLongTableShardSize
+ if e.allDirty || dirtyShardCnt > shardCnt*4/6 {
+ copy(e.longTable[:], e.dictLongTable)
+ for i := range e.longTableShardDirty {
+ e.longTableShardDirty[i] = false
+ }
+ } else {
+ for i := range e.longTableShardDirty {
+ if !e.longTableShardDirty[i] {
+ continue
+ }
+
+ copy(e.longTable[i*shardSize:(i+1)*shardSize], e.dictLongTable[i*shardSize:(i+1)*shardSize])
+ e.longTableShardDirty[i] = false
+ }
+ }
+ }
+ e.cur = e.maxMatchOff
+ e.allDirty = false
+}
+
+func (e *betterFastEncoderDict) markLongShardDirty(entryNum uint32) {
+ e.longTableShardDirty[entryNum/betterLongTableShardSize] = true
+}
+
+func (e *betterFastEncoderDict) markShortShardDirty(entryNum uint32) {
+ e.shortTableShardDirty[entryNum/betterShortTableShardSize] = true
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
new file mode 100644
index 00000000000..2fb6da112bc
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
@@ -0,0 +1,1107 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import "fmt"
+
+const (
+ dFastLongTableBits = 17 // Bits used in the long match table
+ dFastLongTableSize = 1 << dFastLongTableBits // Size of the table
+ dFastLongTableMask = dFastLongTableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks.
+ dFastLongLen = 8 // Bytes used for table hash
+
+ dLongTableShardCnt = 1 << (dFastLongTableBits - dictShardBits) // Number of shards in the table
+ dLongTableShardSize = dFastLongTableSize / dLongTableShardCnt // Size of an individual shard
+
+ dFastShortTableBits = tableBits // Bits used in the short match table
+ dFastShortTableSize = 1 << dFastShortTableBits // Size of the table
+ dFastShortTableMask = dFastShortTableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks.
+ dFastShortLen = 5 // Bytes used for table hash
+
+)
+
+type doubleFastEncoder struct {
+ fastEncoder
+ longTable [dFastLongTableSize]tableEntry
+}
+
+type doubleFastEncoderDict struct {
+ fastEncoderDict
+ longTable [dFastLongTableSize]tableEntry
+ dictLongTable []tableEntry
+ longTableShardDirty [dLongTableShardCnt]bool
+}
+
+// Encode mimmics functionality in zstd_dfast.c
+func (e *doubleFastEncoder) Encode(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 2
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ e.table = [dFastShortTableSize]tableEntry{}
+ e.longTable = [dFastLongTableSize]tableEntry{}
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.table[i].offset = v
+ }
+ for i := range e.longTable[:] {
+ v := e.longTable[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.longTable[i].offset = v
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ s := e.addBlock(src)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 1.
+ const stepSize = 1
+
+ const kSearchStrength = 8
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ var t int32
+ // We allow the encoder to optionally turn off repeat offsets across blocks
+ canRepeat := len(blk.sequences) > 2
+
+ for {
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
+ nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ const repOff = 1
+ repIndex := s - offset1 + repOff
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.table[nextHashS] = entry
+
+ if canRepeat {
+ if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + repOff
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ }
+ // Find the offsets of our two matches.
+ coffsetL := s - (candidateL.offset - e.cur)
+ coffsetS := s - (candidateS.offset - e.cur)
+
+ // Check if we have a long match.
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ break
+ }
+
+ // Check if we have a short match.
+ if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
+ // found a regular match
+ // See if we can find a long match at s+1
+ const checkAt = 1
+ cv := load6432(src, s+checkAt)
+ nextHashL = hashLen(cv, dFastLongTableBits, dFastLongLen)
+ candidateL = e.longTable[nextHashL]
+ coffsetL = s - (candidateL.offset - e.cur) + checkAt
+
+ // We can store it, since we have at least a 4 byte match.
+ e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)}
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ s += checkAt
+ if debugMatches {
+ println("long match (after short)")
+ }
+ break
+ }
+
+ t = candidateS.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ if debugMatches {
+ println("short match")
+ }
+ break
+ }
+
+ // No match found, move forward in input.
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+
+ // A 4-byte match has been found. Update recent offsets.
+ // We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the 4-byte match as long as possible.
+ l := e.matchlen(s+4, t+4, src) + 4
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+
+ // Index match start+1 (long) and start+2 (short)
+ index0 := s - l + 1
+ // Index match end-2 (long) and end-1 (short)
+ index1 := s - 2
+
+ cv0 := load6432(src, index0)
+ cv1 := load6432(src, index1)
+ te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)}
+ te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)}
+ e.longTable[hashLen(cv0, dFastLongTableBits, dFastLongLen)] = te0
+ e.longTable[hashLen(cv1, dFastLongTableBits, dFastLongLen)] = te1
+ cv0 >>= 8
+ cv1 >>= 8
+ te0.offset++
+ te1.offset++
+ te0.val = uint32(cv0)
+ te1.val = uint32(cv1)
+ e.table[hashLen(cv0, dFastShortTableBits, dFastShortLen)] = te0
+ e.table[hashLen(cv1, dFastShortTableBits, dFastShortLen)] = te1
+
+ cv = load6432(src, s)
+
+ if !canRepeat {
+ continue
+ }
+
+ // Check offset 2
+ for {
+ o2 := s - offset2
+ if load3232(src, o2) != uint32(cv) {
+ // Do regular search
+ break
+ }
+
+ // Store this, since we have it.
+ nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
+ nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
+
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.table[nextHashS] = entry
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ // Finished
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// EncodeNoHist will encode a block with no history and no following blocks.
+// Most notable difference is that src will not be copied for history and
+// we do not need to check for max match length.
+func (e *doubleFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 2
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ if e.cur >= e.bufferReset {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ for i := range e.longTable[:] {
+ e.longTable[i] = tableEntry{}
+ }
+ e.cur = e.maxMatchOff
+ }
+
+ s := int32(0)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 1.
+ const stepSize = 1
+
+ const kSearchStrength = 8
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ var t int32
+ for {
+
+ nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
+ nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ const repOff = 1
+ repIndex := s - offset1 + repOff
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.table[nextHashS] = entry
+
+ if len(blk.sequences) > 2 {
+ if load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
+ // Consider history as well.
+ var seq seq
+ //length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
+ length := 4 + int32(matchLen(src[s+4+repOff:], src[repIndex+4:]))
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + repOff
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ }
+ // Find the offsets of our two matches.
+ coffsetL := s - (candidateL.offset - e.cur)
+ coffsetS := s - (candidateS.offset - e.cur)
+
+ // Check if we have a long match.
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d). cur: %d", s, t, e.cur))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ break
+ }
+
+ // Check if we have a short match.
+ if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
+ // found a regular match
+ // See if we can find a long match at s+1
+ const checkAt = 1
+ cv := load6432(src, s+checkAt)
+ nextHashL = hashLen(cv, dFastLongTableBits, dFastLongLen)
+ candidateL = e.longTable[nextHashL]
+ coffsetL = s - (candidateL.offset - e.cur) + checkAt
+
+ // We can store it, since we have at least a 4 byte match.
+ e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)}
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ s += checkAt
+ if debugMatches {
+ println("long match (after short)")
+ }
+ break
+ }
+
+ t = candidateS.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ if debugMatches {
+ println("short match")
+ }
+ break
+ }
+
+ // No match found, move forward in input.
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+
+ // A 4-byte match has been found. Update recent offsets.
+ // We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ // Extend the 4-byte match as long as possible.
+ //l := e.matchlen(s+4, t+4, src) + 4
+ l := int32(matchLen(src[s+4:], src[t+4:])) + 4
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+
+ // Index match start+1 (long) and start+2 (short)
+ index0 := s - l + 1
+ // Index match end-2 (long) and end-1 (short)
+ index1 := s - 2
+
+ cv0 := load6432(src, index0)
+ cv1 := load6432(src, index1)
+ te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)}
+ te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)}
+ e.longTable[hashLen(cv0, dFastLongTableBits, dFastLongLen)] = te0
+ e.longTable[hashLen(cv1, dFastLongTableBits, dFastLongLen)] = te1
+ cv0 >>= 8
+ cv1 >>= 8
+ te0.offset++
+ te1.offset++
+ te0.val = uint32(cv0)
+ te1.val = uint32(cv1)
+ e.table[hashLen(cv0, dFastShortTableBits, dFastShortLen)] = te0
+ e.table[hashLen(cv1, dFastShortTableBits, dFastShortLen)] = te1
+
+ cv = load6432(src, s)
+
+ if len(blk.sequences) <= 2 {
+ continue
+ }
+
+ // Check offset 2
+ for {
+ o2 := s - offset2
+ if load3232(src, o2) != uint32(cv) {
+ // Do regular search
+ break
+ }
+
+ // Store this, since we have it.
+ nextHashS := hashLen(cv1>>8, dFastShortTableBits, dFastShortLen)
+ nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
+
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ //l := 4 + e.matchlen(s+4, o2+4, src)
+ l := 4 + int32(matchLen(src[s+4:], src[o2+4:]))
+
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.table[nextHashS] = entry
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ // Finished
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+
+ // We do not store history, so we must offset e.cur to avoid false matches for next user.
+ if e.cur < e.bufferReset {
+ e.cur += int32(len(src))
+ }
+}
+
+// Encode will encode the content, with a dictionary if initialized for it.
+func (e *doubleFastEncoderDict) Encode(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 2
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ for i := range e.longTable[:] {
+ e.longTable[i] = tableEntry{}
+ }
+ e.markAllShardsDirty()
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.table[i].offset = v
+ }
+ for i := range e.longTable[:] {
+ v := e.longTable[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.longTable[i].offset = v
+ }
+ e.markAllShardsDirty()
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ s := e.addBlock(src)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 1.
+ const stepSize = 1
+
+ const kSearchStrength = 8
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ var t int32
+ // We allow the encoder to optionally turn off repeat offsets across blocks
+ canRepeat := len(blk.sequences) > 2
+
+ for {
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
+ nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ const repOff = 1
+ repIndex := s - offset1 + repOff
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.markLongShardDirty(nextHashL)
+ e.table[nextHashS] = entry
+ e.markShardDirty(nextHashS)
+
+ if canRepeat {
+ if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + repOff
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ }
+ // Find the offsets of our two matches.
+ coffsetL := s - (candidateL.offset - e.cur)
+ coffsetS := s - (candidateS.offset - e.cur)
+
+ // Check if we have a long match.
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ break
+ }
+
+ // Check if we have a short match.
+ if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
+ // found a regular match
+ // See if we can find a long match at s+1
+ const checkAt = 1
+ cv := load6432(src, s+checkAt)
+ nextHashL = hashLen(cv, dFastLongTableBits, dFastLongLen)
+ candidateL = e.longTable[nextHashL]
+ coffsetL = s - (candidateL.offset - e.cur) + checkAt
+
+ // We can store it, since we have at least a 4 byte match.
+ e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)}
+ e.markLongShardDirty(nextHashL)
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ s += checkAt
+ if debugMatches {
+ println("long match (after short)")
+ }
+ break
+ }
+
+ t = candidateS.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ if debugMatches {
+ println("short match")
+ }
+ break
+ }
+
+ // No match found, move forward in input.
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+
+ // A 4-byte match has been found. Update recent offsets.
+ // We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the 4-byte match as long as possible.
+ l := e.matchlen(s+4, t+4, src) + 4
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+
+ // Index match start+1 (long) and start+2 (short)
+ index0 := s - l + 1
+ // Index match end-2 (long) and end-1 (short)
+ index1 := s - 2
+
+ cv0 := load6432(src, index0)
+ cv1 := load6432(src, index1)
+ te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)}
+ te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)}
+ longHash1 := hashLen(cv0, dFastLongTableBits, dFastLongLen)
+ longHash2 := hashLen(cv1, dFastLongTableBits, dFastLongLen)
+ e.longTable[longHash1] = te0
+ e.longTable[longHash2] = te1
+ e.markLongShardDirty(longHash1)
+ e.markLongShardDirty(longHash2)
+ cv0 >>= 8
+ cv1 >>= 8
+ te0.offset++
+ te1.offset++
+ te0.val = uint32(cv0)
+ te1.val = uint32(cv1)
+ hashVal1 := hashLen(cv0, dFastShortTableBits, dFastShortLen)
+ hashVal2 := hashLen(cv1, dFastShortTableBits, dFastShortLen)
+ e.table[hashVal1] = te0
+ e.markShardDirty(hashVal1)
+ e.table[hashVal2] = te1
+ e.markShardDirty(hashVal2)
+
+ cv = load6432(src, s)
+
+ if !canRepeat {
+ continue
+ }
+
+ // Check offset 2
+ for {
+ o2 := s - offset2
+ if load3232(src, o2) != uint32(cv) {
+ // Do regular search
+ break
+ }
+
+ // Store this, since we have it.
+ nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
+ nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
+
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.markLongShardDirty(nextHashL)
+ e.table[nextHashS] = entry
+ e.markShardDirty(nextHashS)
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ // Finished
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+ // If we encoded more than 64K mark all dirty.
+ if len(src) > 64<<10 {
+ e.markAllShardsDirty()
+ }
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *doubleFastEncoder) Reset(d *dict, singleBlock bool) {
+ e.fastEncoder.Reset(d, singleBlock)
+ if d != nil {
+ panic("doubleFastEncoder: Reset with dict not supported")
+ }
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *doubleFastEncoderDict) Reset(d *dict, singleBlock bool) {
+ allDirty := e.allDirty
+ dictChanged := d != e.lastDict
+ e.fastEncoderDict.Reset(d, singleBlock)
+ if d == nil {
+ return
+ }
+
+ // Init or copy dict table
+ if len(e.dictLongTable) != len(e.longTable) || dictChanged {
+ if len(e.dictLongTable) != len(e.longTable) {
+ e.dictLongTable = make([]tableEntry, len(e.longTable))
+ } else {
+ clear(e.dictLongTable)
+ }
+ if len(d.content) >= 8 {
+ cv := load6432(d.content, 0)
+ e.dictLongTable[hashLen(cv, dFastLongTableBits, dFastLongLen)] = tableEntry{
+ val: uint32(cv),
+ offset: e.maxMatchOff,
+ }
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ for i := e.maxMatchOff + 1; i < end; i++ {
+ cv = cv>>8 | (uint64(d.content[i-e.maxMatchOff+7]) << 56)
+ e.dictLongTable[hashLen(cv, dFastLongTableBits, dFastLongLen)] = tableEntry{
+ val: uint32(cv),
+ offset: i,
+ }
+ }
+ }
+ allDirty = true
+ }
+ // Reset table to initial state
+ e.cur = e.maxMatchOff
+
+ dirtyShardCnt := 0
+ if !allDirty {
+ for i := range e.longTableShardDirty {
+ if e.longTableShardDirty[i] {
+ dirtyShardCnt++
+ }
+ }
+ }
+
+ if allDirty || dirtyShardCnt > dLongTableShardCnt/2 {
+ //copy(e.longTable[:], e.dictLongTable)
+ e.longTable = *(*[dFastLongTableSize]tableEntry)(e.dictLongTable)
+ for i := range e.longTableShardDirty {
+ e.longTableShardDirty[i] = false
+ }
+ return
+ }
+ for i := range e.longTableShardDirty {
+ if !e.longTableShardDirty[i] {
+ continue
+ }
+
+ // copy(e.longTable[i*dLongTableShardSize:(i+1)*dLongTableShardSize], e.dictLongTable[i*dLongTableShardSize:(i+1)*dLongTableShardSize])
+ *(*[dLongTableShardSize]tableEntry)(e.longTable[i*dLongTableShardSize:]) = *(*[dLongTableShardSize]tableEntry)(e.dictLongTable[i*dLongTableShardSize:])
+
+ e.longTableShardDirty[i] = false
+ }
+}
+
+func (e *doubleFastEncoderDict) markLongShardDirty(entryNum uint32) {
+ e.longTableShardDirty[entryNum/dLongTableShardSize] = true
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_fast.go b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
new file mode 100644
index 00000000000..5e104f1a482
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
@@ -0,0 +1,875 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "fmt"
+)
+
+const (
+ tableBits = 15 // Bits used in the table
+ tableSize = 1 << tableBits // Size of the table
+ tableShardCnt = 1 << (tableBits - dictShardBits) // Number of shards in the table
+ tableShardSize = tableSize / tableShardCnt // Size of an individual shard
+ tableFastHashLen = 6
+ tableMask = tableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks.
+ maxMatchLength = 131074
+)
+
+type tableEntry struct {
+ val uint32
+ offset int32
+}
+
+type fastEncoder struct {
+ fastBase
+ table [tableSize]tableEntry
+}
+
+type fastEncoderDict struct {
+ fastEncoder
+ dictTable []tableEntry
+ tableShardDirty [tableShardCnt]bool
+ allDirty bool
+}
+
+// Encode mimmics functionality in zstd_fast.c
+func (e *fastEncoder) Encode(blk *blockEnc, src []byte) {
+ const (
+ inputMargin = 8
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.table[i].offset = v
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ s := e.addBlock(src)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 2.
+ const stepSize = 2
+
+ // TEMPLATE
+ const hashLog = tableBits
+ // seems global, but would be nice to tweak.
+ const kSearchStrength = 6
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ // t will contain the match offset when we find one.
+ // When existing the search loop, we have already checked 4 bytes.
+ var t int32
+
+ // We will not use repeat offsets across blocks.
+ // By not using them for the first 3 matches
+ canRepeat := len(blk.sequences) > 2
+
+ for {
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ nextHash := hashLen(cv, hashLog, tableFastHashLen)
+ nextHash2 := hashLen(cv>>8, hashLog, tableFastHashLen)
+ candidate := e.table[nextHash]
+ candidate2 := e.table[nextHash2]
+ repIndex := s - offset1 + 2
+
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)}
+
+ if canRepeat && repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>16) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+6, repIndex+4, src)
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + 2
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ sMin := max(s-e.maxMatchOff, 0)
+ for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + 2
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ coffset0 := s - (candidate.offset - e.cur)
+ coffset1 := s - (candidate2.offset - e.cur) + 1
+ if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val {
+ // found a regular match
+ t = candidate.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ break
+ }
+
+ if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val {
+ // found a regular match
+ t = candidate2.offset - e.cur
+ s++
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ break
+ }
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ // A 4-byte match has been found. We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the 4-byte match as long as possible.
+ l := e.matchlen(s+4, t+4, src) + 4
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence.
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ // Don't use repeat offsets
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+
+ // Check offset 2
+ if o2 := s - offset2; canRepeat && load3232(src, o2) == uint32(cv) {
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ // Store this, since we have it.
+ nextHash := hashLen(cv, hashLog, tableFastHashLen)
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ break encodeLoop
+ }
+ // Prepare next loop.
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// EncodeNoHist will encode a block with no history and no following blocks.
+// Most notable difference is that src will not be copied for history and
+// we do not need to check for max match length.
+func (e *fastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
+ const (
+ inputMargin = 8
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ )
+ if debugEncoder {
+ if len(src) > maxCompressedBlockSize {
+ panic("src too big")
+ }
+ }
+
+ // Protect against e.cur wraparound.
+ if e.cur >= e.bufferReset {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ e.cur = e.maxMatchOff
+ }
+
+ s := int32(0)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 2.
+ const stepSize = 2
+
+ // TEMPLATE
+ const hashLog = tableBits
+ // seems global, but would be nice to tweak.
+ const kSearchStrength = 6
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ // t will contain the match offset when we find one.
+ // When existing the search loop, we have already checked 4 bytes.
+ var t int32
+
+ // We will not use repeat offsets across blocks.
+ // By not using them for the first 3 matches
+
+ for {
+ nextHash := hashLen(cv, hashLog, tableFastHashLen)
+ nextHash2 := hashLen(cv>>8, hashLog, tableFastHashLen)
+ candidate := e.table[nextHash]
+ candidate2 := e.table[nextHash2]
+ repIndex := s - offset1 + 2
+
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)}
+
+ if len(blk.sequences) > 2 && load3232(src, repIndex) == uint32(cv>>16) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+6, repIndex+4, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + 2
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ sMin := max(s-e.maxMatchOff, 0)
+ for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + 2
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ coffset0 := s - (candidate.offset - e.cur)
+ coffset1 := s - (candidate2.offset - e.cur) + 1
+ if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val {
+ // found a regular match
+ t = candidate.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic(fmt.Sprintf("t (%d) < 0, candidate.offset: %d, e.cur: %d, coffset0: %d, e.maxMatchOff: %d", t, candidate.offset, e.cur, coffset0, e.maxMatchOff))
+ }
+ break
+ }
+
+ if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val {
+ // found a regular match
+ t = candidate2.offset - e.cur
+ s++
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ break
+ }
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ // A 4-byte match has been found. We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && t < 0 {
+ panic(fmt.Sprintf("t (%d) < 0 ", t))
+ }
+ // Extend the 4-byte match as long as possible.
+ l := e.matchlen(s+4, t+4, src) + 4
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence.
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ // Don't use repeat offsets
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+
+ // Check offset 2
+ if o2 := s - offset2; len(blk.sequences) > 2 && load3232(src, o2) == uint32(cv) {
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ // Store this, since we have it.
+ nextHash := hashLen(cv, hashLog, tableFastHashLen)
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ break encodeLoop
+ }
+ // Prepare next loop.
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+ // We do not store history, so we must offset e.cur to avoid false matches for next user.
+ if e.cur < e.bufferReset {
+ e.cur += int32(len(src))
+ }
+}
+
+// Encode will encode the content, with a dictionary if initialized for it.
+func (e *fastEncoderDict) Encode(blk *blockEnc, src []byte) {
+ const (
+ inputMargin = 8
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ )
+ if e.allDirty || len(src) > 32<<10 {
+ e.fastEncoder.Encode(blk, src)
+ e.allDirty = true
+ return
+ }
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ e.table = [tableSize]tableEntry{}
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.table[i].offset = v
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ s := e.addBlock(src)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 2.
+ const stepSize = 2
+
+ // TEMPLATE
+ const hashLog = tableBits
+ // seems global, but would be nice to tweak.
+ const kSearchStrength = 7
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ // t will contain the match offset when we find one.
+ // When existing the search loop, we have already checked 4 bytes.
+ var t int32
+
+ // We will not use repeat offsets across blocks.
+ // By not using them for the first 3 matches
+ canRepeat := len(blk.sequences) > 2
+
+ for {
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ nextHash := hashLen(cv, hashLog, tableFastHashLen)
+ nextHash2 := hashLen(cv>>8, hashLog, tableFastHashLen)
+ candidate := e.table[nextHash]
+ candidate2 := e.table[nextHash2]
+ repIndex := s - offset1 + 2
+
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.markShardDirty(nextHash)
+ e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)}
+ e.markShardDirty(nextHash2)
+
+ if canRepeat && repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>16) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+6, repIndex+4, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + 2
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ sMin := max(s-e.maxMatchOff, 0)
+ for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + 2
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ coffset0 := s - (candidate.offset - e.cur)
+ coffset1 := s - (candidate2.offset - e.cur) + 1
+ if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val {
+ // found a regular match
+ t = candidate.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ break
+ }
+
+ if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val {
+ // found a regular match
+ t = candidate2.offset - e.cur
+ s++
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ break
+ }
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ // A 4-byte match has been found. We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the 4-byte match as long as possible.
+ l := e.matchlen(s+4, t+4, src) + 4
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence.
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ // Don't use repeat offsets
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+
+ // Check offset 2
+ if o2 := s - offset2; canRepeat && load3232(src, o2) == uint32(cv) {
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ // Store this, since we have it.
+ nextHash := hashLen(cv, hashLog, tableFastHashLen)
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.markShardDirty(nextHash)
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ break encodeLoop
+ }
+ // Prepare next loop.
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *fastEncoder) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d != nil {
+ panic("fastEncoder: Reset with dict")
+ }
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *fastEncoderDict) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d == nil {
+ return
+ }
+
+ // Init or copy dict table
+ if len(e.dictTable) != len(e.table) || d != e.lastDict {
+ if len(e.dictTable) != len(e.table) {
+ e.dictTable = make([]tableEntry, len(e.table))
+ } else {
+ clear(e.dictTable)
+ }
+ if true {
+ end := e.maxMatchOff + int32(len(d.content)) - 8
+ for i := e.maxMatchOff; i < end; i += 2 {
+ const hashLog = tableBits
+
+ cv := load6432(d.content, i-e.maxMatchOff)
+ nextHash := hashLen(cv, hashLog, tableFastHashLen) // 0 -> 6
+ nextHash1 := hashLen(cv>>8, hashLog, tableFastHashLen) // 1 -> 7
+ e.dictTable[nextHash] = tableEntry{
+ val: uint32(cv),
+ offset: i,
+ }
+ e.dictTable[nextHash1] = tableEntry{
+ val: uint32(cv >> 8),
+ offset: i + 1,
+ }
+ }
+ }
+ e.lastDict = d
+ e.allDirty = true
+ }
+
+ e.cur = e.maxMatchOff
+ dirtyShardCnt := 0
+ if !e.allDirty {
+ for i := range e.tableShardDirty {
+ if e.tableShardDirty[i] {
+ dirtyShardCnt++
+ }
+ }
+ }
+
+ const shardCnt = tableShardCnt
+ const shardSize = tableShardSize
+ if e.allDirty || dirtyShardCnt > shardCnt*4/6 {
+ //copy(e.table[:], e.dictTable)
+ e.table = *(*[tableSize]tableEntry)(e.dictTable)
+ for i := range e.tableShardDirty {
+ e.tableShardDirty[i] = false
+ }
+ e.allDirty = false
+ return
+ }
+ for i := range e.tableShardDirty {
+ if !e.tableShardDirty[i] {
+ continue
+ }
+
+ //copy(e.table[i*shardSize:(i+1)*shardSize], e.dictTable[i*shardSize:(i+1)*shardSize])
+ *(*[shardSize]tableEntry)(e.table[i*shardSize:]) = *(*[shardSize]tableEntry)(e.dictTable[i*shardSize:])
+ e.tableShardDirty[i] = false
+ }
+ e.allDirty = false
+}
+
+func (e *fastEncoderDict) markAllShardsDirty() {
+ e.allDirty = true
+}
+
+func (e *fastEncoderDict) markShardDirty(entryNum uint32) {
+ e.tableShardDirty[entryNum/tableShardSize] = true
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go
new file mode 100644
index 00000000000..0f2a00a0033
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/encoder.go
@@ -0,0 +1,671 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "crypto/rand"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ rdebug "runtime/debug"
+ "sync"
+
+ "github.com/klauspost/compress/zstd/internal/xxhash"
+)
+
+// Encoder provides encoding to Zstandard.
+// An Encoder can be used for either compressing a stream via the
+// io.WriteCloser interface supported by the Encoder or as multiple independent
+// tasks via the EncodeAll function.
+// Smaller encodes are encouraged to use the EncodeAll function.
+// Use NewWriter to create a new instance.
+type Encoder struct {
+ o encoderOptions
+ encoders chan encoder
+ state encoderState
+ init sync.Once
+}
+
+type encoder interface {
+ Encode(blk *blockEnc, src []byte)
+ EncodeNoHist(blk *blockEnc, src []byte)
+ Block() *blockEnc
+ CRC() *xxhash.Digest
+ AppendCRC([]byte) []byte
+ WindowSize(size int64) int32
+ UseBlock(*blockEnc)
+ Reset(d *dict, singleBlock bool)
+}
+
+type encoderState struct {
+ w io.Writer
+ filling []byte
+ current []byte
+ previous []byte
+ encoder encoder
+ writing *blockEnc
+ err error
+ writeErr error
+ nWritten int64
+ nInput int64
+ frameContentSize int64
+ headerWritten bool
+ eofWritten bool
+ fullFrameWritten bool
+
+ // This waitgroup indicates an encode is running.
+ wg sync.WaitGroup
+ // This waitgroup indicates we have a block encoding/writing.
+ wWg sync.WaitGroup
+}
+
+// NewWriter will create a new Zstandard encoder.
+// If the encoder will be used for encoding blocks a nil writer can be used.
+func NewWriter(w io.Writer, opts ...EOption) (*Encoder, error) {
+ initPredefined()
+ var e Encoder
+ e.o.setDefault()
+ for _, o := range opts {
+ err := o(&e.o)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if w != nil {
+ e.Reset(w)
+ }
+ return &e, nil
+}
+
+func (e *Encoder) initialize() {
+ if e.o.concurrent == 0 {
+ e.o.setDefault()
+ }
+ e.encoders = make(chan encoder, e.o.concurrent)
+ for i := 0; i < e.o.concurrent; i++ {
+ enc := e.o.encoder()
+ e.encoders <- enc
+ }
+}
+
+// Reset will re-initialize the writer and new writes will encode to the supplied writer
+// as a new, independent stream.
+func (e *Encoder) Reset(w io.Writer) {
+ s := &e.state
+ s.wg.Wait()
+ s.wWg.Wait()
+ if cap(s.filling) == 0 {
+ s.filling = make([]byte, 0, e.o.blockSize)
+ }
+ if e.o.concurrent > 1 {
+ if cap(s.current) == 0 {
+ s.current = make([]byte, 0, e.o.blockSize)
+ }
+ if cap(s.previous) == 0 {
+ s.previous = make([]byte, 0, e.o.blockSize)
+ }
+ s.current = s.current[:0]
+ s.previous = s.previous[:0]
+ if s.writing == nil {
+ s.writing = &blockEnc{lowMem: e.o.lowMem}
+ s.writing.init()
+ }
+ s.writing.initNewEncode()
+ }
+ if s.encoder == nil {
+ s.encoder = e.o.encoder()
+ }
+ s.filling = s.filling[:0]
+ s.encoder.Reset(e.o.dict, false)
+ s.headerWritten = false
+ s.eofWritten = false
+ s.fullFrameWritten = false
+ s.w = w
+ s.err = nil
+ s.nWritten = 0
+ s.nInput = 0
+ s.writeErr = nil
+ s.frameContentSize = 0
+}
+
+// ResetWithOptions will re-initialize the writer and apply the given options
+// as a new, independent stream.
+// Options are applied on top of the existing options.
+// Some options cannot be changed on reset and will return an error.
+func (e *Encoder) ResetWithOptions(w io.Writer, opts ...EOption) error {
+ e.o.resetOpt = true
+ defer func() { e.o.resetOpt = false }()
+ hadDict := e.o.dict != nil
+ for _, o := range opts {
+ if err := o(&e.o); err != nil {
+ return err
+ }
+ }
+ hasDict := e.o.dict != nil
+ if hadDict != hasDict {
+ // Dict presence changed — encoder type must be recreated.
+ e.state.encoder = nil
+ e.init = sync.Once{}
+ }
+ e.Reset(w)
+ return nil
+}
+
+// ResetContentSize will reset and set a content size for the next stream.
+// If the bytes written does not match the size given an error will be returned
+// when calling Close().
+// This is removed when Reset is called.
+// Sizes <= 0 results in no content size set.
+func (e *Encoder) ResetContentSize(w io.Writer, size int64) {
+ e.Reset(w)
+ if size >= 0 {
+ e.state.frameContentSize = size
+ }
+}
+
+// Write data to the encoder.
+// Input data will be buffered and as the buffer fills up
+// content will be compressed and written to the output.
+// When done writing, use Close to flush the remaining output
+// and write CRC if requested.
+func (e *Encoder) Write(p []byte) (n int, err error) {
+ s := &e.state
+ if s.eofWritten {
+ return 0, ErrEncoderClosed
+ }
+ for len(p) > 0 {
+ if len(p)+len(s.filling) < e.o.blockSize {
+ if e.o.crc {
+ _, _ = s.encoder.CRC().Write(p)
+ }
+ s.filling = append(s.filling, p...)
+ return n + len(p), nil
+ }
+ add := p
+ if len(p)+len(s.filling) > e.o.blockSize {
+ add = add[:e.o.blockSize-len(s.filling)]
+ }
+ if e.o.crc {
+ _, _ = s.encoder.CRC().Write(add)
+ }
+ s.filling = append(s.filling, add...)
+ p = p[len(add):]
+ n += len(add)
+ if len(s.filling) < e.o.blockSize {
+ return n, nil
+ }
+ err := e.nextBlock(false)
+ if err != nil {
+ return n, err
+ }
+ if debugAsserts && len(s.filling) > 0 {
+ panic(len(s.filling))
+ }
+ }
+ return n, nil
+}
+
+// nextBlock will synchronize and start compressing input in e.state.filling.
+// If an error has occurred during encoding it will be returned.
+func (e *Encoder) nextBlock(final bool) error {
+ s := &e.state
+ // Wait for current block.
+ s.wg.Wait()
+ if s.err != nil {
+ return s.err
+ }
+ if len(s.filling) > e.o.blockSize {
+ return fmt.Errorf("block > maxStoreBlockSize")
+ }
+ if !s.headerWritten {
+ // If we have a single block encode, do a sync compression.
+ if final && len(s.filling) == 0 && !e.o.fullZero {
+ s.headerWritten = true
+ s.fullFrameWritten = true
+ s.eofWritten = true
+ return nil
+ }
+ if final && len(s.filling) > 0 {
+ s.current = e.encodeAll(s.encoder, s.filling, s.current[:0])
+ var n2 int
+ n2, s.err = s.w.Write(s.current)
+ if s.err != nil {
+ return s.err
+ }
+ s.nWritten += int64(n2)
+ s.nInput += int64(len(s.filling))
+ s.current = s.current[:0]
+ s.filling = s.filling[:0]
+ s.headerWritten = true
+ s.fullFrameWritten = true
+ s.eofWritten = true
+ return nil
+ }
+
+ var tmp [maxHeaderSize]byte
+ fh := frameHeader{
+ ContentSize: uint64(s.frameContentSize),
+ WindowSize: uint32(s.encoder.WindowSize(s.frameContentSize)),
+ SingleSegment: false,
+ Checksum: e.o.crc,
+ DictID: e.o.dict.ID(),
+ }
+
+ dst := fh.appendTo(tmp[:0])
+ s.headerWritten = true
+ s.wWg.Wait()
+ var n2 int
+ n2, s.err = s.w.Write(dst)
+ if s.err != nil {
+ return s.err
+ }
+ s.nWritten += int64(n2)
+ }
+ if s.eofWritten {
+ // Ensure we only write it once.
+ final = false
+ }
+
+ if len(s.filling) == 0 {
+ // Final block, but no data.
+ if final {
+ enc := s.encoder
+ blk := enc.Block()
+ blk.reset(nil)
+ blk.last = true
+ blk.encodeRaw(nil)
+ s.wWg.Wait()
+ _, s.err = s.w.Write(blk.output)
+ s.nWritten += int64(len(blk.output))
+ s.eofWritten = true
+ }
+ return s.err
+ }
+
+ // SYNC:
+ if e.o.concurrent == 1 {
+ src := s.filling
+ s.nInput += int64(len(s.filling))
+ if debugEncoder {
+ println("Adding sync block,", len(src), "bytes, final:", final)
+ }
+ enc := s.encoder
+ blk := enc.Block()
+ blk.reset(nil)
+ enc.Encode(blk, src)
+ blk.last = final
+ if final {
+ s.eofWritten = true
+ }
+
+ s.err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
+ if s.err != nil {
+ return s.err
+ }
+ _, s.err = s.w.Write(blk.output)
+ s.nWritten += int64(len(blk.output))
+ s.filling = s.filling[:0]
+ return s.err
+ }
+
+ // Move blocks forward.
+ s.filling, s.current, s.previous = s.previous[:0], s.filling, s.current
+ s.nInput += int64(len(s.current))
+ s.wg.Add(1)
+ if final {
+ s.eofWritten = true
+ }
+ go func(src []byte) {
+ if debugEncoder {
+ println("Adding block,", len(src), "bytes, final:", final)
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ s.err = fmt.Errorf("panic while encoding: %v", r)
+ rdebug.PrintStack()
+ }
+ s.wg.Done()
+ }()
+ enc := s.encoder
+ blk := enc.Block()
+ enc.Encode(blk, src)
+ blk.last = final
+ // Wait for pending writes.
+ s.wWg.Wait()
+ if s.writeErr != nil {
+ s.err = s.writeErr
+ return
+ }
+ // Transfer encoders from previous write block.
+ blk.swapEncoders(s.writing)
+ // Transfer recent offsets to next.
+ enc.UseBlock(s.writing)
+ s.writing = blk
+ s.wWg.Add(1)
+ go func() {
+ defer func() {
+ if r := recover(); r != nil {
+ s.writeErr = fmt.Errorf("panic while encoding/writing: %v", r)
+ rdebug.PrintStack()
+ }
+ s.wWg.Done()
+ }()
+ s.writeErr = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
+ if s.writeErr != nil {
+ return
+ }
+ _, s.writeErr = s.w.Write(blk.output)
+ s.nWritten += int64(len(blk.output))
+ }()
+ }(s.current)
+ return nil
+}
+
+// ReadFrom reads data from r until EOF or error.
+// The return value n is the number of bytes read.
+// Any error except io.EOF encountered during the read is also returned.
+//
+// The Copy function uses ReaderFrom if available.
+func (e *Encoder) ReadFrom(r io.Reader) (n int64, err error) {
+ if debugEncoder {
+ println("Using ReadFrom")
+ }
+
+ // Flush any current writes.
+ if len(e.state.filling) > 0 {
+ if err := e.nextBlock(false); err != nil {
+ return 0, err
+ }
+ }
+ e.state.filling = e.state.filling[:e.o.blockSize]
+ src := e.state.filling
+ for {
+ n2, err := r.Read(src)
+ if e.o.crc {
+ _, _ = e.state.encoder.CRC().Write(src[:n2])
+ }
+ // src is now the unfilled part...
+ src = src[n2:]
+ n += int64(n2)
+ switch err {
+ case io.EOF:
+ e.state.filling = e.state.filling[:len(e.state.filling)-len(src)]
+ if debugEncoder {
+ println("ReadFrom: got EOF final block:", len(e.state.filling))
+ }
+ return n, nil
+ case nil:
+ default:
+ if debugEncoder {
+ println("ReadFrom: got error:", err)
+ }
+ e.state.err = err
+ return n, err
+ }
+ if len(src) > 0 {
+ if debugEncoder {
+ println("ReadFrom: got space left in source:", len(src))
+ }
+ continue
+ }
+ err = e.nextBlock(false)
+ if err != nil {
+ return n, err
+ }
+ e.state.filling = e.state.filling[:e.o.blockSize]
+ src = e.state.filling
+ }
+}
+
+// Flush will send the currently written data to output
+// and block until everything has been written.
+// This should only be used on rare occasions where pushing the currently queued data is critical.
+func (e *Encoder) Flush() error {
+ s := &e.state
+ if len(s.filling) > 0 {
+ err := e.nextBlock(false)
+ if err != nil {
+ // Ignore Flush after Close.
+ if errors.Is(s.err, ErrEncoderClosed) {
+ return nil
+ }
+ return err
+ }
+ }
+ s.wg.Wait()
+ s.wWg.Wait()
+ if s.err != nil {
+ // Ignore Flush after Close.
+ if errors.Is(s.err, ErrEncoderClosed) {
+ return nil
+ }
+ return s.err
+ }
+ return s.writeErr
+}
+
+// Close will flush the final output and close the stream.
+// The function will block until everything has been written.
+// The Encoder can still be re-used after calling this.
+func (e *Encoder) Close() error {
+ s := &e.state
+ if s.encoder == nil {
+ return nil
+ }
+ if s.w == nil {
+ if len(s.filling) == 0 && !s.headerWritten && !s.eofWritten && s.nInput == 0 {
+ return nil
+ }
+ return errors.New("zstd: encoder has no writer")
+ }
+ err := e.nextBlock(true)
+ if err != nil {
+ if errors.Is(s.err, ErrEncoderClosed) {
+ return nil
+ }
+ return err
+ }
+ if s.frameContentSize > 0 {
+ if s.nInput != s.frameContentSize {
+ return fmt.Errorf("frame content size %d given, but %d bytes was written", s.frameContentSize, s.nInput)
+ }
+ }
+ if e.state.fullFrameWritten {
+ return s.err
+ }
+ s.wg.Wait()
+ s.wWg.Wait()
+
+ if s.err != nil {
+ return s.err
+ }
+ if s.writeErr != nil {
+ return s.writeErr
+ }
+
+ // Write CRC
+ if e.o.crc && s.err == nil {
+ // heap alloc.
+ var tmp [4]byte
+ _, s.err = s.w.Write(s.encoder.AppendCRC(tmp[:0]))
+ s.nWritten += 4
+ }
+
+ // Add padding with content from crypto/rand.Reader
+ if s.err == nil && e.o.pad > 0 {
+ add := calcSkippableFrame(s.nWritten, int64(e.o.pad))
+ frame, err := skippableFrame(s.filling[:0], add, rand.Reader)
+ if err != nil {
+ return err
+ }
+ _, s.err = s.w.Write(frame)
+ }
+ if s.err == nil {
+ s.err = ErrEncoderClosed
+ return nil
+ }
+
+ return s.err
+}
+
+// EncodeAll will encode all input in src and append it to dst.
+// This function can be called concurrently, but each call will only run on a single goroutine.
+// If empty input is given, nothing is returned, unless WithZeroFrames is specified.
+// Encoded blocks can be concatenated and the result will be the combined input stream.
+// Data compressed with EncodeAll can be decoded with the Decoder,
+// using either a stream or DecodeAll.
+func (e *Encoder) EncodeAll(src, dst []byte) []byte {
+ e.init.Do(e.initialize)
+ enc := <-e.encoders
+ defer func() {
+ e.encoders <- enc
+ }()
+ return e.encodeAll(enc, src, dst)
+}
+
+func (e *Encoder) encodeAll(enc encoder, src, dst []byte) []byte {
+ if len(src) == 0 {
+ if e.o.fullZero {
+ // Add frame header.
+ fh := frameHeader{
+ ContentSize: 0,
+ WindowSize: MinWindowSize,
+ SingleSegment: true,
+ // Adding a checksum would be a waste of space.
+ Checksum: false,
+ DictID: 0,
+ }
+ dst = fh.appendTo(dst)
+
+ // Write raw block as last one only.
+ var blk blockHeader
+ blk.setSize(0)
+ blk.setType(blockTypeRaw)
+ blk.setLast(true)
+ dst = blk.appendTo(dst)
+ }
+ return dst
+ }
+
+ // Use single segments when above minimum window and below window size.
+ single := len(src) <= e.o.windowSize && len(src) > MinWindowSize
+ if e.o.single != nil {
+ single = *e.o.single
+ }
+ fh := frameHeader{
+ ContentSize: uint64(len(src)),
+ WindowSize: uint32(enc.WindowSize(int64(len(src)))),
+ SingleSegment: single,
+ Checksum: e.o.crc,
+ DictID: e.o.dict.ID(),
+ }
+
+ // If less than 1MB, allocate a buffer up front.
+ if len(dst) == 0 && cap(dst) == 0 && len(src) < 1<<20 && !e.o.lowMem {
+ dst = make([]byte, 0, len(src))
+ }
+ dst = fh.appendTo(dst)
+
+ // If we can do everything in one block, prefer that.
+ if len(src) <= e.o.blockSize {
+ enc.Reset(e.o.dict, true)
+ // Slightly faster with no history and everything in one block.
+ if e.o.crc {
+ _, _ = enc.CRC().Write(src)
+ }
+ blk := enc.Block()
+ blk.last = true
+ if e.o.dict == nil {
+ enc.EncodeNoHist(blk, src)
+ } else {
+ enc.Encode(blk, src)
+ }
+
+ // If we got the exact same number of literals as input,
+ // assume the literals cannot be compressed.
+ oldout := blk.output
+ // Output directly to dst
+ blk.output = dst
+
+ err := blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
+ if err != nil {
+ panic(err)
+ }
+ dst = blk.output
+ blk.output = oldout
+ } else {
+ enc.Reset(e.o.dict, false)
+ blk := enc.Block()
+ for len(src) > 0 {
+ todo := src
+ if len(todo) > e.o.blockSize {
+ todo = todo[:e.o.blockSize]
+ }
+ src = src[len(todo):]
+ if e.o.crc {
+ _, _ = enc.CRC().Write(todo)
+ }
+ blk.pushOffsets()
+ enc.Encode(blk, todo)
+ if len(src) == 0 {
+ blk.last = true
+ }
+ err := blk.encode(todo, e.o.noEntropy, !e.o.allLitEntropy)
+ if err != nil {
+ panic(err)
+ }
+ dst = append(dst, blk.output...)
+ blk.reset(nil)
+ }
+ }
+ if e.o.crc {
+ dst = enc.AppendCRC(dst)
+ }
+ // Add padding with content from crypto/rand.Reader
+ if e.o.pad > 0 {
+ add := calcSkippableFrame(int64(len(dst)), int64(e.o.pad))
+ var err error
+ dst, err = skippableFrame(dst, add, rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+ }
+ return dst
+}
+
+// MaxEncodedSize returns the expected maximum
+// size of an encoded block or stream.
+func (e *Encoder) MaxEncodedSize(size int) int {
+ frameHeader := 4 + 2 // magic + frame header & window descriptor
+ if e.o.dict != nil {
+ frameHeader += 4
+ }
+ // Frame content size:
+ if size < 256 {
+ frameHeader++
+ } else if size < 65536+256 {
+ frameHeader += 2
+ } else if size < math.MaxInt32 {
+ frameHeader += 4
+ } else {
+ frameHeader += 8
+ }
+ // Final crc
+ if e.o.crc {
+ frameHeader += 4
+ }
+
+ // Max overhead is 3 bytes/block.
+ // There cannot be 0 blocks.
+ blocks := (size + e.o.blockSize) / e.o.blockSize
+
+ // Combine, add padding.
+ maxSz := frameHeader + 3*blocks + size
+ if e.o.pad > 1 {
+ maxSz += calcSkippableFrame(int64(maxSz), int64(e.o.pad))
+ }
+ return maxSz
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder_options.go b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
new file mode 100644
index 00000000000..e217be0a17a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
@@ -0,0 +1,378 @@
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "math"
+ "math/bits"
+ "runtime"
+ "strings"
+)
+
+// EOption is an option for creating a encoder.
+type EOption func(*encoderOptions) error
+
+// options retains accumulated state of multiple options.
+type encoderOptions struct {
+ resetOpt bool
+ concurrent int
+ level EncoderLevel
+ single *bool
+ pad int
+ blockSize int
+ windowSize int
+ crc bool
+ fullZero bool
+ noEntropy bool
+ allLitEntropy bool
+ customWindow bool
+ customALEntropy bool
+ customBlockSize bool
+ lowMem bool
+ dict *dict
+}
+
+func (o *encoderOptions) setDefault() {
+ *o = encoderOptions{
+ concurrent: runtime.GOMAXPROCS(0),
+ crc: true,
+ single: nil,
+ blockSize: maxCompressedBlockSize,
+ windowSize: 8 << 20,
+ level: SpeedDefault,
+ allLitEntropy: false,
+ lowMem: false,
+ fullZero: true,
+ }
+}
+
+// encoder returns an encoder with the selected options.
+func (o encoderOptions) encoder() encoder {
+ switch o.level {
+ case SpeedFastest:
+ if o.dict != nil {
+ return &fastEncoderDict{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}
+ }
+ return &fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}
+
+ case SpeedDefault:
+ if o.dict != nil {
+ return &doubleFastEncoderDict{fastEncoderDict: fastEncoderDict{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}}
+ }
+ return &doubleFastEncoder{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}
+ case SpeedBetterCompression:
+ if o.dict != nil {
+ return &betterFastEncoderDict{betterFastEncoder: betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}
+ }
+ return &betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}
+ case SpeedBestCompression:
+ return &bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}
+ }
+ panic("unknown compression level")
+}
+
+// WithEncoderCRC will add CRC value to output.
+// Output will be 4 bytes larger.
+// Can be changed with ResetWithOptions.
+func WithEncoderCRC(b bool) EOption {
+ return func(o *encoderOptions) error { o.crc = b; return nil }
+}
+
+// WithEncoderConcurrency will set the concurrency,
+// meaning the maximum number of encoders to run concurrently.
+// The value supplied must be at least 0.
+// When a value of 0 is provided GOMAXPROCS will be used.
+// For streams, setting a value of 1 will disable async compression.
+// By default this will be set to GOMAXPROCS.
+// Cannot be changed with ResetWithOptions.
+func WithEncoderConcurrency(n int) EOption {
+ return func(o *encoderOptions) error {
+ if n < 0 {
+ return errors.New("concurrency must at least 0")
+ }
+ if n == 0 {
+ n = runtime.GOMAXPROCS(0)
+ }
+ if o.resetOpt && n != o.concurrent {
+ return errors.New("WithEncoderConcurrency cannot be changed on Reset")
+ }
+ o.concurrent = n
+ return nil
+ }
+}
+
+// WithWindowSize will set the maximum allowed back-reference distance.
+// The value must be a power of two between MinWindowSize and MaxWindowSize.
+// A larger value will enable better compression but allocate more memory and,
+// for above-default values, take considerably longer.
+// The default value is determined by the compression level and max 8MB.
+// Cannot be changed with ResetWithOptions.
+func WithWindowSize(n int) EOption {
+ return func(o *encoderOptions) error {
+ switch {
+ case n < MinWindowSize:
+ return fmt.Errorf("window size must be at least %d", MinWindowSize)
+ case n > MaxWindowSize:
+ return fmt.Errorf("window size must be at most %d", MaxWindowSize)
+ case (n & (n - 1)) != 0:
+ return errors.New("window size must be a power of 2")
+ }
+ if o.resetOpt && n != o.windowSize {
+ return errors.New("WithWindowSize cannot be changed on Reset")
+ }
+
+ o.windowSize = n
+ o.customWindow = true
+ if o.blockSize > o.windowSize {
+ o.blockSize = o.windowSize
+ o.customBlockSize = true
+ }
+ return nil
+ }
+}
+
+// WithEncoderPadding will add padding to all output so the size will be a multiple of n.
+// This can be used to obfuscate the exact output size or make blocks of a certain size.
+// The contents will be a skippable frame, so it will be invisible by the decoder.
+// n must be > 0 and <= 1GB, 1<<30 bytes.
+// The padded area will be filled with data from crypto/rand.Reader.
+// If `EncodeAll` is used with data already in the destination, the total size will be multiple of this.
+// Can be changed with ResetWithOptions.
+func WithEncoderPadding(n int) EOption {
+ return func(o *encoderOptions) error {
+ if n <= 0 {
+ return fmt.Errorf("padding must be at least 1")
+ }
+ // No need to waste our time.
+ if n == 1 {
+ n = 0
+ }
+ if n > 1<<30 {
+ return fmt.Errorf("padding must less than 1GB (1<<30 bytes) ")
+ }
+ o.pad = n
+ return nil
+ }
+}
+
+// EncoderLevel predefines encoder compression levels.
+// Only use the constants made available, since the actual mapping
+// of these values are very likely to change and your compression could change
+// unpredictably when upgrading the library.
+type EncoderLevel int
+
+const (
+ speedNotSet EncoderLevel = iota
+
+ // SpeedFastest will choose the fastest reasonable compression.
+ // This is roughly equivalent to the fastest Zstandard mode.
+ SpeedFastest
+
+ // SpeedDefault is the default "pretty fast" compression option.
+ // This is roughly equivalent to the default Zstandard mode (level 3).
+ SpeedDefault
+
+ // SpeedBetterCompression will yield better compression than the default.
+ // Currently it is about zstd level 7-8 with ~ 2x-3x the default CPU usage.
+ // By using this, notice that CPU usage may go up in the future.
+ SpeedBetterCompression
+
+ // SpeedBestCompression will choose the best available compression option.
+ // This will offer the best compression no matter the CPU cost.
+ SpeedBestCompression
+
+ // speedLast should be kept as the last actual compression option.
+ // The is not for external usage, but is used to keep track of the valid options.
+ speedLast
+)
+
+// EncoderLevelFromString will convert a string representation of an encoding level back
+// to a compression level. The compare is not case sensitive.
+// If the string wasn't recognized, (false, SpeedDefault) will be returned.
+func EncoderLevelFromString(s string) (bool, EncoderLevel) {
+ for l := speedNotSet + 1; l < speedLast; l++ {
+ if strings.EqualFold(s, l.String()) {
+ return true, l
+ }
+ }
+ return false, SpeedDefault
+}
+
+// EncoderLevelFromZstd will return an encoder level that closest matches the compression
+// ratio of a specific zstd compression level.
+// Many input values will provide the same compression level.
+func EncoderLevelFromZstd(level int) EncoderLevel {
+ switch {
+ case level < 3:
+ return SpeedFastest
+ case level >= 3 && level < 6:
+ return SpeedDefault
+ case level >= 6 && level < 10:
+ return SpeedBetterCompression
+ default:
+ return SpeedBestCompression
+ }
+}
+
+// String provides a string representation of the compression level.
+func (e EncoderLevel) String() string {
+ switch e {
+ case SpeedFastest:
+ return "fastest"
+ case SpeedDefault:
+ return "default"
+ case SpeedBetterCompression:
+ return "better"
+ case SpeedBestCompression:
+ return "best"
+ default:
+ return "invalid"
+ }
+}
+
+// WithEncoderLevel specifies a predefined compression level.
+// Cannot be changed with ResetWithOptions.
+func WithEncoderLevel(l EncoderLevel) EOption {
+ return func(o *encoderOptions) error {
+ switch {
+ case l <= speedNotSet || l >= speedLast:
+ return fmt.Errorf("unknown encoder level")
+ }
+ if o.resetOpt && l != o.level {
+ return errors.New("WithEncoderLevel cannot be changed on Reset")
+ }
+ o.level = l
+ if !o.customWindow {
+ switch o.level {
+ case SpeedFastest:
+ o.windowSize = 4 << 20
+ if !o.customBlockSize {
+ o.blockSize = 1 << 16
+ }
+ case SpeedDefault:
+ o.windowSize = 8 << 20
+ case SpeedBetterCompression:
+ o.windowSize = 8 << 20
+ case SpeedBestCompression:
+ o.windowSize = 8 << 20
+ }
+ }
+ if !o.customALEntropy {
+ o.allLitEntropy = l > SpeedDefault
+ }
+
+ return nil
+ }
+}
+
+// WithZeroFrames will encode 0 length input as full frames.
+// This can be needed for compatibility with zstandard usage,
+// but is not needed for this package.
+// Can be changed with ResetWithOptions.
+func WithZeroFrames(b bool) EOption {
+ return func(o *encoderOptions) error {
+ o.fullZero = b
+ return nil
+ }
+}
+
+// WithAllLitEntropyCompression will apply entropy compression if no matches are found.
+// Disabling this will skip incompressible data faster, but in cases with no matches but
+// skewed character distribution compression is lost.
+// Default value depends on the compression level selected.
+// Can be changed with ResetWithOptions.
+func WithAllLitEntropyCompression(b bool) EOption {
+ return func(o *encoderOptions) error {
+ o.customALEntropy = true
+ o.allLitEntropy = b
+ return nil
+ }
+}
+
+// WithNoEntropyCompression will always skip entropy compression of literals.
+// This can be useful if content has matches, but unlikely to benefit from entropy
+// compression. Usually the slight speed improvement is not worth enabling this.
+// Can be changed with ResetWithOptions.
+func WithNoEntropyCompression(b bool) EOption {
+ return func(o *encoderOptions) error {
+ o.noEntropy = b
+ return nil
+ }
+}
+
+// WithSingleSegment will set the "single segment" flag when EncodeAll is used.
+// If this flag is set, data must be regenerated within a single continuous memory segment.
+// In this case, Window_Descriptor byte is skipped, but Frame_Content_Size is necessarily present.
+// As a consequence, the decoder must allocate a memory segment of size equal or larger than size of your content.
+// In order to preserve the decoder from unreasonable memory requirements,
+// a decoder is allowed to reject a compressed frame which requests a memory size beyond decoder's authorized range.
+// For broader compatibility, decoders are recommended to support memory sizes of at least 8 MB.
+// This is only a recommendation, each decoder is free to support higher or lower limits, depending on local limitations.
+// If this is not specified, block encodes will automatically choose this based on the input size and the window size.
+// This setting has no effect on streamed encodes.
+// Can be changed with ResetWithOptions.
+func WithSingleSegment(b bool) EOption {
+ return func(o *encoderOptions) error {
+ o.single = &b
+ return nil
+ }
+}
+
+// WithLowerEncoderMem will trade in some memory cases trade less memory usage for
+// slower encoding speed.
+// This will not change the window size which is the primary function for reducing
+// memory usage. See WithWindowSize.
+// Cannot be changed with ResetWithOptions.
+func WithLowerEncoderMem(b bool) EOption {
+ return func(o *encoderOptions) error {
+ if o.resetOpt && b != o.lowMem {
+ return errors.New("WithLowerEncoderMem cannot be changed on Reset")
+ }
+ o.lowMem = b
+ return nil
+ }
+}
+
+// WithEncoderDict allows to register a dictionary that will be used for the encode.
+//
+// The slice dict must be in the [dictionary format] produced by
+// "zstd --train" from the Zstandard reference implementation.
+//
+// The encoder *may* choose to use no dictionary instead for certain payloads.
+// Can be changed with ResetWithOptions.
+//
+// [dictionary format]: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format
+func WithEncoderDict(dict []byte) EOption {
+ return func(o *encoderOptions) error {
+ d, err := loadDict(dict)
+ if err != nil {
+ return err
+ }
+ o.dict = d
+ return nil
+ }
+}
+
+// WithEncoderDictRaw registers a dictionary that may be used by the encoder.
+//
+// The slice content may contain arbitrary data. It will be used as an initial
+// history.
+// Can be changed with ResetWithOptions.
+func WithEncoderDictRaw(id uint32, content []byte) EOption {
+ return func(o *encoderOptions) error {
+ if bits.UintSize > 32 && uint(len(content)) > dictMaxLength {
+ return fmt.Errorf("dictionary of size %d > 2GiB too large", len(content))
+ }
+ o.dict = &dict{id: id, content: content, offsets: [3]int{1, 4, 8}}
+ return nil
+ }
+}
+
+// WithEncoderDictDelete clears the dictionary, so no dictionary will be used.
+// Should be used with ResetWithOptions.
+func WithEncoderDictDelete() EOption {
+ return func(o *encoderOptions) error {
+ o.dict = nil
+ return nil
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/framedec.go b/vendor/github.com/klauspost/compress/zstd/framedec.go
new file mode 100644
index 00000000000..d88f067e5c2
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/framedec.go
@@ -0,0 +1,412 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "errors"
+ "io"
+
+ "github.com/klauspost/compress/zstd/internal/xxhash"
+)
+
+type frameDec struct {
+ o decoderOptions
+ crc *xxhash.Digest
+
+ WindowSize uint64
+
+ // Frame history passed between blocks
+ history history
+
+ rawInput byteBuffer
+
+ // Byte buffer that can be reused for small input blocks.
+ bBuf byteBuf
+
+ FrameContentSize uint64
+
+ DictionaryID uint32
+ HasCheckSum bool
+ SingleSegment bool
+}
+
+const (
+ // MinWindowSize is the minimum Window Size, which is 1 KB.
+ MinWindowSize = 1 << 10
+
+ // MaxWindowSize is the maximum encoder window size
+ // and the default decoder maximum window size.
+ MaxWindowSize = 1 << 29
+)
+
+const (
+ frameMagic = "\x28\xb5\x2f\xfd"
+ skippableFrameMagic = "\x2a\x4d\x18"
+)
+
+func newFrameDec(o decoderOptions) *frameDec {
+ if o.maxWindowSize > o.maxDecodedSize {
+ o.maxWindowSize = o.maxDecodedSize
+ }
+ d := frameDec{
+ o: o,
+ }
+ return &d
+}
+
+// reset will read the frame header and prepare for block decoding.
+// If nothing can be read from the input, io.EOF will be returned.
+// Any other error indicated that the stream contained data, but
+// there was a problem.
+func (d *frameDec) reset(br byteBuffer) error {
+ d.HasCheckSum = false
+ d.WindowSize = 0
+ var signature [4]byte
+ for {
+ var err error
+ // Check if we can read more...
+ b, err := br.readSmall(1)
+ switch err {
+ case io.EOF, io.ErrUnexpectedEOF:
+ return io.EOF
+ case nil:
+ signature[0] = b[0]
+ default:
+ return err
+ }
+ // Read the rest, don't allow io.ErrUnexpectedEOF
+ b, err = br.readSmall(3)
+ switch err {
+ case io.EOF:
+ return io.EOF
+ case nil:
+ copy(signature[1:], b)
+ default:
+ return err
+ }
+
+ if string(signature[1:4]) != skippableFrameMagic || signature[0]&0xf0 != 0x50 {
+ if debugDecoder {
+ println("Not skippable", hex.EncodeToString(signature[:]), hex.EncodeToString([]byte(skippableFrameMagic)))
+ }
+ // Break if not skippable frame.
+ break
+ }
+ // Read size to skip
+ b, err = br.readSmall(4)
+ if err != nil {
+ if debugDecoder {
+ println("Reading Frame Size", err)
+ }
+ return err
+ }
+ n := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ println("Skipping frame with", n, "bytes.")
+ err = br.skipN(int64(n))
+ if err != nil {
+ if debugDecoder {
+ println("Reading discarded frame", err)
+ }
+ return err
+ }
+ }
+ if string(signature[:]) != frameMagic {
+ if debugDecoder {
+ println("Got magic numbers: ", signature, "want:", []byte(frameMagic))
+ }
+ return ErrMagicMismatch
+ }
+
+ // Read Frame_Header_Descriptor
+ fhd, err := br.readByte()
+ if err != nil {
+ if debugDecoder {
+ println("Reading Frame_Header_Descriptor", err)
+ }
+ return err
+ }
+ d.SingleSegment = fhd&(1<<5) != 0
+
+ if fhd&(1<<3) != 0 {
+ return errors.New("reserved bit set on frame header")
+ }
+
+ // Read Window_Descriptor
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor
+ d.WindowSize = 0
+ if !d.SingleSegment {
+ wd, err := br.readByte()
+ if err != nil {
+ if debugDecoder {
+ println("Reading Window_Descriptor", err)
+ }
+ return err
+ }
+ if debugDecoder {
+ printf("raw: %x, mantissa: %d, exponent: %d\n", wd, wd&7, wd>>3)
+ }
+ windowLog := 10 + (wd >> 3)
+ windowBase := uint64(1) << windowLog
+ windowAdd := (windowBase / 8) * uint64(wd&0x7)
+ d.WindowSize = windowBase + windowAdd
+ }
+
+ // Read Dictionary_ID
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_id
+ d.DictionaryID = 0
+ if size := fhd & 3; size != 0 {
+ if size == 3 {
+ size = 4
+ }
+
+ b, err := br.readSmall(int(size))
+ if err != nil {
+ println("Reading Dictionary_ID", err)
+ return err
+ }
+ var id uint32
+ switch len(b) {
+ case 1:
+ id = uint32(b[0])
+ case 2:
+ id = uint32(b[0]) | (uint32(b[1]) << 8)
+ case 4:
+ id = uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ }
+ if debugDecoder {
+ println("Dict size", size, "ID:", id)
+ }
+ d.DictionaryID = id
+ }
+
+ // Read Frame_Content_Size
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frame_content_size
+ var fcsSize int
+ v := fhd >> 6
+ switch v {
+ case 0:
+ if d.SingleSegment {
+ fcsSize = 1
+ }
+ default:
+ fcsSize = 1 << v
+ }
+ d.FrameContentSize = fcsUnknown
+ if fcsSize > 0 {
+ b, err := br.readSmall(fcsSize)
+ if err != nil {
+ println("Reading Frame content", err)
+ return err
+ }
+ switch len(b) {
+ case 1:
+ d.FrameContentSize = uint64(b[0])
+ case 2:
+ // When FCS_Field_Size is 2, the offset of 256 is added.
+ d.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) + 256
+ case 4:
+ d.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) | (uint64(b[2]) << 16) | (uint64(b[3]) << 24)
+ case 8:
+ d1 := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ d2 := uint32(b[4]) | (uint32(b[5]) << 8) | (uint32(b[6]) << 16) | (uint32(b[7]) << 24)
+ d.FrameContentSize = uint64(d1) | (uint64(d2) << 32)
+ }
+ if debugDecoder {
+ println("Read FCS:", d.FrameContentSize)
+ }
+ }
+
+ // Move this to shared.
+ d.HasCheckSum = fhd&(1<<2) != 0
+ if d.HasCheckSum {
+ if d.crc == nil {
+ d.crc = xxhash.New()
+ }
+ d.crc.Reset()
+ }
+
+ if d.WindowSize > d.o.maxWindowSize {
+ if debugDecoder {
+ printf("window size %d > max %d\n", d.WindowSize, d.o.maxWindowSize)
+ }
+ return ErrWindowSizeExceeded
+ }
+
+ if d.WindowSize == 0 && d.SingleSegment {
+ // We may not need window in this case.
+ d.WindowSize = max(d.FrameContentSize, MinWindowSize)
+ if d.WindowSize > d.o.maxDecodedSize {
+ if debugDecoder {
+ printf("window size %d > max %d\n", d.WindowSize, d.o.maxWindowSize)
+ }
+ return ErrDecoderSizeExceeded
+ }
+ }
+
+ // The minimum Window_Size is 1 KB.
+ if d.WindowSize < MinWindowSize {
+ if debugDecoder {
+ println("got window size: ", d.WindowSize)
+ }
+ return ErrWindowSizeTooSmall
+ }
+ d.history.windowSize = int(d.WindowSize)
+ if !d.o.lowMem || d.history.windowSize < maxBlockSize {
+ // Alloc 2x window size if not low-mem, or window size below 2MB.
+ d.history.allocFrameBuffer = d.history.windowSize * 2
+ } else {
+ if d.o.lowMem {
+ // Alloc with 1MB extra.
+ d.history.allocFrameBuffer = d.history.windowSize + maxBlockSize/2
+ } else {
+ // Alloc with 2MB extra.
+ d.history.allocFrameBuffer = d.history.windowSize + maxBlockSize
+ }
+ }
+
+ if debugDecoder {
+ println("Frame: Dict:", d.DictionaryID, "FrameContentSize:", d.FrameContentSize, "singleseg:", d.SingleSegment, "window:", d.WindowSize, "crc:", d.HasCheckSum)
+ }
+
+ // history contains input - maybe we do something
+ d.rawInput = br
+ return nil
+}
+
+// next will start decoding the next block from stream.
+func (d *frameDec) next(block *blockDec) error {
+ if debugDecoder {
+ println("decoding new block")
+ }
+ err := block.reset(d.rawInput, d.WindowSize)
+ if err != nil {
+ println("block error:", err)
+ // Signal the frame decoder we have a problem.
+ block.sendErr(err)
+ return err
+ }
+ return nil
+}
+
+// checkCRC will check the checksum, assuming the frame has one.
+// Will return ErrCRCMismatch if crc check failed, otherwise nil.
+func (d *frameDec) checkCRC() error {
+ // We can overwrite upper tmp now
+ buf, err := d.rawInput.readSmall(4)
+ if err != nil {
+ println("CRC missing?", err)
+ return err
+ }
+
+ want := binary.LittleEndian.Uint32(buf[:4])
+ got := uint32(d.crc.Sum64())
+
+ if got != want {
+ if debugDecoder {
+ printf("CRC check failed: got %08x, want %08x\n", got, want)
+ }
+ return ErrCRCMismatch
+ }
+ if debugDecoder {
+ printf("CRC ok %08x\n", got)
+ }
+ return nil
+}
+
+// consumeCRC skips over the checksum, assuming the frame has one.
+func (d *frameDec) consumeCRC() error {
+ _, err := d.rawInput.readSmall(4)
+ if err != nil {
+ println("CRC missing?", err)
+ }
+ return err
+}
+
+// runDecoder will run the decoder for the remainder of the frame.
+func (d *frameDec) runDecoder(dst []byte, dec *blockDec) ([]byte, error) {
+ saved := d.history.b
+
+ // We use the history for output to avoid copying it.
+ d.history.b = dst
+ d.history.ignoreBuffer = len(dst)
+ // Store input length, so we only check new data.
+ crcStart := len(dst)
+ d.history.decoders.maxSyncLen = 0
+ if d.o.limitToCap {
+ d.history.decoders.maxSyncLen = uint64(cap(dst) - len(dst))
+ }
+ if d.FrameContentSize != fcsUnknown {
+ if !d.o.limitToCap || d.FrameContentSize+uint64(len(dst)) < d.history.decoders.maxSyncLen {
+ d.history.decoders.maxSyncLen = d.FrameContentSize + uint64(len(dst))
+ }
+ if d.history.decoders.maxSyncLen > d.o.maxDecodedSize {
+ if debugDecoder {
+ println("maxSyncLen:", d.history.decoders.maxSyncLen, "> maxDecodedSize:", d.o.maxDecodedSize)
+ }
+ return dst, ErrDecoderSizeExceeded
+ }
+ if debugDecoder {
+ println("maxSyncLen:", d.history.decoders.maxSyncLen)
+ }
+ if !d.o.limitToCap && uint64(cap(dst)) < d.history.decoders.maxSyncLen {
+ // Alloc for output
+ dst2 := make([]byte, len(dst), d.history.decoders.maxSyncLen+compressedBlockOverAlloc)
+ copy(dst2, dst)
+ dst = dst2
+ }
+ }
+ var err error
+ for {
+ err = dec.reset(d.rawInput, d.WindowSize)
+ if err != nil {
+ break
+ }
+ if debugDecoder {
+ println("next block:", dec)
+ }
+ err = dec.decodeBuf(&d.history)
+ if err != nil {
+ break
+ }
+ if uint64(len(d.history.b)-crcStart) > d.o.maxDecodedSize {
+ println("runDecoder: maxDecodedSize exceeded", uint64(len(d.history.b)-crcStart), ">", d.o.maxDecodedSize)
+ err = ErrDecoderSizeExceeded
+ break
+ }
+ if d.o.limitToCap && len(d.history.b) > cap(dst) {
+ println("runDecoder: cap exceeded", uint64(len(d.history.b)), ">", cap(dst))
+ err = ErrDecoderSizeExceeded
+ break
+ }
+ if uint64(len(d.history.b)-crcStart) > d.FrameContentSize {
+ println("runDecoder: FrameContentSize exceeded", uint64(len(d.history.b)-crcStart), ">", d.FrameContentSize)
+ err = ErrFrameSizeExceeded
+ break
+ }
+ if dec.Last {
+ break
+ }
+ if debugDecoder {
+ println("runDecoder: FrameContentSize", uint64(len(d.history.b)-crcStart), "<=", d.FrameContentSize)
+ }
+ }
+ dst = d.history.b
+ if err == nil {
+ if d.FrameContentSize != fcsUnknown && uint64(len(d.history.b)-crcStart) != d.FrameContentSize {
+ err = ErrFrameSizeMismatch
+ } else if d.HasCheckSum {
+ if d.o.ignoreChecksum {
+ err = d.consumeCRC()
+ } else {
+ d.crc.Write(dst[crcStart:])
+ err = d.checkCRC()
+ }
+ }
+ }
+ d.history.b = saved
+ return dst, err
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/frameenc.go b/vendor/github.com/klauspost/compress/zstd/frameenc.go
new file mode 100644
index 00000000000..667ca06794e
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/frameenc.go
@@ -0,0 +1,137 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "math"
+ "math/bits"
+)
+
+type frameHeader struct {
+ ContentSize uint64
+ WindowSize uint32
+ SingleSegment bool
+ Checksum bool
+ DictID uint32
+}
+
+const maxHeaderSize = 14
+
+func (f frameHeader) appendTo(dst []byte) []byte {
+ dst = append(dst, frameMagic...)
+ var fhd uint8
+ if f.Checksum {
+ fhd |= 1 << 2
+ }
+ if f.SingleSegment {
+ fhd |= 1 << 5
+ }
+
+ var dictIDContent []byte
+ if f.DictID > 0 {
+ var tmp [4]byte
+ if f.DictID < 256 {
+ fhd |= 1
+ tmp[0] = uint8(f.DictID)
+ dictIDContent = tmp[:1]
+ } else if f.DictID < 1<<16 {
+ fhd |= 2
+ binary.LittleEndian.PutUint16(tmp[:2], uint16(f.DictID))
+ dictIDContent = tmp[:2]
+ } else {
+ fhd |= 3
+ binary.LittleEndian.PutUint32(tmp[:4], f.DictID)
+ dictIDContent = tmp[:4]
+ }
+ }
+ var fcs uint8
+ if f.ContentSize >= 256 {
+ fcs++
+ }
+ if f.ContentSize >= 65536+256 {
+ fcs++
+ }
+ if f.ContentSize >= 0xffffffff {
+ fcs++
+ }
+
+ fhd |= fcs << 6
+
+ dst = append(dst, fhd)
+ if !f.SingleSegment {
+ const winLogMin = 10
+ windowLog := (bits.Len32(f.WindowSize-1) - winLogMin) << 3
+ dst = append(dst, uint8(windowLog))
+ }
+ if f.DictID > 0 {
+ dst = append(dst, dictIDContent...)
+ }
+ switch fcs {
+ case 0:
+ if f.SingleSegment {
+ dst = append(dst, uint8(f.ContentSize))
+ }
+ // Unless SingleSegment is set, framessizes < 256 are not stored.
+ case 1:
+ f.ContentSize -= 256
+ dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8))
+ case 2:
+ dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8), uint8(f.ContentSize>>16), uint8(f.ContentSize>>24))
+ case 3:
+ dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8), uint8(f.ContentSize>>16), uint8(f.ContentSize>>24),
+ uint8(f.ContentSize>>32), uint8(f.ContentSize>>40), uint8(f.ContentSize>>48), uint8(f.ContentSize>>56))
+ default:
+ panic("invalid fcs")
+ }
+ return dst
+}
+
+const skippableFrameHeader = 4 + 4
+
+// calcSkippableFrame will return a total size to be added for written
+// to be divisible by multiple.
+// The value will always be > skippableFrameHeader.
+// The function will panic if written < 0 or wantMultiple <= 0.
+func calcSkippableFrame(written, wantMultiple int64) int {
+ if wantMultiple <= 0 {
+ panic("wantMultiple <= 0")
+ }
+ if written < 0 {
+ panic("written < 0")
+ }
+ leftOver := written % wantMultiple
+ if leftOver == 0 {
+ return 0
+ }
+ toAdd := wantMultiple - leftOver
+ for toAdd < skippableFrameHeader {
+ toAdd += wantMultiple
+ }
+ return int(toAdd)
+}
+
+// skippableFrame will add a skippable frame with a total size of bytes.
+// total should be >= skippableFrameHeader and < math.MaxUint32.
+func skippableFrame(dst []byte, total int, r io.Reader) ([]byte, error) {
+ if total == 0 {
+ return dst, nil
+ }
+ if total < skippableFrameHeader {
+ return dst, fmt.Errorf("requested skippable frame (%d) < 8", total)
+ }
+ if int64(total) > math.MaxUint32 {
+ return dst, fmt.Errorf("requested skippable frame (%d) > max uint32", total)
+ }
+ dst = append(dst, 0x50, 0x2a, 0x4d, 0x18)
+ f := uint32(total - skippableFrameHeader)
+ dst = append(dst, uint8(f), uint8(f>>8), uint8(f>>16), uint8(f>>24))
+ start := len(dst)
+ dst = append(dst, make([]byte, f)...)
+ _, err := io.ReadFull(r, dst[start:])
+ return dst, err
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder.go
new file mode 100644
index 00000000000..2f8860a722b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder.go
@@ -0,0 +1,307 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+)
+
+const (
+ tablelogAbsoluteMax = 9
+)
+
+const (
+ /*!MEMORY_USAGE :
+ * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+ * Increasing memory usage improves compression ratio
+ * Reduced memory usage can improve speed, due to cache effect
+ * Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
+ maxMemoryUsage = tablelogAbsoluteMax + 2
+
+ maxTableLog = maxMemoryUsage - 2
+ maxTablesize = 1 << maxTableLog
+ maxTableMask = (1 << maxTableLog) - 1
+ minTablelog = 5
+ maxSymbolValue = 255
+)
+
+// fseDecoder provides temporary storage for compression and decompression.
+type fseDecoder struct {
+ dt [maxTablesize]decSymbol // Decompression table.
+ symbolLen uint16 // Length of active part of the symbol table.
+ actualTableLog uint8 // Selected tablelog.
+ maxBits uint8 // Maximum number of additional bits
+
+ // used for table creation to avoid allocations.
+ stateTable [256]uint16
+ norm [maxSymbolValue + 1]int16
+ preDefined bool
+}
+
+// tableStep returns the next table index.
+func tableStep(tableSize uint32) uint32 {
+ return (tableSize >> 1) + (tableSize >> 3) + 3
+}
+
+// readNCount will read the symbol distribution so decoding tables can be constructed.
+func (s *fseDecoder) readNCount(b *byteReader, maxSymbol uint16) error {
+ var (
+ charnum uint16
+ previous0 bool
+ )
+ if b.remain() < 4 {
+ return errors.New("input too small")
+ }
+ bitStream := b.Uint32NC()
+ nbBits := uint((bitStream & 0xF) + minTablelog) // extract tableLog
+ if nbBits > tablelogAbsoluteMax {
+ println("Invalid tablelog:", nbBits)
+ return errors.New("tableLog too large")
+ }
+ bitStream >>= 4
+ bitCount := uint(4)
+
+ s.actualTableLog = uint8(nbBits)
+ remaining := int32((1 << nbBits) + 1)
+ threshold := int32(1 << nbBits)
+ gotTotal := int32(0)
+ nbBits++
+
+ for remaining > 1 && charnum <= maxSymbol {
+ if previous0 {
+ //println("prev0")
+ n0 := charnum
+ for (bitStream & 0xFFFF) == 0xFFFF {
+ //println("24 x 0")
+ n0 += 24
+ if r := b.remain(); r > 5 {
+ b.advance(2)
+ // The check above should make sure we can read 32 bits
+ bitStream = b.Uint32NC() >> bitCount
+ } else {
+ // end of bit stream
+ bitStream >>= 16
+ bitCount += 16
+ }
+ }
+ //printf("bitstream: %d, 0b%b", bitStream&3, bitStream)
+ for (bitStream & 3) == 3 {
+ n0 += 3
+ bitStream >>= 2
+ bitCount += 2
+ }
+ n0 += uint16(bitStream & 3)
+ bitCount += 2
+
+ if n0 > maxSymbolValue {
+ return errors.New("maxSymbolValue too small")
+ }
+ //println("inserting ", n0-charnum, "zeroes from idx", charnum, "ending before", n0)
+ for charnum < n0 {
+ s.norm[uint8(charnum)] = 0
+ charnum++
+ }
+
+ if r := b.remain(); r >= 7 || r-int(bitCount>>3) >= 4 {
+ b.advance(bitCount >> 3)
+ bitCount &= 7
+ // The check above should make sure we can read 32 bits
+ bitStream = b.Uint32NC() >> bitCount
+ } else {
+ bitStream >>= 2
+ }
+ }
+
+ max := (2*threshold - 1) - remaining
+ var count int32
+
+ if int32(bitStream)&(threshold-1) < max {
+ count = int32(bitStream) & (threshold - 1)
+ if debugAsserts && nbBits < 1 {
+ panic("nbBits underflow")
+ }
+ bitCount += nbBits - 1
+ } else {
+ count = int32(bitStream) & (2*threshold - 1)
+ if count >= threshold {
+ count -= max
+ }
+ bitCount += nbBits
+ }
+
+ // extra accuracy
+ count--
+ if count < 0 {
+ // -1 means +1
+ remaining += count
+ gotTotal -= count
+ } else {
+ remaining -= count
+ gotTotal += count
+ }
+ s.norm[charnum&0xff] = int16(count)
+ charnum++
+ previous0 = count == 0
+ for remaining < threshold {
+ nbBits--
+ threshold >>= 1
+ }
+
+ if r := b.remain(); r >= 7 || r-int(bitCount>>3) >= 4 {
+ b.advance(bitCount >> 3)
+ bitCount &= 7
+ // The check above should make sure we can read 32 bits
+ bitStream = b.Uint32NC() >> (bitCount & 31)
+ } else {
+ bitCount -= (uint)(8 * (len(b.b) - 4 - b.off))
+ b.off = len(b.b) - 4
+ bitStream = b.Uint32() >> (bitCount & 31)
+ }
+ }
+ s.symbolLen = charnum
+ if s.symbolLen <= 1 {
+ return fmt.Errorf("symbolLen (%d) too small", s.symbolLen)
+ }
+ if s.symbolLen > maxSymbolValue+1 {
+ return fmt.Errorf("symbolLen (%d) too big", s.symbolLen)
+ }
+ if remaining != 1 {
+ return fmt.Errorf("corruption detected (remaining %d != 1)", remaining)
+ }
+ if bitCount > 32 {
+ return fmt.Errorf("corruption detected (bitCount %d > 32)", bitCount)
+ }
+ if gotTotal != 1<> 3)
+ return s.buildDtable()
+}
+
+func (s *fseDecoder) mustReadFrom(r io.Reader) {
+ fatalErr := func(err error) {
+ if err != nil {
+ panic(err)
+ }
+ }
+ // dt [maxTablesize]decSymbol // Decompression table.
+ // symbolLen uint16 // Length of active part of the symbol table.
+ // actualTableLog uint8 // Selected tablelog.
+ // maxBits uint8 // Maximum number of additional bits
+ // // used for table creation to avoid allocations.
+ // stateTable [256]uint16
+ // norm [maxSymbolValue + 1]int16
+ // preDefined bool
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.dt))
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.symbolLen))
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.actualTableLog))
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.maxBits))
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.stateTable))
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.norm))
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.preDefined))
+}
+
+// decSymbol contains information about a state entry,
+// Including the state offset base, the output symbol and
+// the number of bits to read for the low part of the destination state.
+// Using a composite uint64 is faster than a struct with separate members.
+type decSymbol uint64
+
+func newDecSymbol(nbits, addBits uint8, newState uint16, baseline uint32) decSymbol {
+ return decSymbol(nbits) | (decSymbol(addBits) << 8) | (decSymbol(newState) << 16) | (decSymbol(baseline) << 32)
+}
+
+func (d decSymbol) nbBits() uint8 {
+ return uint8(d)
+}
+
+func (d decSymbol) addBits() uint8 {
+ return uint8(d >> 8)
+}
+
+func (d decSymbol) newState() uint16 {
+ return uint16(d >> 16)
+}
+
+func (d decSymbol) baselineInt() int {
+ return int(d >> 32)
+}
+
+func (d *decSymbol) setNBits(nBits uint8) {
+ const mask = 0xffffffffffffff00
+ *d = (*d & mask) | decSymbol(nBits)
+}
+
+func (d *decSymbol) setAddBits(addBits uint8) {
+ const mask = 0xffffffffffff00ff
+ *d = (*d & mask) | (decSymbol(addBits) << 8)
+}
+
+func (d *decSymbol) setNewState(state uint16) {
+ const mask = 0xffffffff0000ffff
+ *d = (*d & mask) | decSymbol(state)<<16
+}
+
+func (d *decSymbol) setExt(addBits uint8, baseline uint32) {
+ const mask = 0xffff00ff
+ *d = (*d & mask) | (decSymbol(addBits) << 8) | (decSymbol(baseline) << 32)
+}
+
+// decSymbolValue returns the transformed decSymbol for the given symbol.
+func decSymbolValue(symb uint8, t []baseOffset) (decSymbol, error) {
+ if int(symb) >= len(t) {
+ return 0, fmt.Errorf("rle symbol %d >= max %d", symb, len(t))
+ }
+ lu := t[symb]
+ return newDecSymbol(0, lu.addBits, 0, lu.baseLine), nil
+}
+
+// setRLE will set the decoder til RLE mode.
+func (s *fseDecoder) setRLE(symbol decSymbol) {
+ s.actualTableLog = 0
+ s.maxBits = symbol.addBits()
+ s.dt[0] = symbol
+}
+
+// transform will transform the decoder table into a table usable for
+// decoding without having to apply the transformation while decoding.
+// The state will contain the base value and the number of bits to read.
+func (s *fseDecoder) transform(t []baseOffset) error {
+ tableSize := uint16(1 << s.actualTableLog)
+ s.maxBits = 0
+ for i, v := range s.dt[:tableSize] {
+ add := v.addBits()
+ if int(add) >= len(t) {
+ return fmt.Errorf("invalid decoding table entry %d, symbol %d >= max (%d)", i, v.addBits(), len(t))
+ }
+ lu := t[add]
+ if lu.addBits > s.maxBits {
+ s.maxBits = lu.addBits
+ }
+ v.setExt(lu.addBits, lu.baseLine)
+ s.dt[i] = v
+ }
+ return nil
+}
+
+type fseState struct {
+ dt []decSymbol
+ state decSymbol
+}
+
+// Initialize and decodeAsync first state and symbol.
+func (s *fseState) init(br *bitReader, tableLog uint8, dt []decSymbol) {
+ s.dt = dt
+ br.fill()
+ s.state = dt[br.getBits(tableLog)]
+}
+
+// final returns the current state symbol without decoding the next.
+func (s decSymbol) final() (int, uint8) {
+ return s.baselineInt(), s.addBits()
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go
new file mode 100644
index 00000000000..b8c8607b5df
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go
@@ -0,0 +1,64 @@
+//go:build amd64 && !appengine && !noasm && gc
+
+package zstd
+
+import (
+ "fmt"
+)
+
+type buildDtableAsmContext struct {
+ // inputs
+ stateTable *uint16
+ norm *int16
+ dt *uint64
+
+ // outputs --- set by the procedure in the case of error;
+ // for interpretation please see the error handling part below
+ errParam1 uint64
+ errParam2 uint64
+}
+
+// buildDtable_asm is an x86 assembly implementation of fseDecoder.buildDtable.
+// Function returns non-zero exit code on error.
+//
+//go:noescape
+func buildDtable_asm(s *fseDecoder, ctx *buildDtableAsmContext) int
+
+// please keep in sync with _generate/gen_fse.go
+const (
+ errorCorruptedNormalizedCounter = 1
+ errorNewStateTooBig = 2
+ errorNewStateNoBits = 3
+)
+
+// buildDtable will build the decoding table.
+func (s *fseDecoder) buildDtable() error {
+ ctx := buildDtableAsmContext{
+ stateTable: &s.stateTable[0],
+ norm: &s.norm[0],
+ dt: (*uint64)(&s.dt[0]),
+ }
+ code := buildDtable_asm(s, &ctx)
+
+ if code != 0 {
+ switch code {
+ case errorCorruptedNormalizedCounter:
+ position := ctx.errParam1
+ return fmt.Errorf("corrupted input (position=%d, expected 0)", position)
+
+ case errorNewStateTooBig:
+ newState := decSymbol(ctx.errParam1)
+ size := ctx.errParam2
+ return fmt.Errorf("newState (%d) outside table size (%d)", newState, size)
+
+ case errorNewStateNoBits:
+ newState := decSymbol(ctx.errParam1)
+ oldState := decSymbol(ctx.errParam2)
+ return fmt.Errorf("newState (%d) == oldState (%d) and no bits", newState, oldState)
+
+ default:
+ return fmt.Errorf("buildDtable_asm returned unhandled nonzero code = %d", code)
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s
new file mode 100644
index 00000000000..bcde3986953
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s
@@ -0,0 +1,126 @@
+// Code generated by command: go run gen_fse.go -out ../fse_decoder_amd64.s -pkg=zstd. DO NOT EDIT.
+
+//go:build !appengine && !noasm && gc && !noasm
+
+// func buildDtable_asm(s *fseDecoder, ctx *buildDtableAsmContext) int
+TEXT ·buildDtable_asm(SB), $0-24
+ MOVQ ctx+8(FP), CX
+ MOVQ s+0(FP), DI
+
+ // Load values
+ MOVBQZX 4098(DI), DX
+ XORQ AX, AX
+ BTSQ DX, AX
+ MOVQ (CX), BX
+ MOVQ 16(CX), SI
+ LEAQ -1(AX), R8
+ MOVQ 8(CX), CX
+ MOVWQZX 4096(DI), DI
+
+ // End load values
+ // Init, lay down lowprob symbols
+ XORQ R9, R9
+ JMP init_main_loop_condition
+
+init_main_loop:
+ MOVWQSX (CX)(R9*2), R10
+ CMPW R10, $-1
+ JNE do_not_update_high_threshold
+ MOVB R9, 1(SI)(R8*8)
+ DECQ R8
+ MOVQ $0x0000000000000001, R10
+
+do_not_update_high_threshold:
+ MOVW R10, (BX)(R9*2)
+ INCQ R9
+
+init_main_loop_condition:
+ CMPQ R9, DI
+ JL init_main_loop
+
+ // Spread symbols
+ // Calculate table step
+ MOVQ AX, R9
+ SHRQ $0x01, R9
+ MOVQ AX, R10
+ SHRQ $0x03, R10
+ LEAQ 3(R9)(R10*1), R9
+
+ // Fill add bits values
+ LEAQ -1(AX), R10
+ XORQ R11, R11
+ XORQ R12, R12
+ JMP spread_main_loop_condition
+
+spread_main_loop:
+ XORQ R13, R13
+ MOVWQSX (CX)(R12*2), R14
+ JMP spread_inner_loop_condition
+
+spread_inner_loop:
+ MOVB R12, 1(SI)(R11*8)
+
+adjust_position:
+ ADDQ R9, R11
+ ANDQ R10, R11
+ CMPQ R11, R8
+ JG adjust_position
+ INCQ R13
+
+spread_inner_loop_condition:
+ CMPQ R13, R14
+ JL spread_inner_loop
+ INCQ R12
+
+spread_main_loop_condition:
+ CMPQ R12, DI
+ JL spread_main_loop
+ TESTQ R11, R11
+ JZ spread_check_ok
+ MOVQ ctx+8(FP), AX
+ MOVQ R11, 24(AX)
+ MOVQ $+1, ret+16(FP)
+ RET
+
+spread_check_ok:
+ // Build Decoding table
+ XORQ DI, DI
+
+build_table_main_table:
+ MOVBQZX 1(SI)(DI*8), CX
+ MOVWQZX (BX)(CX*2), R8
+ LEAQ 1(R8), R9
+ MOVW R9, (BX)(CX*2)
+ MOVQ R8, R9
+ BSRQ R9, R9
+ MOVQ DX, CX
+ SUBQ R9, CX
+ SHLQ CL, R8
+ SUBQ AX, R8
+ MOVB CL, (SI)(DI*8)
+ MOVW R8, 2(SI)(DI*8)
+ CMPQ R8, AX
+ JLE build_table_check1_ok
+ MOVQ ctx+8(FP), CX
+ MOVQ R8, 24(CX)
+ MOVQ AX, 32(CX)
+ MOVQ $+2, ret+16(FP)
+ RET
+
+build_table_check1_ok:
+ TESTB CL, CL
+ JNZ build_table_check2_ok
+ CMPW R8, DI
+ JNE build_table_check2_ok
+ MOVQ ctx+8(FP), AX
+ MOVQ R8, 24(AX)
+ MOVQ DI, 32(AX)
+ MOVQ $+3, ret+16(FP)
+ RET
+
+build_table_check2_ok:
+ INCQ DI
+ CMPQ DI, AX
+ JL build_table_main_table
+ MOVQ $+0, ret+16(FP)
+ RET
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go
new file mode 100644
index 00000000000..2138f8091a9
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go
@@ -0,0 +1,72 @@
+//go:build !amd64 || appengine || !gc || noasm
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+)
+
+// buildDtable will build the decoding table.
+func (s *fseDecoder) buildDtable() error {
+ tableSize := uint32(1 << s.actualTableLog)
+ highThreshold := tableSize - 1
+ symbolNext := s.stateTable[:256]
+
+ // Init, lay down lowprob symbols
+ {
+ for i, v := range s.norm[:s.symbolLen] {
+ if v == -1 {
+ s.dt[highThreshold].setAddBits(uint8(i))
+ highThreshold--
+ v = 1
+ }
+ symbolNext[i] = uint16(v)
+ }
+ }
+
+ // Spread symbols
+ {
+ tableMask := tableSize - 1
+ step := tableStep(tableSize)
+ position := uint32(0)
+ for ss, v := range s.norm[:s.symbolLen] {
+ for i := 0; i < int(v); i++ {
+ s.dt[position].setAddBits(uint8(ss))
+ for {
+ // lowprob area
+ position = (position + step) & tableMask
+ if position <= highThreshold {
+ break
+ }
+ }
+ }
+ }
+ if position != 0 {
+ // position must reach all cells once, otherwise normalizedCounter is incorrect
+ return errors.New("corrupted input (position != 0)")
+ }
+ }
+
+ // Build Decoding table
+ {
+ tableSize := uint16(1 << s.actualTableLog)
+ for u, v := range s.dt[:tableSize] {
+ symbol := v.addBits()
+ nextState := symbolNext[symbol]
+ symbolNext[symbol] = nextState + 1
+ nBits := s.actualTableLog - byte(highBits(uint32(nextState)))
+ s.dt[u&maxTableMask].setNBits(nBits)
+ newState := (nextState << nBits) - tableSize
+ if newState > tableSize {
+ return fmt.Errorf("newState (%d) outside table size (%d)", newState, tableSize)
+ }
+ if newState == uint16(u) && nBits == 0 {
+ // Seems weird that this is possible with nbits > 0.
+ return fmt.Errorf("newState (%d) == oldState (%d) and no bits", newState, u)
+ }
+ s.dt[u&maxTableMask].setNewState(newState)
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_encoder.go b/vendor/github.com/klauspost/compress/zstd/fse_encoder.go
new file mode 100644
index 00000000000..3a0f4e7fbe6
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/fse_encoder.go
@@ -0,0 +1,701 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "math"
+)
+
+const (
+ // For encoding we only support up to
+ maxEncTableLog = 8
+ maxEncTablesize = 1 << maxTableLog
+ maxEncTableMask = (1 << maxTableLog) - 1
+ minEncTablelog = 5
+ maxEncSymbolValue = maxMatchLengthSymbol
+)
+
+// Scratch provides temporary storage for compression and decompression.
+type fseEncoder struct {
+ symbolLen uint16 // Length of active part of the symbol table.
+ actualTableLog uint8 // Selected tablelog.
+ ct cTable // Compression tables.
+ maxCount int // count of the most probable symbol
+ zeroBits bool // no bits has prob > 50%.
+ clearCount bool // clear count
+ useRLE bool // This encoder is for RLE
+ preDefined bool // This encoder is predefined.
+ reUsed bool // Set to know when the encoder has been reused.
+ rleVal uint8 // RLE Symbol
+ maxBits uint8 // Maximum output bits after transform.
+
+ // TODO: Technically zstd should be fine with 64 bytes.
+ count [256]uint32
+ norm [256]int16
+}
+
+// cTable contains tables used for compression.
+type cTable struct {
+ tableSymbol []byte
+ stateTable []uint16
+ symbolTT []symbolTransform
+}
+
+// symbolTransform contains the state transform for a symbol.
+type symbolTransform struct {
+ deltaNbBits uint32
+ deltaFindState int16
+ outBits uint8
+}
+
+// String prints values as a human readable string.
+func (s symbolTransform) String() string {
+ return fmt.Sprintf("{deltabits: %08x, findstate:%d outbits:%d}", s.deltaNbBits, s.deltaFindState, s.outBits)
+}
+
+// Histogram allows to populate the histogram and skip that step in the compression,
+// It otherwise allows to inspect the histogram when compression is done.
+// To indicate that you have populated the histogram call HistogramFinished
+// with the value of the highest populated symbol, as well as the number of entries
+// in the most populated entry. These are accepted at face value.
+func (s *fseEncoder) Histogram() *[256]uint32 {
+ return &s.count
+}
+
+// HistogramFinished can be called to indicate that the histogram has been populated.
+// maxSymbol is the index of the highest set symbol of the next data segment.
+// maxCount is the number of entries in the most populated entry.
+// These are accepted at face value.
+func (s *fseEncoder) HistogramFinished(maxSymbol uint8, maxCount int) {
+ s.maxCount = maxCount
+ s.symbolLen = uint16(maxSymbol) + 1
+ s.clearCount = maxCount != 0
+}
+
+// allocCtable will allocate tables needed for compression.
+// If existing tables a re big enough, they are simply re-used.
+func (s *fseEncoder) allocCtable() {
+ tableSize := 1 << s.actualTableLog
+ // get tableSymbol that is big enough.
+ if cap(s.ct.tableSymbol) < tableSize {
+ s.ct.tableSymbol = make([]byte, tableSize)
+ }
+ s.ct.tableSymbol = s.ct.tableSymbol[:tableSize]
+
+ ctSize := tableSize
+ if cap(s.ct.stateTable) < ctSize {
+ s.ct.stateTable = make([]uint16, ctSize)
+ }
+ s.ct.stateTable = s.ct.stateTable[:ctSize]
+
+ if cap(s.ct.symbolTT) < 256 {
+ s.ct.symbolTT = make([]symbolTransform, 256)
+ }
+ s.ct.symbolTT = s.ct.symbolTT[:256]
+}
+
+// buildCTable will populate the compression table so it is ready to be used.
+func (s *fseEncoder) buildCTable() error {
+ tableSize := uint32(1 << s.actualTableLog)
+ highThreshold := tableSize - 1
+ var cumul [256]int16
+
+ s.allocCtable()
+ tableSymbol := s.ct.tableSymbol[:tableSize]
+ // symbol start positions
+ {
+ cumul[0] = 0
+ for ui, v := range s.norm[:s.symbolLen-1] {
+ u := byte(ui) // one less than reference
+ if v == -1 {
+ // Low proba symbol
+ cumul[u+1] = cumul[u] + 1
+ tableSymbol[highThreshold] = u
+ highThreshold--
+ } else {
+ cumul[u+1] = cumul[u] + v
+ }
+ }
+ // Encode last symbol separately to avoid overflowing u
+ u := int(s.symbolLen - 1)
+ v := s.norm[s.symbolLen-1]
+ if v == -1 {
+ // Low proba symbol
+ cumul[u+1] = cumul[u] + 1
+ tableSymbol[highThreshold] = byte(u)
+ highThreshold--
+ } else {
+ cumul[u+1] = cumul[u] + v
+ }
+ if uint32(cumul[s.symbolLen]) != tableSize {
+ return fmt.Errorf("internal error: expected cumul[s.symbolLen] (%d) == tableSize (%d)", cumul[s.symbolLen], tableSize)
+ }
+ cumul[s.symbolLen] = int16(tableSize) + 1
+ }
+ // Spread symbols
+ s.zeroBits = false
+ {
+ step := tableStep(tableSize)
+ tableMask := tableSize - 1
+ var position uint32
+ // if any symbol > largeLimit, we may have 0 bits output.
+ largeLimit := int16(1 << (s.actualTableLog - 1))
+ for ui, v := range s.norm[:s.symbolLen] {
+ symbol := byte(ui)
+ if v > largeLimit {
+ s.zeroBits = true
+ }
+ for range v {
+ tableSymbol[position] = symbol
+ position = (position + step) & tableMask
+ for position > highThreshold {
+ position = (position + step) & tableMask
+ } /* Low proba area */
+ }
+ }
+
+ // Check if we have gone through all positions
+ if position != 0 {
+ return errors.New("position!=0")
+ }
+ }
+
+ // Build table
+ table := s.ct.stateTable
+ {
+ tsi := int(tableSize)
+ for u, v := range tableSymbol {
+ // TableU16 : sorted by symbol order; gives next state value
+ table[cumul[v]] = uint16(tsi + u)
+ cumul[v]++
+ }
+ }
+
+ // Build Symbol Transformation Table
+ {
+ total := int16(0)
+ symbolTT := s.ct.symbolTT[:s.symbolLen]
+ tableLog := s.actualTableLog
+ tl := (uint32(tableLog) << 16) - (1 << tableLog)
+ for i, v := range s.norm[:s.symbolLen] {
+ switch v {
+ case 0:
+ case -1, 1:
+ symbolTT[i].deltaNbBits = tl
+ symbolTT[i].deltaFindState = total - 1
+ total++
+ default:
+ maxBitsOut := uint32(tableLog) - highBit(uint32(v-1))
+ minStatePlus := uint32(v) << maxBitsOut
+ symbolTT[i].deltaNbBits = (maxBitsOut << 16) - minStatePlus
+ symbolTT[i].deltaFindState = total - v
+ total += v
+ }
+ }
+ if total != int16(tableSize) {
+ return fmt.Errorf("total mismatch %d (got) != %d (want)", total, tableSize)
+ }
+ }
+ return nil
+}
+
+var rtbTable = [...]uint32{0, 473195, 504333, 520860, 550000, 700000, 750000, 830000}
+
+func (s *fseEncoder) setRLE(val byte) {
+ s.allocCtable()
+ s.actualTableLog = 0
+ s.ct.stateTable = s.ct.stateTable[:1]
+ s.ct.symbolTT[val] = symbolTransform{
+ deltaFindState: 0,
+ deltaNbBits: 0,
+ }
+ if debugEncoder {
+ println("setRLE: val", val, "symbolTT", s.ct.symbolTT[val])
+ }
+ s.rleVal = val
+ s.useRLE = true
+}
+
+// setBits will set output bits for the transform.
+// if nil is provided, the number of bits is equal to the index.
+func (s *fseEncoder) setBits(transform []byte) {
+ if s.reUsed || s.preDefined {
+ return
+ }
+ if s.useRLE {
+ if transform == nil {
+ s.ct.symbolTT[s.rleVal].outBits = s.rleVal
+ s.maxBits = s.rleVal
+ return
+ }
+ s.maxBits = transform[s.rleVal]
+ s.ct.symbolTT[s.rleVal].outBits = s.maxBits
+ return
+ }
+ if transform == nil {
+ for i := range s.ct.symbolTT[:s.symbolLen] {
+ s.ct.symbolTT[i].outBits = uint8(i)
+ }
+ s.maxBits = uint8(s.symbolLen - 1)
+ return
+ }
+ s.maxBits = 0
+ for i, v := range transform[:s.symbolLen] {
+ s.ct.symbolTT[i].outBits = v
+ if v > s.maxBits {
+ // We could assume bits always going up, but we play safe.
+ s.maxBits = v
+ }
+ }
+}
+
+// normalizeCount will normalize the count of the symbols so
+// the total is equal to the table size.
+// If successful, compression tables will also be made ready.
+func (s *fseEncoder) normalizeCount(length int) error {
+ if s.reUsed {
+ return nil
+ }
+ s.optimalTableLog(length)
+ var (
+ tableLog = s.actualTableLog
+ scale = 62 - uint64(tableLog)
+ step = (1 << 62) / uint64(length)
+ vStep = uint64(1) << (scale - 20)
+ stillToDistribute = int16(1 << tableLog)
+ largest int
+ largestP int16
+ lowThreshold = (uint32)(length >> tableLog)
+ )
+ if s.maxCount == length {
+ s.useRLE = true
+ return nil
+ }
+ s.useRLE = false
+ for i, cnt := range s.count[:s.symbolLen] {
+ // already handled
+ // if (count[s] == s.length) return 0; /* rle special case */
+
+ if cnt == 0 {
+ s.norm[i] = 0
+ continue
+ }
+ if cnt <= lowThreshold {
+ s.norm[i] = -1
+ stillToDistribute--
+ } else {
+ proba := (int16)((uint64(cnt) * step) >> scale)
+ if proba < 8 {
+ restToBeat := vStep * uint64(rtbTable[proba])
+ v := uint64(cnt)*step - (uint64(proba) << scale)
+ if v > restToBeat {
+ proba++
+ }
+ }
+ if proba > largestP {
+ largestP = proba
+ largest = i
+ }
+ s.norm[i] = proba
+ stillToDistribute -= proba
+ }
+ }
+
+ if -stillToDistribute >= (s.norm[largest] >> 1) {
+ // corner case, need another normalization method
+ err := s.normalizeCount2(length)
+ if err != nil {
+ return err
+ }
+ if debugAsserts {
+ err = s.validateNorm()
+ if err != nil {
+ return err
+ }
+ }
+ return s.buildCTable()
+ }
+ s.norm[largest] += stillToDistribute
+ if debugAsserts {
+ err := s.validateNorm()
+ if err != nil {
+ return err
+ }
+ }
+ return s.buildCTable()
+}
+
+// Secondary normalization method.
+// To be used when primary method fails.
+func (s *fseEncoder) normalizeCount2(length int) error {
+ const notYetAssigned = -2
+ var (
+ distributed uint32
+ total = uint32(length)
+ tableLog = s.actualTableLog
+ lowThreshold = total >> tableLog
+ lowOne = (total * 3) >> (tableLog + 1)
+ )
+ for i, cnt := range s.count[:s.symbolLen] {
+ if cnt == 0 {
+ s.norm[i] = 0
+ continue
+ }
+ if cnt <= lowThreshold {
+ s.norm[i] = -1
+ distributed++
+ total -= cnt
+ continue
+ }
+ if cnt <= lowOne {
+ s.norm[i] = 1
+ distributed++
+ total -= cnt
+ continue
+ }
+ s.norm[i] = notYetAssigned
+ }
+ toDistribute := (1 << tableLog) - distributed
+
+ if (total / toDistribute) > lowOne {
+ // risk of rounding to zero
+ lowOne = (total * 3) / (toDistribute * 2)
+ for i, cnt := range s.count[:s.symbolLen] {
+ if (s.norm[i] == notYetAssigned) && (cnt <= lowOne) {
+ s.norm[i] = 1
+ distributed++
+ total -= cnt
+ continue
+ }
+ }
+ toDistribute = (1 << tableLog) - distributed
+ }
+ if distributed == uint32(s.symbolLen)+1 {
+ // all values are pretty poor;
+ // probably incompressible data (should have already been detected);
+ // find max, then give all remaining points to max
+ var maxV int
+ var maxC uint32
+ for i, cnt := range s.count[:s.symbolLen] {
+ if cnt > maxC {
+ maxV = i
+ maxC = cnt
+ }
+ }
+ s.norm[maxV] += int16(toDistribute)
+ return nil
+ }
+
+ if total == 0 {
+ // all of the symbols were low enough for the lowOne or lowThreshold
+ for i := uint32(0); toDistribute > 0; i = (i + 1) % (uint32(s.symbolLen)) {
+ if s.norm[i] > 0 {
+ toDistribute--
+ s.norm[i]++
+ }
+ }
+ return nil
+ }
+
+ var (
+ vStepLog = 62 - uint64(tableLog)
+ mid = uint64((1 << (vStepLog - 1)) - 1)
+ rStep = (((1 << vStepLog) * uint64(toDistribute)) + mid) / uint64(total) // scale on remaining
+ tmpTotal = mid
+ )
+ for i, cnt := range s.count[:s.symbolLen] {
+ if s.norm[i] == notYetAssigned {
+ var (
+ end = tmpTotal + uint64(cnt)*rStep
+ sStart = uint32(tmpTotal >> vStepLog)
+ sEnd = uint32(end >> vStepLog)
+ weight = sEnd - sStart
+ )
+ if weight < 1 {
+ return errors.New("weight < 1")
+ }
+ s.norm[i] = int16(weight)
+ tmpTotal = end
+ }
+ }
+ return nil
+}
+
+// optimalTableLog calculates and sets the optimal tableLog in s.actualTableLog
+func (s *fseEncoder) optimalTableLog(length int) {
+ tableLog := uint8(maxEncTableLog)
+ minBitsSrc := highBit(uint32(length)) + 1
+ minBitsSymbols := highBit(uint32(s.symbolLen-1)) + 2
+ minBits := uint8(minBitsSymbols)
+ if minBitsSrc < minBitsSymbols {
+ minBits = uint8(minBitsSrc)
+ }
+
+ maxBitsSrc := uint8(highBit(uint32(length-1))) - 2
+ if maxBitsSrc < tableLog {
+ // Accuracy can be reduced
+ tableLog = maxBitsSrc
+ }
+ if minBits > tableLog {
+ tableLog = minBits
+ }
+ // Need a minimum to safely represent all symbol values
+ if tableLog < minEncTablelog {
+ tableLog = minEncTablelog
+ }
+ if tableLog > maxEncTableLog {
+ tableLog = maxEncTableLog
+ }
+ s.actualTableLog = tableLog
+}
+
+// validateNorm validates the normalized histogram table.
+func (s *fseEncoder) validateNorm() (err error) {
+ var total int
+ for _, v := range s.norm[:s.symbolLen] {
+ if v >= 0 {
+ total += int(v)
+ } else {
+ total -= int(v)
+ }
+ }
+ defer func() {
+ if err == nil {
+ return
+ }
+ fmt.Printf("selected TableLog: %d, Symbol length: %d\n", s.actualTableLog, s.symbolLen)
+ for i, v := range s.norm[:s.symbolLen] {
+ fmt.Printf("%3d: %5d -> %4d \n", i, s.count[i], v)
+ }
+ }()
+ if total != (1 << s.actualTableLog) {
+ return fmt.Errorf("warning: Total == %d != %d", total, 1<