# Protobuf - High-performance Perl Protocol Buffers using upb

Protobuf is a high-performance Protocol Buffers implementation for Perl, built
upon the efficient `upb` C library. It provides a memory-safe, thread-isolated
environment with advanced features like thread-local arena caching,
SIMD-accelerated conversions, and zero-copy IPC support.

## Features

-   **Extreme Performance:** Utilizes the `upb` C library and VPP-inspired
    patterns.
-   **Memory Safety:** Implements 16-byte canary guards for all arena-allocated
    blocks.
-   **Thread Isolation:** Interpreter-local state via a per-interpreter
    registry.
-   **Advanced Containers:** Direct-to-hash projection for maps and descriptors.
-   **Well-Known Types:** Full support for Any, Duration, Timestamp, Struct,
    etc.
-   **JSON & Text Format:** High-speed serialization and parsing.

## Prerequisites

This Perl module requires Bazel to build the `protoc-gen-perl-pb` plugin. Ensure
you have Bazel installed. The necessary C++ Protobuf libraries used by the
plugin are typically fetched and built by Bazel as part of the main project's
workspace setup.

Additionally, you'll need a C++ compiler (like g++), Make, and the Perl
development headers.

To install Perl module dependencies, you can use `cpanm`:

```bash
# Install cpanminus and Carton
cpanm App::cpanminus Carton

# From the perl/ directory
carton install
```

This will install dependencies listed in the `cpanfile`.

## Building the Plugin

The `protoc-gen-perl-pb` plugin is built automatically via Bazel when you run
`make` in the `perl/` directory, as configured in `Makefile.PL`.

## Installation

To build and test the Perl module:

```bash
# From the perl/ directory
perl Makefile.PL
make -j$(nproc)
make test
sudo make install
```

To run a full clean test cycle, including rebuilding the plugin:

```bash
# From the perl/ directory
# Clean up previous Bazel run for the plugin
bazel --output_base=/usr/local/google/home/cjac/.gemini/tmp/protobuf/bazel_output_base clean --expunge
# Clean up MakeMaker build
make clean
# Regenerate Makefile and build everything including the plugin, then test
perl Makefile.PL && make -j$(nproc) && make test
```

**Note:** We use a specific Bazel `output_base` to ensure cache consistency
between different shells. If you run Bazel commands manually in this workspace,
you should use the same output base: `alias bazel='bazel
--output_base=/usr/local/google/home/cjac/.gemini/tmp/protobuf/bazel_output_base'`

## Code Generation

To translate a `.proto` schema file into Perl classes, you use the standard
Protocol Buffers compiler `protoc` in combination with the custom
`protoc-gen-perl-pb` plugin.

### 1. Build the Plugin

First, ensure that the plugin executable has been built in the `perl` directory
by running:

```bash
make protoc-gen-perl-pb
```

This generates the executable file `protoc-gen-perl-pb` in the root of the
`perl` directory.

> [!NOTE] The file `bin/protoc-gen-perl-pb` tracked in the repository is a
> skeletal mock script. The actual compiled C++ plugin binary will be created in
> the root of the `perl` directory.

### 2. Generate Perl Classes

Run `protoc` specifying the path to our plugin and the output directory:

```bash
protoc --plugin=protoc-gen-perl-pb=./protoc-gen-perl-pb \
       --perl-pb_out=embed_descriptors=true:./lib \
       --proto_path=./proto \
       ./proto/my_service.proto
```

Flag Details:

*   `--plugin=protoc-gen-perl-pb=./protoc-gen-perl-pb` points the compiler to
    the plugin executable
*   `--perl-pb_out=embed_descriptors=true:./lib` specifies the target directory
    for the generated `.pm` files. The `embed_descriptors=true` parameter is
    required to embed the compiled schema metadata in the generated modules,
    enabling runtime loading without `.proto` file dependencies
*   `--proto_path=./proto` defines the search path for imported `.proto` schemas
*   `./proto/my_service.proto` is the target schema file to compile

### 3. Load the Generated Module

The plugin generates Perl modules matching the package namespace. If
`my_service.proto` defines `package google.cloud.test.v1;`, it generates
`Google/Cloud/Test/V1/Service.pm` under the target directory.

You can then load it in your Perl code by adding the target directory to `@INC`:

```perl
use lib 'lib';
use Google::Cloud::Test::V1::Service;

my $req = Google::Cloud::Test::V1::Service::HelloRequest->new(
    name => 'World',
);
```

## Usage

```perl
use Protobuf::DescriptorPool;

my $pool = Protobuf::DescriptorPool->generated_pool();
$pool->add_serialized_file_descriptor_set($data);

my $msg = My::Generated::Message->new();
$msg->set_value(42);
my $wire = $msg->serialize();
```

## License

This software is licensed under the Apache License 2.0.
