proto

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 24, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package proto provides Protocol Buffers binding support for the binding package.

This package extends rivaas.dev/binding with Protocol Buffers serialization support, using google.golang.org/protobuf for parsing.

Example:

// Assuming you have generated proto code:
// message User {
//     string name = 1;
//     int32 age = 2;
// }

user, err := proto.Proto[*pb.User](body)
if err != nil {
    // handle error
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func FromProto

func FromProto(body []byte, opts ...Option) binding.Option

FromProto returns a binding.Option that specifies Protocol Buffers body as a binding source. This can be used with binding.Bind for multi-source binding.

Note: When using FromProto, you need to ensure the target struct implements proto.Message.

Example:

req, err := binding.Bind[*pb.Request](
    binding.FromQuery(r.URL.Query()),
    proto.FromProto(body),
)

func FromProtoReader

func FromProtoReader(r io.Reader, opts ...Option) binding.Option

FromProtoReader returns a binding.Option that specifies Protocol Buffers from io.Reader as a binding source.

Example:

req, err := binding.Bind[*pb.Request](
    proto.FromProtoReader(r.Body),
)

func Proto

func Proto[T Message](body []byte, opts ...Option) (T, error)

Proto binds Protocol Buffers bytes to type T. T must implement proto.Message.

Example:

user, err := proto.Proto[*pb.User](body)

// With options
user, err := proto.Proto[*pb.User](body, proto.WithDiscardUnknown())
Example

ExampleProto demonstrates basic Protocol Buffers binding.

package main

import (
	"fmt"
	"log"

	"rivaas.dev/binding/proto"
	"rivaas.dev/binding/proto/testdata"

	goproto "google.golang.org/protobuf/proto"
)

func main() {
	// Create a test user message
	user := &testdata.User{
		Name:   "John",
		Email:  "john@example.com",
		Age:    30,
		Active: true,
	}

	// Marshal to proto bytes (simulating incoming request)
	body, err := goproto.Marshal(user)
	if err != nil {
		log.Fatal(err)
	}

	// Bind using the proto package
	result, err := proto.Proto[*testdata.User](body)
	if err != nil {
		log.Fatal(err)
	}

	_, _ = fmt.Printf("Name: %s, Email: %s, Age: %d, Active: %v\n", result.GetName(), result.GetEmail(), result.GetAge(), result.GetActive())
}
Output:
Name: John, Email: john@example.com, Age: 30, Active: true
Example (MapFields)

ExampleProto_mapFields demonstrates binding Protocol Buffers map fields.

package main

import (
	"fmt"
	"log"

	"rivaas.dev/binding/proto"
	"rivaas.dev/binding/proto/testdata"

	goproto "google.golang.org/protobuf/proto"
)

func main() {
	// Create settings with a map field
	settings := &testdata.Settings{
		Name: "AppSettings",
		Metadata: map[string]string{
			"version":     "1.0.0",
			"environment": "production",
		},
	}

	// Marshal to proto bytes
	body, err := goproto.Marshal(settings)
	if err != nil {
		log.Fatal(err)
	}

	// Bind the map fields
	result, err := proto.Proto[*testdata.Settings](body)
	if err != nil {
		log.Fatal(err)
	}

	_, _ = fmt.Printf("Settings: %s\n", result.GetName())
	_, _ = fmt.Printf("Version: %s\n", result.GetMetadata()["version"])
	_, _ = fmt.Printf("Environment: %s\n", result.GetMetadata()["environment"])
}
Output:
Settings: AppSettings
Version: 1.0.0
Environment: production
Example (MultipleOptions)

ExampleProto_multipleOptions demonstrates using multiple options together.

package main

import (
	"fmt"
	"log"

	"rivaas.dev/binding/proto"
	"rivaas.dev/binding/proto/testdata"

	goproto "google.golang.org/protobuf/proto"
)

func main() {
	// Create a test user message
	user := &testdata.User{
		Name:   "Diana",
		Email:  "diana@example.com",
		Age:    32,
		Active: true,
	}

	// Marshal to proto bytes
	body, err := goproto.Marshal(user)
	if err != nil {
		log.Fatal(err)
	}

	// Bind with multiple options
	result, err := proto.Proto[*testdata.User](body,
		proto.WithAllowPartial(),
		proto.WithDiscardUnknown(),
		proto.WithRecursionLimit(5000),
	)
	if err != nil {
		log.Fatal(err)
	}

	_, _ = fmt.Printf("Name: %s, Age: %d\n", result.GetName(), result.GetAge())
}
Output:
Name: Diana, Age: 32
Example (NestedMessages)

ExampleProto_nestedMessages demonstrates binding nested Protocol Buffers messages.

package main

import (
	"fmt"
	"log"

	"rivaas.dev/binding/proto"
	"rivaas.dev/binding/proto/testdata"

	goproto "google.golang.org/protobuf/proto"
)

func main() {
	// Create a nested config message
	config := &testdata.Config{
		Title: "Production Config",
		Server: &testdata.Server{
			Host: "0.0.0.0",
			Port: 8080,
		},
		Database: &testdata.Database{
			Host:     "db.example.com",
			Port:     5432,
			Name:     "mydb",
			User:     "admin",
			Password: "secret",
		},
	}

	// Marshal to proto bytes
	body, err := goproto.Marshal(config)
	if err != nil {
		log.Fatal(err)
	}

	// Bind the nested structure
	result, err := proto.Proto[*testdata.Config](body)
	if err != nil {
		log.Fatal(err)
	}

	_, _ = fmt.Printf("Title: %s\n", result.GetTitle())
	_, _ = fmt.Printf("Server: %s:%d\n", result.GetServer().GetHost(), result.GetServer().GetPort())
	_, _ = fmt.Printf("Database: %s@%s:%d\n", result.GetDatabase().GetName(), result.GetDatabase().GetHost(), result.GetDatabase().GetPort())
}
Output:
Title: Production Config
Server: 0.0.0.0:8080
Database: mydb@db.example.com:5432
Example (RepeatedFields)

ExampleProto_repeatedFields demonstrates binding repeated Protocol Buffers fields.

package main

import (
	"fmt"
	"log"

	"rivaas.dev/binding/proto"
	"rivaas.dev/binding/proto/testdata"

	goproto "google.golang.org/protobuf/proto"
)

func main() {
	// Create a product with repeated fields
	product := &testdata.Product{
		Name:   "Widget",
		Tags:   []string{"electronics", "gadget", "sale"},
		Prices: []int32{100, 150, 200},
	}

	// Marshal to proto bytes
	body, err := goproto.Marshal(product)
	if err != nil {
		log.Fatal(err)
	}

	// Bind the repeated fields
	result, err := proto.Proto[*testdata.Product](body)
	if err != nil {
		log.Fatal(err)
	}

	_, _ = fmt.Printf("Product: %s\n", result.GetName())
	_, _ = fmt.Printf("Tags: %v\n", result.GetTags())
	_, _ = fmt.Printf("Prices: %v\n", result.GetPrices())
}
Output:
Product: Widget
Tags: [electronics gadget sale]
Prices: [100 150 200]
Example (WithDiscardUnknown)

ExampleProto_withDiscardUnknown demonstrates binding with unknown field handling.

package main

import (
	"fmt"
	"log"

	"rivaas.dev/binding/proto"
	"rivaas.dev/binding/proto/testdata"

	goproto "google.golang.org/protobuf/proto"
)

func main() {
	// Create a test user message
	user := &testdata.User{
		Name:   "Bob",
		Email:  "bob@example.com",
		Age:    35,
		Active: false,
	}

	// Marshal to proto bytes
	body, err := goproto.Marshal(user)
	if err != nil {
		log.Fatal(err)
	}

	// Bind with DiscardUnknown option
	result, err := proto.Proto[*testdata.User](body, proto.WithDiscardUnknown())
	if err != nil {
		log.Fatal(err)
	}

	_, _ = fmt.Printf("Name: %s, Active: %v\n", result.GetName(), result.GetActive())
}
Output:
Name: Bob, Active: false

func ProtoReader

func ProtoReader[T Message](r io.Reader, opts ...Option) (T, error)

ProtoReader binds Protocol Buffers from an io.Reader to type T. T must implement proto.Message.

Example:

user, err := proto.ProtoReader[*pb.User](r.Body)
Example

ExampleProtoReader demonstrates Protocol Buffers binding from io.Reader.

package main

import (
	"bytes"
	"fmt"
	"log"

	"rivaas.dev/binding/proto"
	"rivaas.dev/binding/proto/testdata"

	goproto "google.golang.org/protobuf/proto"
)

func main() {
	// Create a test user message
	user := &testdata.User{
		Name:   "Alice",
		Email:  "alice@example.com",
		Age:    25,
		Active: true,
	}

	// Marshal to proto bytes
	body, err := goproto.Marshal(user)
	if err != nil {
		log.Fatal(err)
	}

	// Bind from io.Reader
	result, err := proto.ProtoReader[*testdata.User](bytes.NewReader(body))
	if err != nil {
		log.Fatal(err)
	}

	_, _ = fmt.Printf("Name: %s, Email: %s\n", result.GetName(), result.GetEmail())
}
Output:
Name: Alice, Email: alice@example.com

func ProtoReaderTo

func ProtoReaderTo(r io.Reader, out Message, opts ...Option) error

ProtoReaderTo binds Protocol Buffers from an io.Reader to out. out must implement proto.Message.

Example:

var user pb.User
err := proto.ProtoReaderTo(r.Body, &user)

func ProtoTo

func ProtoTo(body []byte, out Message, opts ...Option) error

ProtoTo binds Protocol Buffers bytes to out. out must implement proto.Message.

Example:

var user pb.User
err := proto.ProtoTo(body, &user)
Example

ExampleProtoTo demonstrates non-generic Protocol Buffers binding.

package main

import (
	"fmt"
	"log"

	"rivaas.dev/binding/proto"
	"rivaas.dev/binding/proto/testdata"

	goproto "google.golang.org/protobuf/proto"
)

func main() {
	// Create a test config message
	config := &testdata.Config{
		Title: "My App",
		Server: &testdata.Server{
			Host: "localhost",
			Port: 8080,
		},
	}

	// Marshal to proto bytes
	body, err := goproto.Marshal(config)
	if err != nil {
		log.Fatal(err)
	}

	// Bind using the non-generic function
	var result testdata.Config
	err = proto.ProtoTo(body, &result)
	if err != nil {
		log.Fatal(err)
	}

	_, _ = fmt.Printf("Title: %s, Server: %s:%d\n", result.GetTitle(), result.GetServer().GetHost(), result.GetServer().GetPort())
}
Output:
Title: My App, Server: localhost:8080

Types

type Message

type Message = proto.Message

Message is an alias for proto.Message to simplify imports.

type Option

type Option func(*config)

Option configures Protocol Buffers binding behavior.

func WithAllowPartial

func WithAllowPartial() Option

WithAllowPartial allows messages that have missing required fields to unmarshal without returning an error.

func WithDiscardUnknown

func WithDiscardUnknown() Option

WithDiscardUnknown specifies whether to ignore unknown fields when unmarshaling.

func WithRecursionLimit

func WithRecursionLimit(limit int) Option

WithRecursionLimit sets the maximum recursion depth for unmarshaling. The default limit is 10,000.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL