### Install msgp with Go Toolchain Source: https://github.com/tinylib/msgp/wiki/Getting-Started Installs the msgp library using the go toolchain. Supports Go 1.17+ with 'go install' and earlier versions with 'go get'. ```bash $ go install github.com/tinylib/msgp@latest ``` ```bash $ go get -u -t github.com/tinylib/msgp ``` -------------------------------- ### Custom Msgpack Unmarshaling for Type Changes Source: https://github.com/tinylib/msgp/wiki/Versioning Provides an example of a custom Msgpack unmarshaling logic to handle changing field types. This specific example shows how to read a field that could be either a string or a timestamp, adapting the reading logic based on the Msgpack type. ```go switch msgp.UnsafeString(field) { case "C": switch msgp.NextType(bts) { case msgp.StrType: z.C, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "C") return } case msgp.TimeType: var t time.Time t, bts, err = msgp.ReadTimeBytes(bts) if err != nil { err = msgp.WrapError(err, "C") return } z.C = t.Format(time.RFC3339) default: err = errors.New("did someone change the type again??") return } ... ``` -------------------------------- ### Go: Complete Example with Generic QueueItem, Batch, and Result Source: https://github.com/tinylib/msgp/wiki/Structs-with-Generics A comprehensive Go example showcasing multiple generic types: `QueueItem` for messages, `Batch` for processing multiple items, and `Result` for wrapping outcomes. It includes custom type `UserID` and demonstrates generic constraints with `msgp.RTFor[T]`. ```go package example //go:generate msgp import "github.com/tinylib/msgp/msgp" // Custom type that will be used with generics type UserID int // Generic message queue item type QueueItem[T any, P msgp.RTFor[T]] struct { ID string `msg:"id" Priority int `msg:"priority" Payload T `msg:"payload" Metadata map[string]string `msg:"metadata,allownil" Timestamp int64 `msg:"timestamp" Retries int `msg:"retries" } // Generic batch processor type Batch[T any, P msgp.RTFor[T]] struct { Items []T `msg:"items" ProcessedAt int64 `msg:"processed_at" Results []Result[T, P] `msg:"results,allownil" } // Generic result wrapper type Result[T any, _ msgp.RTFor[T]] struct { Success bool `msg:"success" Data *T `msg:"data,allownil" Error *string `msg:"error,allownil" } // Usage after code generation: // var queue QueueItem[UserID, *UserID] // var batch Batch[UserID, *UserID] ``` -------------------------------- ### Worked Example: Implementing RGBA MessagePack Extension Source: https://github.com/tinylib/msgp/wiki/Using-Extensions A complete example in Go demonstrating the implementation of a custom RGBA MessagePack extension type. It includes registration, defining the Extension interface methods, and using the type within a struct. ```go package main import ( "github.com/tinylib/msgp/msgp" ) func init() { // Registering an extension is as simple as matching the // appropriate type number with a function that initializes // a freshly-allocated object of that type msgp.RegisterExtension(99, func() msgp.Extension { return new(RGBA) } ) } // RGBA will be the concrete type // of our new extension type RGBA [4]byte // Here, we'll pick an arbitrary number between // 0 and 127 that isn't already in use func (r *RGBA) ExtensionType() int8 { return 99 } // We'll always use 4 bytes to encode the data func (r *RGBA) Len() int { return 4 } // MarshalBinaryTo simply copies the value // of the bytes into 'b' func (r *RGBA) MarshalBinaryTo(b []byte) error { copy(b, (*r)[:]) return nil } // UnmarshalBinary copies the value of 'b' // into the RGBA object. (We might want to add // a sanity check here later that len(b)==4.) func (r *RGBA) UnmarshalBinary(b []byte) error { copy((*r)[:], b) return nil } ``` -------------------------------- ### Msgp Command-Line Code Generation Examples Source: https://context7.com/tinylib/msgp/llms.txt Provides examples of how to use the `msgp` command-line tool to generate MessagePack serialization code for Go structs. It covers various options such as specifying input/output files, disabling tests, controlling IO and marshal/unmarshal generation, processing directories, enabling verbose output, including unexported types, and applying directives. ```bash # Generate with default options msgp -file=types.go # Custom output file without tests msgp -file=types.go -o=serialization.go -tests=false # Only generate marshal/unmarshal methods msgp -file=types.go -io=false -marshal=true # Process entire directory msgp -file=./models/ # Enable verbose diagnostics msgp -file=types.go -v # Include unexported types msgp -file=types.go -unexported=true # Apply directives from command line msgp -file=types.go -d "tuple Point" -d "ignore InternalState" ``` -------------------------------- ### Install msgp Go Code Generator Source: https://context7.com/tinylib/msgp/llms.txt Installs the msgp code generator for Go. Supports Go 1.17+ with `@latest` or older versions with `go get -u -t`. This tool is essential for generating optimized MessagePack serialization code. ```bash # For Go 1.17 and later go install github.com/tinylib/msgp@latest # For earlier Go versions go get -u -t github.com/tinylib/msgp ``` -------------------------------- ### Msgp Code Generation Example (Go) Source: https://github.com/tinylib/msgp/wiki/Getting-Started Illustrates a Go code snippet generated by the msgp library, showcasing the implementation of methods for MessagePack encoding and decoding. These generated methods typically include MarshalMsg, UnmarshalMsg, EncodeMsg, DecodeMsg, and Msgsize, which are implementations of interfaces defined in the msgp library. ```Go func (z Foo) Msgsize() (s int) { s = 1 + 4 + msgp.StringPrefixSize + len(z.Bar) + 4 + msgp.Float64Size return } // Assuming a definition for Foo and msgp.ReadFloat64Bytes, msgp.Skip, etc. // The following is a hypothetical unmarshalling logic snippet. /* func (z *Foo) UnmarshalMsg(bts []byte) (o []byte, err error) { var field []byte _ = field if len(bts) < 1+msgp.HashSize { // Check for at least header size return nil, msgp.ErrShortData } msglen, l Nxhdr := msgp.DecodeSize(bts) if l Nxhdr > 0 { bts = bts[l Nxhdr:] } var offset int for msglen > offset { field, err = msgp.ReadMapKeyPtr(bts) if err != nil { return bts, err } bts = bts[len(field):] switch string(field) { case "bar": z.Bar, bts, err = msgp.ReadStringBytes(bts) if err != nil { return } case "baz": z.Baz, bts, err = msgp.ReadFloat64Bytes(bts) if err != nil { return } default: bts, err = msgp.Skip(bts) if err != nil { return } } } o = bts return } */ ``` -------------------------------- ### Zero-Allocation Marshaling with Buffer Reuse in Go Source: https://context7.com/tinylib/msgp/llms.txt Shows how to achieve zero-allocation marshaling in Go using msgp by reusing a byte buffer. This example also demonstrates decoding multiple MessagePack objects from concatenated byte data. ```go package main import ( "fmt" ) //go:generate msgp type Product struct { ID string `msg:"id" Price float64 `msg:"price" Stock int `msg:"stock" } func main() { products := []Product{ {ID: "PROD001", Price: 29.99, Stock: 100}, {ID: "PROD002", Price: 49.99, Stock: 50}, {ID: "PROD003", Price: 19.99, Stock: 200}, } // Allocate buffer once and reuse for multiple objects buf := make([]byte, 0, 256) for i, p := range products { // Reuse buffer (zero allocations after first) buf, err := p.MarshalMsg(buf[:0]) if err != nil { panic(err) } fmt.Printf("Product %d encoded as: %x (%d bytes)\n", i+1, buf, len(buf)) } // Decode multiple objects from concatenated data data, _ := products[0].MarshalMsg(nil) data, _ = products[1].MarshalMsg(data) data, _ = products[2].MarshalMsg(data) var decoded [3]Product remaining := data for i := range decoded { var err error remaining, err = decoded[i].UnmarshalMsg(remaining) if err != nil { panic(err) } } fmt.Printf("\nDecoded all products, remaining bytes: %d\n", len(remaining)) for i, p := range decoded { fmt.Printf("Product %d: %+v\n", i+1, p) } } ``` -------------------------------- ### Renaming Fields in Structs with Msgpack Source: https://github.com/tinylib/msgp/wiki/Versioning Demonstrates how to handle field renaming in Msgpack structs by deserializing into a compatible struct that includes a field for the old name and using the new name for serialization. This approach keeps the primary struct clean but requires manual conversion. ```go type A struct { X string } type A struct { Y string } type WrapA struct { A `msg:",flatten"` X *string } ``` -------------------------------- ### Nested Structures with Maps and Slices in Msgp Go Source: https://context7.com/tinylib/msgp/llms.txt Demonstrates how `msgp` handles complex nested data structures in Go, including nested structs, maps, and slices. This example shows the serialization and deserialization of an `Event` struct which contains a nested `Metadata` struct, a map for tags, an `interface{}` map for properties, and a slice of child `Event` pointers. ```go package main import ( "fmt" "time" ) //go:generate msgp type Metadata struct { Tags map[string]string `msg:"tags" Properties map[string]interface{} `msg:"props" } type Event struct { ID string `msg:"id" Type string `msg:"type" Timestamp time.Time `msg:"ts" Metadata Metadata `msg:"meta" Children []*Event `msg:"children,omitempty" } func main() { event := Event{ ID: "EVT001", Type: "user.login", Timestamp: time.Now(), Metadata: Metadata{ Tags: map[string]string{ "region": "us-west", "env": "prod", }, Properties: map[string]interface{} { "ip": "192.168.1.1", "retries": 3, "success": true, }, }, Children: []*Event{ { ID: "EVT002", Type: "session.created", Timestamp: time.Now(), }, }, } data, err := event.MarshalMsg(nil) if err != nil { panic(err) } fmt.Printf("Encoded event tree: %d bytes\n", len(data)) var decoded Event _, err = decoded.UnmarshalMsg(data) if err != nil { panic(err) } fmt.Printf("Decoded: %s (%s) with %d children\n", decoded.ID, decoded.Type, len(decoded.Children)) } ``` -------------------------------- ### Type Replacement for Foreign Types in Go Source: https://context7.com/tinylib/msgp/llms.txt Illustrates how to replace foreign types with built-in types for serialization using msgp's `msgp:replace` directive. This example replaces `uuid.UUID` with a `[16]byte` array for more efficient serialization. Dependencies: 'github.com/google/uuid'. ```go package main import "github.com/google/uuid" //go:generate msgp //msgp:replace uuid.UUID with:[16]byte type User struct { ID uuid.UUID `msg:"id" // Serialized as [16]byte Username string `msg:"username" Email string `msg:"email" } func main() { u := User{ ID: uuid.New(), Username: "john_doe", Email: "john@example.com", } data, err := u.MarshalMsg(nil) if err != nil { panic(err) } var decoded User _, err = decoded.UnmarshalMsg(data) if err != nil { panic(err) } println("Original ID:", u.ID.String()) println("Decoded ID:", decoded.ID.String()) } ``` -------------------------------- ### Msgp Nested Generics with Constraint Passing Source: https://github.com/tinylib/msgp/wiki/Structs-with-Generics This example illustrates handling nested generic types with Msgp. It shows how to pass the generic constraint parameter (`P msgp.RTFor[T]`) from a parent type (`Parent`) to its child types (`Child`). This ensures consistent type checking and code generation across nested generic structures. ```go //go:generate msgp // Parent type with named constraint parameter type Parent[T any, P msgp.RTFor[T]] struct { Direct T `msg:"direct" Child Child[T, P] `msg:"child" Children []Child[T, P] `msg:"children,allownil" ChildMap map[string]Child[T, P] `msg:"child_map,allownil" } // Child type reusing the parent's constraint type Child[T any, _ msgp.RTFor[T]] struct { Value T `msg:"value" IsValid bool `msg:"is_valid" } ``` -------------------------------- ### Type Shimming for Custom Serialization in Go Source: https://context7.com/tinylib/msgp/llms.txt Shows how to use type shimming with msgp to customize the serialization of types. The `msgp:shim` directive allows specifying a type to alias to and the methods used for conversion (e.g., `String` for encoding, `parseStatus` for decoding). This example customizes the serialization of a `Status` byte type to a string. Dependencies: Go standard library. ```go package main import "fmt" //go:generate msgp //msgp:shim Status as:string using:(Status).String/parseStatus type Status byte const ( Active Status = iota Inactive Suspended Deleted ) func (s Status) String() string { switch s { case Active: return "active" case Inactive: return "inactive" case Suspended: return "suspended" case Deleted: return "deleted" default: return "unknown" } } func parseStatus(s string) Status { switch s { case "active": return Active case "inactive": return Inactive case "suspended": return Suspended case "deleted": return Deleted default: return Inactive } } type Account struct { ID string `msg:"id" Status Status `msg:"status" // Serialized as string instead of byte } func main() { acc := Account{ID: "ACC001", Status: Active} data, _ := acc.MarshalMsg(nil) fmt.Printf("Encoded: %x\n", data) // Status is encoded as "active" string, not byte value } ``` -------------------------------- ### Msgp Struct with Multiple Generic Parameters Source: https://github.com/tinylib/msgp/wiki/Structs-with-Generics This example demonstrates a Msgp-compatible struct `Pair` that uses multiple generic type parameters (`A`, `B`), each with its own Msgp constraint (`AP msgp.RTFor[A]`, `BP msgp.RTFor[B]`). It includes fields for individual elements, a list of type `A`, and a map of type `B`, showcasing flexibility in generic struct design. ```go //go:generate msgp // Struct with two generic types type Pair[A, B any, AP msgp.RTFor[A], BP msgp.RTFor[B]] struct { First A `msg:"first" Second B `msg:"second" AList []A `msg:"a_list,allownil" BMap map[string]B `msg:"b_map,allownil" } // Alternative syntax with unnamed constraints type DualContainer[A, B any, _ msgp.RTFor[A], _ msgp.RTFor[B]] struct { Primary A Secondary B } ``` -------------------------------- ### Tuple Encoding for Compact Serialization in Go Source: https://context7.com/tinylib/msgp/llms.txt Utilizes msgp's tuple encoding to serialize structs as arrays instead of maps, leading to more compact data. This is achieved using the `msgp:tuple` directive. The example shows a `Point` struct being encoded as an array within a `Shape` struct. Dependencies: Go standard library. ```go package main //go:generate msgp // Encode as array [10.5, 20.3] instead of map {"X":10.5,"Y":20.3} //msgp:tuple Point type Point struct { X float64 `msg:"x" Y float64 `msg:"y" } type Shape struct { Name string `msg:"name" Center Point `msg:"center" // Will be encoded as array Radius float64 `msg:"radius" } func main() { s := Shape{ Name: "Circle", Center: Point{X: 10.5, Y: 20.3}, Radius: 5.0, } data, _ := s.MarshalMsg(nil) // Output: map with "center" as [10.5, 20.3] array (more compact) println("Encoded bytes:", len(data)) } ``` -------------------------------- ### Set up Go project and define struct for msgp Source: https://github.com/tinylib/msgp/wiki/Getting-Started Initializes a Go project directory, creates a main.go file, and defines a struct 'Foo' with custom field names for MessagePack serialization using `msgp` directives. This struct will have its serialization and deserialization methods generated. ```bash $ mkdir -p $GOPATH/src/msgp-demo $ cd $GOPATH/src/msgp-demo $ touch main.go ``` ```go package main import ( "fmt" ) //go:generate msgp type Foo struct { Bar string `msg:"bar" Baz float64 `msg:"baz" } func main() { fmt.Println("Nothing to see here yet!") } ``` -------------------------------- ### Buffered I/O for High-Performance Streaming in Go Source: https://context7.com/tinylib/msgp/llms.txt Demonstrates high-performance streaming of log entries using buffered I/O with the msgp library. It shows how to encode multiple log entries into a buffer and then decode them, simulating network or file I/O efficiently. Dependencies include the 'bytes', 'fmt', and 'github.com/tinylib/msgp/msgp' packages. ```go package main import ( "bytes" "fmt" "github.com/tinylib/msgp/msgp" ) //go:generate msgp type LogEntry struct { Timestamp int64 `msg:"ts" Level string `msg:"level" Message string `msg:"msg" } func main() { // Create buffer to simulate network or file I/O var buf bytes.Buffer // Create buffered writer for efficient encoding writer := msgp.NewWriter(&buf) // Encode multiple log entries to stream entries := []LogEntry{ {Timestamp: 1640000000, Level: "INFO", Message: "Application started"}, {Timestamp: 1640000001, Level: "WARN", Message: "High memory usage detected"}, {Timestamp: 1640000002, Level: "ERROR", Message: "Connection failed"}, } for _, entry := range entries { if err := entry.EncodeMsg(writer); err != nil { panic(err) } } // Flush buffered data if err := writer.Flush(); err != nil { panic(err) } fmt.Printf("Encoded %d log entries (%d bytes)\n\n", len(entries), buf.Len()) // Decode from stream reader := msgp.NewReader(&buf) for i := 0; i < len(entries); i++ { var entry LogEntry if err := entry.DecodeMsg(reader); err != nil { panic(err) } fmt.Printf("Entry %d: [%s] %s (ts=%d)\n", i+1, entry.Level, entry.Message, entry.Timestamp) } } ``` -------------------------------- ### Generate MessagePack Serialization Methods in Go Source: https://github.com/tinylib/msgp/blob/master/README.md This directive instructs the `msgp` tool to generate MessagePack serialization and deserialization methods for all exported types within the Go source file. It requires the `msgp` command to be installed. ```go //go:generate msgp ``` -------------------------------- ### Generate msgp code and run tests Source: https://github.com/tinylib/msgp/wiki/Getting-Started Executes the `go generate` command, which triggers the msgp tool to create `main_gen.go` and `main_gen_test.go` based on the `//go:generate msgp` directive in `main.go`. It then shows how to run the generated tests and benchmarks to verify the functionality. ```bash $ go generate ======== MessagePack Code Generator ======= >>> Input: "main.go" >>> Wrote and formatted "main_gen.go" >>> Wrote and formatted "main_gen_test.go" $ ls main.go main_gen.go main_gen_test.go $ go test -v -bench . === RUN TestMarshalUnmarshalFoo --- PASS: TestMarshalUnmarshalFoo (0.00s) === RUN TestEncodeDecodeFoo --- PASS: TestEncodeDecodeFoo (0.00s) PASS BenchmarkMarshalMsgFoo-8 20000000 97.9 ns/op 32 B/op 1 allocs/op BenchmarkAppendMsgFoo-8 30000000 41.4 ns/op 458.43 MB/s 0 B/op 0 allocs/op BenchmarkUnmarshalFoo-8 20000000 94.7 ns/op 200.57 MB/s 0 B/op 0 allocs/op BenchmarkEncodeFoo-8 20000000 57.2 ns/op 332.15 MB/s 0 B/op 0 allocs/op BenchmarkDecodeFoo-8 10000000 135 ns/op 140.50 MB/s 0 B/op 0 allocs/op ok msgp-demo 9.712s ``` -------------------------------- ### Estimate Size and Pre-allocate Buffers in Go Source: https://context7.com/tinylib/msgp/llms.txt This code illustrates performance optimizations for msgp serialization in Go, focusing on estimating the encoded size of a struct and pre-allocating buffers. It demonstrates calculating the estimated size using `Msgsize()`, pre-allocating a buffer with that capacity, and then marshaling data into it. This reduces memory allocations and improves efficiency, especially for batch operations. It requires the 'fmt' and 'github.com/tinylib/msgp/msgp' packages. ```go package main import ( "fmt" "github.com/tinylib/msgp/msgp" ) //go:generate msgp type Transaction struct { ID string `msg:"id" Amount float64 `msg:"amount" Currency string `msg:"currency" Description string `msg:"desc" } func main() { txn := Transaction{ ID: "TXN123456789", Amount: 1234.56, Currency: "USD", Description: "Purchase from online store", } // Get estimated size before encoding estimatedSize := txn.Msgsize() fmt.Printf("Estimated encoded size: %d bytes\n", estimatedSize) // Pre-allocate buffer with estimated size buf := make([]byte, 0, estimatedSize) buf, err := txn.MarshalMsg(buf) if err != nil { panic(err) } fmt.Printf("Actual encoded size: %d bytes\n", len(buf)) fmt.Printf("Estimation accuracy: %.1f%%\n", float64(estimatedSize)/float64(len(buf))*100) // Efficient batch encoding with pre-sized buffer transactions := make([]Transaction, 100) totalSize := 0 for i := range transactions { transactions[i] = txn totalSize += transactions[i].Msgsize() } batchBuf := make([]byte, 0, totalSize) for _, t := range transactions { batchBuf, _ = t.MarshalMsg(batchBuf) } fmt.Printf("\nBatch: %d transactions = %d bytes\n", len(transactions), len(batchBuf)) } ``` -------------------------------- ### Ignoring Types from Code Generation in Go Source: https://context7.com/tinylib/msgp/llms.txt Demonstrates how to prevent msgp from generating serialization code for specific types using the `msgp:ignore` directive. This is useful for types that should not be serialized or deserialized. The example shows `InternalState` and `DebugInfo` types being ignored. Dependencies: Go standard library. ```go package main //go:generate msgp //msgp:ignore InternalState DebugInfo type InternalState struct { // This type will be skipped by code generator data []byte } type DebugInfo struct { // This type will also be skipped stackTrace string } type User struct { ID string `msg:"id" Username string `msg:"username" // These fields won't have generated code state InternalState `msg:"-" debug DebugInfo `msg:"-" } ``` -------------------------------- ### msgp.Marshaler and msgp.Unmarshaler Usage (Go) Source: https://github.com/tinylib/msgp/wiki/Getting-Started Demonstrates the zero-allocation marshaling and unmarshaling of MessagePack data using the msgp.Marshaler and msgp.Unmarshaler interfaces. These methods allow for efficient in-place data manipulation by returning slices that are concatenations or sub-slices of the input, minimizing memory allocations. ```Go foo1 := Foo{ /* ... */ } foo2 := Foo{ /* ... */ } // data contains the body of foo1 data, _ := foo1.MarshalMsg(nil) fmt.Printf("foo1 is encoded as %x\n", data) // data is overwritten with the // body of foo2. if it fits within // the old slice, no new memory // is allocated. data, _ = foo2.MarshalMsg(data[:0]) fmt.Printf("foo2 is encoded as %x\n", data) foo1 = Foo{ /* ... */ } foo2 = Foo{ /* ... */ } fmt.Printf("foo1: %v\n", foo1) fmt.Printf("foo2: %v\n", foo2) // Here, we append two messages // to the same slice. data, _ := foo1.MarshalMsg(nil) data, _ = foo2.MarshalMsg(data) // Now we'll just decode them // in reverse: data, _ = foo2.UnmarshalMsg(data) data, _ = foo1.UnmarshalMsg(data) // at this point, len(data) should be 0 fmt.Println("len(data) =", len(data)) fmt.Printf("foo1: %v", foo1) fmt.Printf("foo2: %v", foo2) ``` -------------------------------- ### Marshal and Unmarshal Data with Msgp in Go Source: https://github.com/tinylib/msgp/wiki/Working-Demo This Go snippet demonstrates how to use the msgp-generated `MarshalMsg` and `UnmarshalMsg` methods. It creates an instance of the `QryD` struct, marshals it into a byte slice, then unmarshals the byte slice back into another `QryD` instance, printing the results. ```go package main import ( "fmt" ) //go:generate msgp type QryD struct { A int8 D int8 T string K string V string } func main() { var valuePlaceholder QryD v := QryD{A: 1, D: 9, T: "table", K: "key", V: "value"} bts, err := v.MarshalMsg(nil) if err != nil { // fmt.Println(err) // print err or log error information } leftovervalues, err := valuePlaceholder.UnmarshalMsg(bts) // purpose of lefovervalues, pls read doc. fmt.Println(leftovervalues) // leftovervalues is empty because bts only contained one object. fmt.Println(valuePlaceholder) fmt.Println(valuePlaceholder.A) fmt.Println(valuePlaceholder.D) fmt.Println(valuePlaceholder.T) fmt.Println(valuePlaceholder.K) fmt.Println(valuePlaceholder.V) if err != nil { fmt.Printf("error: %s\n", err) } } ``` -------------------------------- ### Define Struct and Generate Msgp Code in Go Source: https://github.com/tinylib/msgp/wiki/Working-Demo This snippet defines a Go struct `QryD` and uses the `//go:generate msgp` directive to instruct the msgp tool to generate serialization and deserialization methods for this struct. The `go generate` command processes this directive. ```go package main import ( "fmt" ) //go:generate msgp type QryD struct { A int8 D int8 T string K string V string } func main() { fmt.Println("Nothing to see here yet!") } ``` -------------------------------- ### Decoding Data with msgp.Decodable in Go Source: https://github.com/tinylib/msgp/wiki/Getting-Started Demonstrates how to use the msgp.Decodable interface to read data from a msgp.Reader. This involves setting up an io.Pipe, encoding an object in a goroutine, and then decoding it into another object. It requires the 'msgp' and 'io' packages. ```go pr, pw := io.Pipe() go func() { w := msgp.NewWriter(pw) fooIn := Foo{ /* ... */ } fmt.Printf("fooIn is %v\n", fooIn) fooIn.EncodeMsg(w) w.Flush() }() var fooOut Foo fooOut.DecodeMsg(msgp.NewReader(pr)) fmt.Printf("fooOut is %v\n", fooOut) ``` -------------------------------- ### Lazy Serialization with msgp.Raw Source: https://github.com/tinylib/msgp/wiki/Tips-and-Tricks Illustrates using msgp.Raw for lazy serialization, allowing a struct to act as a container for any MessagePack object. This is useful for handling unknown or polymorphic data structures. ```go package main import ( "fmt" "github.com/tinylib/msgp/msgp" ) //go:generate msgp type Foo struct { A string `msg:"a"` Another string `msg:"b"` } type Data struct { Header uint16 `msg:"header"` Body msgp.Raw `msg:"body"` } func main() { foo1 := Foo{A: "Hello", Another: "World"} body, _ := foo1.MarshalMsg(nil) fmt.Printf("foo1 is encoded as %x\n", body) data := Data{ Header: 1, Body: body, } dataPacket, _ := data.MarshalMsg(nil) var ( readPacket Data readFoo Foo ) _, _ = readPacket.UnmarshalMsg(dataPacket) if readPacket.Header == 1 { _, _ = readFoo.UnmarshalMsg([]byte(readPacket.Body)) fmt.Println(readFoo) } } ``` -------------------------------- ### Handle msgp Errors with msgp.Error Interface Source: https://github.com/tinylib/msgp/wiki/Tips-and-Tricks Demonstrates how to check for msgp-specific errors by implementing the msgp.Error interface. This allows distinguishing between MessagePack encoding/decoding errors and other types of errors, and checking if an error is resumable. ```go f, err := r.ReadFloat64() if err != nil { if msgerr, ok := err.(msgp.Error); ok && msgerr.Resumable() { // the next object probably isn't a float64 } // something else went wrong log.Fatalln("something broke:", err) } ``` -------------------------------- ### Serialize Slice of Structs with msgp Source: https://github.com/tinylib/msgp/wiki/Tips-and-Tricks Demonstrates how to define a custom type for a slice of structs and use msgp to marshal and unmarshal them. This approach is useful for direct serialization of base types within slices. ```go package main import ( "fmt" "github.com/tinylib/msgp/msgp" ) //go:generate msgp type Foo struct { A string `msg:"a"` } type Foos []Foo func main() { // Marshal foos := []Foo{{A: "Hello"}, {A: "World"}} body, _ := Foos(foos).MarshalMsg(nil) fmt.Printf("foos is encoded as %x\n", body) // Unmarshal var dst Foos _, _ = dst.UnmarshalMsg(body) // Foos can easily be converted back to []Foo if needed. fmt.Println([]Foo(dst)) } ``` -------------------------------- ### Implement Custom MessagePack Extensions with Go Source: https://context7.com/tinylib/msgp/llms.txt Demonstrates how to define and register custom extension types for MessagePack serialization in Go using the `msgp` library. This includes defining a custom type (RGBA), registering it with a specific type ID, and implementing the necessary methods for marshaling and unmarshaling. ```go package main import ( "fmt" "github.com/tinylib/msgp/msgp" ) // Custom extension for RGBA color values type RGBA [4]byte func init() { // Register extension with type ID 99 msgp.RegisterExtension(99, func() msgp.Extension { return new(RGBA) }) } func (r *RGBA) ExtensionType() int8 { return 99 } func (r *RGBA) Len() int { return 4 } func (r *RGBA) MarshalBinaryTo(b []byte) error { copy(b, (*r)[:]) return nil } func (r *RGBA) UnmarshalBinary(b []byte) error { copy((*r)[:], b) return nil } //go:generate msgp type Image struct { Width int `msg:"width" Height int `msg:"height" Background RGBA `msg:"bg,extension" // Use extension encoding Foreground RGBA `msg:"fg,extension" } func main() { img := Image{ Width: 800, Height: 600, Background: RGBA{255, 255, 255, 255}, // White Foreground: RGBA{0, 0, 0, 255}, // Black } data, err := img.MarshalMsg(nil) if err != nil { panic(err) } fmt.Printf("Encoded image metadata: %x\n", data) var decoded Image _, err = decoded.UnmarshalMsg(data) if err != nil { panic(err) } fmt.Printf("Decoded: %dx%d, BG=%v, FG=%v\n", decoded.Width, decoded.Height, decoded.Background, decoded.Foreground) } ``` -------------------------------- ### Go: Struct with Zerocopy Tag for Byte Slices Source: https://github.com/tinylib/msgp/wiki/Zero-Values;-Omitempty-and-Allownil Demonstrates the `zerocopy` tag in Go for `[]byte` fields. This option allows `UnmarshalMsg` to extract bytes without performing a copy, improving performance. It can be combined with `allownil` and `omitempty`. ```Go type X struct { ZCBytes []byte `msg:",zerocopy"` ZCBytesAN []byte `msg:",zerocopy,allownil"` ZCBytesOE []byte `msg:",zerocopy,omitempty"` } ``` -------------------------------- ### Using Custom RGBA Type in a Struct and JSON Marshaling Source: https://github.com/tinylib/msgp/wiki/Using-Extensions Illustrates how to use a custom `RGBA` type, which has been registered as a MessagePack extension, within a Go struct. It also shows how to implement `json.Marshaler` for custom JSON representation. ```go type ColoredBox struct { Height int `msg:"height` Width int `msg:"width"` Color RGBA `msg:"color,extension"` } func (r *RGBA) MarshalJSON() ([]byte, error) { b := *r return []byte(fmt.Sprintf("[%d, %d, %d, %d]", b[0], b[1], b[2], b[3])), nil } ``` -------------------------------- ### Go: Struct with AllowNil Tag for Slices Source: https://github.com/tinylib/msgp/wiki/Zero-Values;-Omitempty-and-Allownil Shows how the `allownil` tag in Go enables nil slices and maps to be explicitly represented rather than being treated as zero-sized. Field `A` will always be included, writing a nil value if the slice is nil. This contrasts with `omitempty` (field `B`) which would omit the field entirely if the slice is nil. ```Go type Example struct { A []string `msg:"a,allownil"` B []int `msg:"b,omitempty"` C []string `msg:"c"` } ``` -------------------------------- ### Advanced Field Tags for Msgp in Go Source: https://context7.com/tinylib/msgp/llms.txt Illustrates the use of advanced field tags in `msgp` for fine-grained control over serialization behavior. This includes `zerocopy` for efficient byte slice handling, `omitempty` to exclude fields with zero values, and `allownil` to permit nil values for optional fields. ```go package main //go:generate msgp type DataPacket struct { // Zero-copy byte slices (no defensive copy on decode) Payload []byte `msg:"payload,zerocopy" // Allow nil for optional byte slices OptionalData []byte `msg:"optional,zerocopy,allownil" // Omit field if empty Metadata []byte `msg:"meta,zerocopy,omitempty" // Regular fields ID string `msg:"id" Size int `msg:"size" // Omit empty string Description string `msg:"desc,omitempty" // Private field (not serialized) privateField string } func main() { pkt := DataPacket{ ID: "PKT001", Payload: []byte("Hello, World!"), Size: 13, // OptionalData is nil (will be encoded as nil) // Metadata is nil (will be omitted) // Description is empty (will be omitted) } data, _ := pkt.MarshalMsg(nil) println("Encoded size:", len(data)) var decoded DataPacket decoded.UnmarshalMsg(data) println("Decoded ID:", decoded.ID) println("Payload length:", len(decoded.Payload)) } ``` -------------------------------- ### Generated msgp MarshalMsg method Source: https://github.com/tinylib/msgp/wiki/Getting-Started This Go code snippet shows the `MarshalMsg` method generated by msgp for the 'Foo' struct. It demonstrates how to efficiently marshal the struct into a byte slice, including pre-allocating sufficient space and appending MessagePack encoded fields. ```go package main // NOTE: THIS FILE WAS PRODUCED BY THE // MSGP CODE GENERATION TOOL (github.com/tinylib/msgp) // DO NOT EDIT import ( "github.com/tinylib/msgp/msgp" ) // MarshalMsg implements msgp.Marshaler func (z Foo) MarshalMsg(b []byte) (o []byte, err error) { o = msgp.Require(b, z.Msgsize()) // map header, size 2 // string "bar" o = append(o, 0x82, 0xa3, 0x62, 0x61, 0x72) o = msgp.AppendString(o, z.Bar) // string "baz" o = append(o, 0xa3, 0x62, 0x61, 0x7a) o = msgp.AppendFloat64(o, z.Baz) return } ``` -------------------------------- ### msgp.Encodable Usage with msgp.Writer (Go) Source: https://github.com/tinylib/msgp/wiki/Getting-Started Shows how to encode a struct to a msgp.Writer using the msgp.Encodable interface. This method writes the object to a buffered writer, leveraging its internal buffer for efficient, no-allocation writing to an io.Writer. ```Go foo := Foo{ /* ... */ } w := msgp.NewWriter(os.Stdout) foo.EncodeMsg(w) w.Flush() ``` -------------------------------- ### Go: Generic Response Wrapper Structure Source: https://github.com/tinylib/msgp/wiki/Structs-with-Generics Defines a generic struct `Response` for wrapping API responses. It supports generic data types and includes fields for success status, data payload, error messages, and metadata. The `msgp.RTFor[T]` constraint ensures type compatibility for marshaling. ```go //go:generate msgp type Response[T any, _ msgp.RTFor[T]] struct { Success bool `msg:"success" Data T `msg:"data" Error *string `msg:"error,allownil" Meta map[string]string `msg:"meta,allownil" } ```