diff --git a/.github/README.md b/.github/README.md
index 64bc6e37f1..15e55489b6 100644
--- a/.github/README.md
+++ b/.github/README.md
@@ -665,3 +665,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_ckb.md b/.github/README_ckb.md
index 4b12e914e4..22cf3ecac6 100644
--- a/.github/README_ckb.md
+++ b/.github/README_ckb.md
@@ -665,3 +665,4 @@ func main() {
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_de.md b/.github/README_de.md
index 9f3dd5587e..aa9c124145 100644
--- a/.github/README_de.md
+++ b/.github/README_de.md
@@ -635,3 +635,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_es.md b/.github/README_es.md
index c50e524b0c..4a986cd360 100644
--- a/.github/README_es.md
+++ b/.github/README_es.md
@@ -635,3 +635,5 @@ Copyright (c) 2019-presente [Fenny](https://github.com/fenny) y [contribuyentes]
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
+
diff --git a/.github/README_fa.md b/.github/README_fa.md
index ad2ddbbadd..d7ffeafdd9 100644
--- a/.github/README_fa.md
+++ b/.github/README_fa.md
@@ -794,3 +794,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_fr.md b/.github/README_fr.md
index 0dcc691089..cc4973cb18 100644
--- a/.github/README_fr.md
+++ b/.github/README_fr.md
@@ -637,3 +637,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_he.md b/.github/README_he.md
index 6708d6fcae..2473a1bd01 100644
--- a/.github/README_he.md
+++ b/.github/README_he.md
@@ -810,4 +810,5 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_id.md b/.github/README_id.md
index e83ceee61b..e60f8f2549 100644
--- a/.github/README_id.md
+++ b/.github/README_id.md
@@ -638,3 +638,5 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
+
diff --git a/.github/README_it.md b/.github/README_it.md
index a752de5455..9bcf06b104 100644
--- a/.github/README_it.md
+++ b/.github/README_it.md
@@ -661,3 +661,4 @@ Copyright (c) 2019-ora [Fenny](https://github.com/fenny) e [Contributors](https:
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_ja.md b/.github/README_ja.md
index 68d4bcd4bc..d936c9bbf3 100644
--- a/.github/README_ja.md
+++ b/.github/README_ja.md
@@ -641,3 +641,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_ko.md b/.github/README_ko.md
index ddc6c07a8c..4c57ff0f25 100644
--- a/.github/README_ko.md
+++ b/.github/README_ko.md
@@ -641,3 +641,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_nl.md b/.github/README_nl.md
index a52f32d916..c52a1d25ed 100644
--- a/.github/README_nl.md
+++ b/.github/README_nl.md
@@ -641,3 +641,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_pt.md b/.github/README_pt.md
index 3e818406a2..9cb4aa7ad0 100644
--- a/.github/README_pt.md
+++ b/.github/README_pt.md
@@ -637,3 +637,4 @@ O logo oficial foi criado por [Vic Shóstak](https://github.com/koddr) e distrib
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_ru.md b/.github/README_ru.md
index eee845895c..022ca6767e 100644
--- a/.github/README_ru.md
+++ b/.github/README_ru.md
@@ -644,3 +644,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_sa.md b/.github/README_sa.md
index 4518eea382..68772b1d5c 100644
--- a/.github/README_sa.md
+++ b/.github/README_sa.md
@@ -702,3 +702,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_tr.md b/.github/README_tr.md
index ba10a4cc9c..fc59090e08 100644
--- a/.github/README_tr.md
+++ b/.github/README_tr.md
@@ -635,3 +635,4 @@ Telif (c) 2019-günümüz [Fenny](https://github.com/fenny) ve [Contributors](ht
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_zh-CN.md b/.github/README_zh-CN.md
index d54c56149c..3c9407633c 100644
--- a/.github/README_zh-CN.md
+++ b/.github/README_zh-CN.md
@@ -637,3 +637,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/README_zh-TW.md b/.github/README_zh-TW.md
index 5d8c8ba93c..1315f3cfa7 100644
--- a/.github/README_zh-TW.md
+++ b/.github/README_zh-TW.md
@@ -635,3 +635,4 @@ Fiber 是一個以贊助維生的開源專案,像是: 網域、gitbook、netli
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
+- [dictpool](https://github.com/savsgio/dictpool)
diff --git a/.github/testdata/template.html b/.github/testdata/template.html
deleted file mode 100644
index 131044d79b..0000000000
--- a/.github/testdata/template.html
+++ /dev/null
@@ -1 +0,0 @@
-
{{.Title}}
\ No newline at end of file
diff --git a/.github/testdata/template.tmpl b/.github/testdata/template.tmpl
new file mode 100644
index 0000000000..ab6e56044d
--- /dev/null
+++ b/.github/testdata/template.tmpl
@@ -0,0 +1 @@
+{{.Title}} {{.Summary}}
\ No newline at end of file
diff --git a/app_test.go b/app_test.go
index a9ec4d01da..d33994e861 100644
--- a/app_test.go
+++ b/app_test.go
@@ -779,7 +779,7 @@ func Test_App_Static_Prefix(t *testing.T) {
app.Static("/prefix", "./.github/testdata")
- req = httptest.NewRequest(MethodGet, "/prefix/template.html", nil)
+ req = httptest.NewRequest(MethodGet, "/prefix/index.html", nil)
resp, err = app.Test(req)
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
@@ -1146,7 +1146,7 @@ func Test_App_ListenTLS_Prefork(t *testing.T) {
app := New(Config{DisableStartupMessage: true, Prefork: true})
// invalid key file content
- utils.AssertEqual(t, false, app.ListenTLS(":0", "./.github/testdata/ssl.pem", "./.github/testdata/template.html") == nil)
+ utils.AssertEqual(t, false, app.ListenTLS(":0", "./.github/testdata/ssl.pem", "./.github/testdata/template.tmpl") == nil)
utils.AssertEqual(t, nil, app.ListenTLS(":99999", "./.github/testdata/ssl.pem", "./.github/testdata/ssl.key"))
}
diff --git a/ctx.go b/ctx.go
index efb9b312f1..935056304b 100644
--- a/ctx.go
+++ b/ctx.go
@@ -24,6 +24,7 @@ import (
"time"
"github.com/gofiber/fiber/v2/internal/bytebufferpool"
+ "github.com/gofiber/fiber/v2/internal/dictpool"
"github.com/gofiber/fiber/v2/internal/go-json"
"github.com/gofiber/fiber/v2/internal/schema"
"github.com/gofiber/fiber/v2/utils"
@@ -62,6 +63,7 @@ type Ctx struct {
values [maxParams]string // Route parameter values
fasthttp *fasthttp.RequestCtx // Reference to *fasthttp.RequestCtx
matched bool // Non use route matched
+ viewBindMap *dictpool.Dict // Default view map to bind template engine
}
// Range data for c.Range
@@ -137,6 +139,9 @@ func (app *App) ReleaseCtx(c *Ctx) {
// Reset values
c.route = nil
c.fasthttp = nil
+ if c.viewBindMap != nil {
+ dictpool.ReleaseDict(c.viewBindMap)
+ }
app.pool.Put(c)
}
@@ -1060,6 +1065,20 @@ func (c *Ctx) Redirect(location string, status ...int) error {
return nil
}
+// Add vars to default view var map binding to template engine.
+// Variables are read by the Render method and may be overwritten.
+func (c *Ctx) Bind(vars Map) error {
+ // init viewBindMap - lazy map
+ if c.viewBindMap == nil {
+ c.viewBindMap = dictpool.AcquireDict()
+ }
+ for k, v := range vars {
+ c.viewBindMap.Set(k, v)
+ }
+
+ return nil
+}
+
// get URL location from route using parameters
func (c *Ctx) getLocationFromRoute(route Route, params Map) (string, error) {
buf := bytebufferpool.Get()
@@ -1113,25 +1132,8 @@ func (c *Ctx) Render(name string, bind interface{}, layouts ...string) error {
buf := bytebufferpool.Get()
defer bytebufferpool.Put(buf)
- // Check if the PassLocalsToViews option is enabled (By default it is disabled)
- if c.app.config.PassLocalsToViews {
- // Safely cast the bind interface to a map
- bindMap, ok := bind.(Map)
- // Check if the bind is a map
- if ok {
- // Loop through each local and set it in the map
- c.fasthttp.VisitUserValues(func(key []byte, val interface{}) {
- // check if bindMap doesn't contain the key
- if _, ok := bindMap[string(key)]; !ok {
- // Set the key and value in the bindMap
- bindMap[string(key)] = val
- }
- })
- // set the original bind to the map
- bind = bindMap
- }
-
- }
+ // Pass-locals-to-views & bind
+ c.renderExtensions(bind)
rendered := false
for prefix, app := range c.app.appList {
@@ -1179,6 +1181,29 @@ func (c *Ctx) Render(name string, bind interface{}, layouts ...string) error {
return err
}
+func (c *Ctx) renderExtensions(bind interface{}) {
+ if bindMap, ok := bind.(Map); ok {
+ // Bind view map
+ if c.viewBindMap != nil {
+ for _, v := range c.viewBindMap.D {
+ bindMap[v.Key] = v.Value
+ }
+ }
+
+ // Check if the PassLocalsToViews option is enabled (by default it is disabled)
+ if c.app.config.PassLocalsToViews {
+ // Loop through each local and set it in the map
+ c.fasthttp.VisitUserValues(func(key []byte, val interface{}) {
+ // check if bindMap doesn't contain the key
+ if _, ok := bindMap[utils.UnsafeString(key)]; !ok {
+ // Set the key and value in the bindMap
+ bindMap[utils.UnsafeString(key)] = val
+ }
+ })
+ }
+ }
+}
+
// Route returns the matched Route struct.
func (c *Ctx) Route() *Route {
if c.route == nil {
diff --git a/ctx_test.go b/ctx_test.go
index 333bdb6b64..1c082f01bd 100644
--- a/ctx_test.go
+++ b/ctx_test.go
@@ -2140,7 +2140,7 @@ func Test_Ctx_Render(t *testing.T) {
app := New()
c := app.AcquireCtx(&fasthttp.RequestCtx{})
defer app.ReleaseCtx(c)
- err := c.Render("./.github/testdata/template.html", Map{
+ err := c.Render("./.github/testdata/index.tmpl", Map{
"Title": "Hello, World!",
})
@@ -2219,7 +2219,7 @@ func Test_Ctx_RenderWithoutLocals(t *testing.T) {
c.Locals("Title", "Hello, World!")
defer app.ReleaseCtx(c)
- err := c.Render("./.github/testdata/template.html", Map{})
+ err := c.Render("./.github/testdata/index.tmpl", Map{})
buf := bytebufferpool.Get()
_, _ = buf.WriteString("overwrite")
@@ -2238,7 +2238,7 @@ func Test_Ctx_RenderWithLocals(t *testing.T) {
c.Locals("Title", "Hello, World!")
defer app.ReleaseCtx(c)
- err := c.Render("./.github/testdata/template.html", Map{})
+ err := c.Render("./.github/testdata/index.tmpl", Map{})
buf := bytebufferpool.Get()
_, _ = buf.WriteString("overwrite")
@@ -2248,27 +2248,149 @@ func Test_Ctx_RenderWithLocals(t *testing.T) {
utils.AssertEqual(t, "Hello, World!
", string(c.Response().Body()))
}
+
+func Test_Ctx_RenderWithBind(t *testing.T) {
+ t.Parallel()
+
+ app := New()
+ c := app.AcquireCtx(&fasthttp.RequestCtx{})
+
+ c.Bind(Map{
+ "Title": "Hello, World!",
+ })
+ defer app.ReleaseCtx(c)
+ err := c.Render("./.github/testdata/index.tmpl", Map{})
+
+ buf := bytebufferpool.Get()
+ _, _ = buf.WriteString("overwrite")
+ defer bytebufferpool.Put(buf)
+
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, "Hello, World!
", string(c.Response().Body()))
+
+}
+
+func Test_Ctx_RenderWithBindLocals(t *testing.T) {
+ t.Parallel()
+
+ app := New(Config{
+ PassLocalsToViews: true,
+ })
+
+ c := app.AcquireCtx(&fasthttp.RequestCtx{})
+
+ c.Bind(Map{
+ "Title": "Hello, World!",
+ })
+
+ c.Locals("Summary", "Test")
+
+ defer app.ReleaseCtx(c)
+ err := c.Render("./.github/testdata/template.tmpl", Map{})
+
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, "Hello, World! Test
", string(c.Response().Body()))
+
+}
+
func Test_Ctx_RenderWithLocalsAndBinding(t *testing.T) {
t.Parallel()
+ engine := &testTemplateEngine{}
+ err := engine.Load()
app := New(Config{
PassLocalsToViews: true,
+ Views: engine,
})
c := app.AcquireCtx(&fasthttp.RequestCtx{})
c.Locals("Title", "This is a test.")
defer app.ReleaseCtx(c)
- err := c.Render("./.github/testdata/template.html", Map{
+ err = c.Render("index.tmpl", Map{
"Title": "Hello, World!",
})
- buf := bytebufferpool.Get()
- _, _ = buf.WriteString("overwrite")
- defer bytebufferpool.Put(buf)
-
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "Hello, World!
", string(c.Response().Body()))
}
+func Benchmark_Ctx_RenderWithLocalsAndBinding(b *testing.B) {
+ engine := &testTemplateEngine{}
+ err := engine.Load()
+ utils.AssertEqual(b, nil, err)
+ app := New(Config{
+ PassLocalsToViews: true,
+ Views: engine,
+ })
+ c := app.AcquireCtx(&fasthttp.RequestCtx{})
+
+ c.Bind(Map{
+ "Title": "Hello, World!",
+ })
+ c.Locals("Summary", "Test")
+
+ defer app.ReleaseCtx(c)
+
+ b.ReportAllocs()
+ b.ResetTimer()
+
+ for n := 0; n < b.N; n++ {
+ err = c.Render("template.tmpl", Map{})
+ }
+
+ utils.AssertEqual(b, nil, err)
+ utils.AssertEqual(b, "Hello, World! Test
", string(c.Response().Body()))
+}
+
+func Benchmark_Ctx_RenderLocals(b *testing.B) {
+ engine := &testTemplateEngine{}
+ err := engine.Load()
+ utils.AssertEqual(b, nil, err)
+ app := New(Config{
+ PassLocalsToViews: true,
+ })
+ app.config.Views = engine
+ c := app.AcquireCtx(&fasthttp.RequestCtx{})
+
+ c.Locals("Title", "Hello, World!")
+
+ defer app.ReleaseCtx(c)
+
+ b.ReportAllocs()
+ b.ResetTimer()
+
+ for n := 0; n < b.N; n++ {
+ err = c.Render("index.tmpl", Map{})
+ }
+
+ utils.AssertEqual(b, nil, err)
+ utils.AssertEqual(b, "Hello, World!
", string(c.Response().Body()))
+}
+
+func Benchmark_Ctx_RenderBind(b *testing.B) {
+ engine := &testTemplateEngine{}
+ err := engine.Load()
+ utils.AssertEqual(b, nil, err)
+ app := New()
+ app.config.Views = engine
+ c := app.AcquireCtx(&fasthttp.RequestCtx{})
+
+ c.Bind(Map{
+ "Title": "Hello, World!",
+ })
+
+ defer app.ReleaseCtx(c)
+
+ b.ReportAllocs()
+ b.ResetTimer()
+
+ for n := 0; n < b.N; n++ {
+ err = c.Render("index.tmpl", Map{})
+ }
+
+ utils.AssertEqual(b, nil, err)
+ utils.AssertEqual(b, "Hello, World!
", string(c.Response().Body()))
+}
+
// go test -run Test_Ctx_RestartRouting
func Test_Ctx_RestartRouting(t *testing.T) {
app := New()
diff --git a/internal/dictpool/LICENSE b/internal/dictpool/LICENSE
new file mode 100644
index 0000000000..2b440abc7b
--- /dev/null
+++ b/internal/dictpool/LICENSE
@@ -0,0 +1,201 @@
+ 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 2020-present Sergio Andres Virviescas Santana
+
+ 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/internal/dictpool/dict.go b/internal/dictpool/dict.go
new file mode 100644
index 0000000000..39b740d2f3
--- /dev/null
+++ b/internal/dictpool/dict.go
@@ -0,0 +1,164 @@
+package dictpool
+
+import (
+ "sort"
+
+ "github.com/gofiber/fiber/v2/utils"
+)
+
+func (d *Dict) allocKV() *KV {
+ n := len(d.D)
+
+ if cap(d.D) > n {
+ d.D = d.D[:n+1]
+ } else {
+ d.D = append(d.D, KV{})
+ }
+
+ return &d.D[n]
+}
+
+func (d *Dict) append(key string, value interface{}) {
+ kv := d.allocKV()
+ kv.Key = key
+ kv.Value = value
+}
+
+func (d *Dict) indexOf(key string) int {
+ n := len(d.D)
+
+ if d.BinarySearch {
+ idx := sort.Search(n, func(i int) bool {
+ return key <= d.D[i].Key
+ })
+
+ if idx < n && d.D[idx].Key == key {
+ return idx
+ }
+ } else {
+ for i := 0; i < n; i++ {
+ if d.D[i].Key == key {
+ return i
+ }
+ }
+ }
+
+ return -1
+}
+
+// Len is the number of elements in the Dict.
+func (d *Dict) Len() int {
+ return len(d.D)
+}
+
+// Swap swaps the elements with indexes i and j.
+func (d *Dict) Swap(i, j int) {
+ iKey, iValue := d.D[i].Key, d.D[i].Value
+ jKey, jValue := d.D[j].Key, d.D[j].Value
+
+ d.D[i].Key, d.D[i].Value = jKey, jValue
+ d.D[j].Key, d.D[j].Value = iKey, iValue
+}
+
+// Less reports whether the element with
+// index i should sort before the element with index j.
+func (d *Dict) Less(i, j int) bool {
+ return d.D[i].Key < d.D[j].Key
+}
+
+// Get get data from key.
+func (d *Dict) Get(key string) interface{} {
+ idx := d.indexOf(key)
+ if idx > -1 {
+ return d.D[idx].Value
+ }
+
+ return nil
+}
+
+// GetBytes get data from key.
+func (d *Dict) GetBytes(key []byte) interface{} {
+ return d.Get(utils.UnsafeString(key))
+}
+
+// Set set new key.
+func (d *Dict) Set(key string, value interface{}) {
+ idx := d.indexOf(key)
+ if idx > -1 {
+ kv := &d.D[idx]
+ kv.Value = value
+ } else {
+ d.append(key, value)
+
+ if d.BinarySearch {
+ sort.Sort(d)
+ }
+ }
+}
+
+// SetBytes set new key.
+func (d *Dict) SetBytes(key []byte, value interface{}) {
+ d.Set(utils.UnsafeString(key), value)
+}
+
+// Del delete key.
+func (d *Dict) Del(key string) {
+ idx := d.indexOf(key)
+ if idx > -1 {
+ n := len(d.D) - 1
+ d.Swap(idx, n)
+ d.D = d.D[:n] // Remove last position
+ }
+}
+
+// DelBytes delete key.
+func (d *Dict) DelBytes(key []byte) {
+ d.Del(utils.UnsafeString(key))
+}
+
+// Has check if key exists.
+func (d *Dict) Has(key string) bool {
+ return d.indexOf(key) > -1
+}
+
+// HasBytes check if key exists.
+func (d *Dict) HasBytes(key []byte) bool {
+ return d.Has(utils.UnsafeString(key))
+}
+
+// Reset reset dict.
+func (d *Dict) Reset() {
+ d.D = d.D[:0]
+}
+
+// Map convert to map.
+func (d *Dict) Map(dst DictMap) {
+ for i := range d.D {
+ kv := &d.D[i]
+
+ sd, ok := kv.Value.(*Dict)
+ if ok {
+ subDst := make(DictMap)
+ sd.Map(subDst)
+ dst[kv.Key] = subDst
+ } else {
+ dst[kv.Key] = kv.Value
+ }
+ }
+}
+
+// Parse convert map to Dict.
+func (d *Dict) Parse(src DictMap) {
+ d.Reset()
+
+ for k, v := range src {
+ sv, ok := v.(map[string]interface{})
+ if ok {
+ subDict := new(Dict)
+ subDict.Parse(sv)
+ d.append(k, subDict)
+ } else {
+ d.append(k, v)
+ }
+ }
+}
diff --git a/internal/dictpool/pool.go b/internal/dictpool/pool.go
new file mode 100644
index 0000000000..6160a4ff65
--- /dev/null
+++ b/internal/dictpool/pool.go
@@ -0,0 +1,20 @@
+package dictpool
+
+import "sync"
+
+var defaultPool = sync.Pool{
+ New: func() interface{} {
+ return new(Dict)
+ },
+}
+
+// AcquireDict acquire new dict.
+func AcquireDict() *Dict {
+ return defaultPool.Get().(*Dict) // nolint:forcetypeassert
+}
+
+// ReleaseDict release dict.
+func ReleaseDict(d *Dict) {
+ d.Reset()
+ defaultPool.Put(d)
+}
diff --git a/internal/dictpool/types.go b/internal/dictpool/types.go
new file mode 100644
index 0000000000..bfcd97796c
--- /dev/null
+++ b/internal/dictpool/types.go
@@ -0,0 +1,25 @@
+package dictpool
+
+//go:generate msgp
+
+// KV struct so it storages key/value data.
+type KV struct {
+ Key string
+ Value interface{}
+}
+
+// Dict dictionary as slice with better performance.
+type Dict struct {
+ // D slice of KV for storage the data
+ D []KV
+
+ // Use binary search to the get an item.
+ // It's only useful on big heaps.
+ //
+ // WARNING: Increase searching performance on big heaps,
+ // but whe set new items could be slowier due to the sorting.
+ BinarySearch bool
+}
+
+// DictMap dictionary as map.
+type DictMap map[string]interface{}
diff --git a/internal/dictpool/types_gen.go b/internal/dictpool/types_gen.go
new file mode 100644
index 0000000000..e1213d3e10
--- /dev/null
+++ b/internal/dictpool/types_gen.go
@@ -0,0 +1,509 @@
+package dictpool
+
+// Code generated by github.com/tinylib/msgp DO NOT EDIT.
+
+import (
+ "github.com/gofiber/fiber/v2/internal/msgp"
+)
+
+// DecodeMsg implements msgp.Decodable
+func (z *Dict) DecodeMsg(dc *msgp.Reader) (err error) {
+ var field []byte
+ _ = field
+ var zb0001 uint32
+ zb0001, err = dc.ReadMapHeader()
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ for zb0001 > 0 {
+ zb0001--
+ field, err = dc.ReadMapKeyPtr()
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ switch msgp.UnsafeString(field) {
+ case "D":
+ var zb0002 uint32
+ zb0002, err = dc.ReadArrayHeader()
+ if err != nil {
+ err = msgp.WrapError(err, "D")
+ return
+ }
+ if cap(z.D) >= int(zb0002) {
+ z.D = (z.D)[:zb0002]
+ } else {
+ z.D = make([]KV, zb0002)
+ }
+ for za0001 := range z.D {
+ var zb0003 uint32
+ zb0003, err = dc.ReadMapHeader()
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001)
+ return
+ }
+ for zb0003 > 0 {
+ zb0003--
+ field, err = dc.ReadMapKeyPtr()
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001)
+ return
+ }
+ switch msgp.UnsafeString(field) {
+ case "Key":
+ z.D[za0001].Key, err = dc.ReadString()
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001, "Key")
+ return
+ }
+ case "Value":
+ z.D[za0001].Value, err = dc.ReadIntf()
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001, "Value")
+ return
+ }
+ default:
+ err = dc.Skip()
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001)
+ return
+ }
+ }
+ }
+ }
+ case "BinarySearch":
+ z.BinarySearch, err = dc.ReadBool()
+ if err != nil {
+ err = msgp.WrapError(err, "BinarySearch")
+ return
+ }
+ default:
+ err = dc.Skip()
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ }
+ }
+ return
+}
+
+// EncodeMsg implements msgp.Encodable
+func (z *Dict) EncodeMsg(en *msgp.Writer) (err error) {
+ // map header, size 2
+ // write "D"
+ err = en.Append(0x82, 0xa1, 0x44)
+ if err != nil {
+ return
+ }
+ err = en.WriteArrayHeader(uint32(len(z.D)))
+ if err != nil {
+ err = msgp.WrapError(err, "D")
+ return
+ }
+ for za0001 := range z.D {
+ // map header, size 2
+ // write "Key"
+ err = en.Append(0x82, 0xa3, 0x4b, 0x65, 0x79)
+ if err != nil {
+ return
+ }
+ err = en.WriteString(z.D[za0001].Key)
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001, "Key")
+ return
+ }
+ // write "Value"
+ err = en.Append(0xa5, 0x56, 0x61, 0x6c, 0x75, 0x65)
+ if err != nil {
+ return
+ }
+ err = en.WriteIntf(z.D[za0001].Value)
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001, "Value")
+ return
+ }
+ }
+ // write "BinarySearch"
+ err = en.Append(0xac, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68)
+ if err != nil {
+ return
+ }
+ err = en.WriteBool(z.BinarySearch)
+ if err != nil {
+ err = msgp.WrapError(err, "BinarySearch")
+ return
+ }
+ return
+}
+
+// MarshalMsg implements msgp.Marshaler
+func (z *Dict) MarshalMsg(b []byte) (o []byte, err error) {
+ o = msgp.Require(b, z.Msgsize())
+ // map header, size 2
+ // string "D"
+ o = append(o, 0x82, 0xa1, 0x44)
+ o = msgp.AppendArrayHeader(o, uint32(len(z.D)))
+ for za0001 := range z.D {
+ // map header, size 2
+ // string "Key"
+ o = append(o, 0x82, 0xa3, 0x4b, 0x65, 0x79)
+ o = msgp.AppendString(o, z.D[za0001].Key)
+ // string "Value"
+ o = append(o, 0xa5, 0x56, 0x61, 0x6c, 0x75, 0x65)
+ o, err = msgp.AppendIntf(o, z.D[za0001].Value)
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001, "Value")
+ return
+ }
+ }
+ // string "BinarySearch"
+ o = append(o, 0xac, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68)
+ o = msgp.AppendBool(o, z.BinarySearch)
+ return
+}
+
+// UnmarshalMsg implements msgp.Unmarshaler
+func (z *Dict) UnmarshalMsg(bts []byte) (o []byte, err error) {
+ var field []byte
+ _ = field
+ var zb0001 uint32
+ zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ for zb0001 > 0 {
+ zb0001--
+ field, bts, err = msgp.ReadMapKeyZC(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ switch msgp.UnsafeString(field) {
+ case "D":
+ var zb0002 uint32
+ zb0002, bts, err = msgp.ReadArrayHeaderBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "D")
+ return
+ }
+ if cap(z.D) >= int(zb0002) {
+ z.D = (z.D)[:zb0002]
+ } else {
+ z.D = make([]KV, zb0002)
+ }
+ for za0001 := range z.D {
+ var zb0003 uint32
+ zb0003, bts, err = msgp.ReadMapHeaderBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001)
+ return
+ }
+ for zb0003 > 0 {
+ zb0003--
+ field, bts, err = msgp.ReadMapKeyZC(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001)
+ return
+ }
+ switch msgp.UnsafeString(field) {
+ case "Key":
+ z.D[za0001].Key, bts, err = msgp.ReadStringBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001, "Key")
+ return
+ }
+ case "Value":
+ z.D[za0001].Value, bts, err = msgp.ReadIntfBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001, "Value")
+ return
+ }
+ default:
+ bts, err = msgp.Skip(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "D", za0001)
+ return
+ }
+ }
+ }
+ }
+ case "BinarySearch":
+ z.BinarySearch, bts, err = msgp.ReadBoolBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "BinarySearch")
+ return
+ }
+ default:
+ bts, err = msgp.Skip(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ }
+ }
+ o = bts
+ return
+}
+
+// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
+func (z *Dict) Msgsize() (s int) {
+ s = 1 + 2 + msgp.ArrayHeaderSize
+ for za0001 := range z.D {
+ s += 1 + 4 + msgp.StringPrefixSize + len(z.D[za0001].Key) + 6 + msgp.GuessSize(z.D[za0001].Value)
+ }
+ s += 13 + msgp.BoolSize
+ return
+}
+
+// DecodeMsg implements msgp.Decodable
+func (z *DictMap) DecodeMsg(dc *msgp.Reader) (err error) {
+ var zb0003 uint32
+ zb0003, err = dc.ReadMapHeader()
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ if (*z) == nil {
+ (*z) = make(DictMap, zb0003)
+ } else if len((*z)) > 0 {
+ for key := range *z {
+ delete((*z), key)
+ }
+ }
+ for zb0003 > 0 {
+ zb0003--
+ var zb0001 string
+ var zb0002 interface{}
+ zb0001, err = dc.ReadString()
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ zb0002, err = dc.ReadIntf()
+ if err != nil {
+ err = msgp.WrapError(err, zb0001)
+ return
+ }
+ (*z)[zb0001] = zb0002
+ }
+ return
+}
+
+// EncodeMsg implements msgp.Encodable
+func (z DictMap) EncodeMsg(en *msgp.Writer) (err error) {
+ err = en.WriteMapHeader(uint32(len(z)))
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ for zb0004, zb0005 := range z {
+ err = en.WriteString(zb0004)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ err = en.WriteIntf(zb0005)
+ if err != nil {
+ err = msgp.WrapError(err, zb0004)
+ return
+ }
+ }
+ return
+}
+
+// MarshalMsg implements msgp.Marshaler
+func (z DictMap) MarshalMsg(b []byte) (o []byte, err error) {
+ o = msgp.Require(b, z.Msgsize())
+ o = msgp.AppendMapHeader(o, uint32(len(z)))
+ for zb0004, zb0005 := range z {
+ o = msgp.AppendString(o, zb0004)
+ o, err = msgp.AppendIntf(o, zb0005)
+ if err != nil {
+ err = msgp.WrapError(err, zb0004)
+ return
+ }
+ }
+ return
+}
+
+// UnmarshalMsg implements msgp.Unmarshaler
+func (z *DictMap) UnmarshalMsg(bts []byte) (o []byte, err error) {
+ var zb0003 uint32
+ zb0003, bts, err = msgp.ReadMapHeaderBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ if (*z) == nil {
+ (*z) = make(DictMap, zb0003)
+ } else if len((*z)) > 0 {
+ for key := range *z {
+ delete((*z), key)
+ }
+ }
+ for zb0003 > 0 {
+ var zb0001 string
+ var zb0002 interface{}
+ zb0003--
+ zb0001, bts, err = msgp.ReadStringBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ zb0002, bts, err = msgp.ReadIntfBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, zb0001)
+ return
+ }
+ (*z)[zb0001] = zb0002
+ }
+ o = bts
+ return
+}
+
+// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
+func (z DictMap) Msgsize() (s int) {
+ s = msgp.MapHeaderSize
+ if z != nil {
+ for zb0004, zb0005 := range z {
+ _ = zb0005
+ s += msgp.StringPrefixSize + len(zb0004) + msgp.GuessSize(zb0005)
+ }
+ }
+ return
+}
+
+// DecodeMsg implements msgp.Decodable
+func (z *KV) DecodeMsg(dc *msgp.Reader) (err error) {
+ var field []byte
+ _ = field
+ var zb0001 uint32
+ zb0001, err = dc.ReadMapHeader()
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ for zb0001 > 0 {
+ zb0001--
+ field, err = dc.ReadMapKeyPtr()
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ switch msgp.UnsafeString(field) {
+ case "Key":
+ z.Key, err = dc.ReadString()
+ if err != nil {
+ err = msgp.WrapError(err, "Key")
+ return
+ }
+ case "Value":
+ z.Value, err = dc.ReadIntf()
+ if err != nil {
+ err = msgp.WrapError(err, "Value")
+ return
+ }
+ default:
+ err = dc.Skip()
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ }
+ }
+ return
+}
+
+// EncodeMsg implements msgp.Encodable
+func (z KV) EncodeMsg(en *msgp.Writer) (err error) {
+ // map header, size 2
+ // write "Key"
+ err = en.Append(0x82, 0xa3, 0x4b, 0x65, 0x79)
+ if err != nil {
+ return
+ }
+ err = en.WriteString(z.Key)
+ if err != nil {
+ err = msgp.WrapError(err, "Key")
+ return
+ }
+ // write "Value"
+ err = en.Append(0xa5, 0x56, 0x61, 0x6c, 0x75, 0x65)
+ if err != nil {
+ return
+ }
+ err = en.WriteIntf(z.Value)
+ if err != nil {
+ err = msgp.WrapError(err, "Value")
+ return
+ }
+ return
+}
+
+// MarshalMsg implements msgp.Marshaler
+func (z KV) MarshalMsg(b []byte) (o []byte, err error) {
+ o = msgp.Require(b, z.Msgsize())
+ // map header, size 2
+ // string "Key"
+ o = append(o, 0x82, 0xa3, 0x4b, 0x65, 0x79)
+ o = msgp.AppendString(o, z.Key)
+ // string "Value"
+ o = append(o, 0xa5, 0x56, 0x61, 0x6c, 0x75, 0x65)
+ o, err = msgp.AppendIntf(o, z.Value)
+ if err != nil {
+ err = msgp.WrapError(err, "Value")
+ return
+ }
+ return
+}
+
+// UnmarshalMsg implements msgp.Unmarshaler
+func (z *KV) UnmarshalMsg(bts []byte) (o []byte, err error) {
+ var field []byte
+ _ = field
+ var zb0001 uint32
+ zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ for zb0001 > 0 {
+ zb0001--
+ field, bts, err = msgp.ReadMapKeyZC(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ switch msgp.UnsafeString(field) {
+ case "Key":
+ z.Key, bts, err = msgp.ReadStringBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "Key")
+ return
+ }
+ case "Value":
+ z.Value, bts, err = msgp.ReadIntfBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "Value")
+ return
+ }
+ default:
+ bts, err = msgp.Skip(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ }
+ }
+ o = bts
+ return
+}
+
+// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
+func (z KV) Msgsize() (s int) {
+ s = 1 + 4 + msgp.StringPrefixSize + len(z.Key) + 6 + msgp.GuessSize(z.Value)
+ return
+}