mirror of
https://github.com/Brandon-Rozek/website.git
synced 2024-10-30 01:12:07 -04:00
78 lines
3 KiB
Markdown
78 lines
3 KiB
Markdown
---
|
|
title: "Importing External Schemas in Prost"
|
|
date: 2024-10-05T11:19:37-07:00
|
|
draft: false
|
|
tags: []
|
|
math: false
|
|
medium_enabled: false
|
|
---
|
|
|
|
[Prost](https://github.com/tokio-rs/prost) is a popular Protocol Buffers implementation written in Rust. The `protoc` command is commonly used to generate serializers and de-serializers for many different languages. However, the Prost team instead recommends compiling the Protocol Buffers schema directly within `build.rs`.
|
|
|
|
In this post, I'll give a quick tutorial on how I compiled my Protocol Buffers schema when I needed to depend on another package with its own PB messages.
|
|
|
|
Let's say I have a Rust package called `people`. It contains a file called `Person.proto` with the following contents:
|
|
|
|
```protobuf
|
|
syntax = "proto3";
|
|
package people;
|
|
|
|
message Employee {
|
|
string name = 1;
|
|
string position = 2;
|
|
}
|
|
```
|
|
|
|
For sake of our example, we'll assume they exposed the data structures via a `proto` submodule. However, you can check what the module name actually is by looking at the package's codebase for something like
|
|
|
|
```rust
|
|
pub mod namespace_name_goes_here {
|
|
#![allow(missing_docs)]
|
|
include!(concat!(env!("OUT_DIR"), "/people.rs"));
|
|
}
|
|
```
|
|
|
|
Now to the package we're creating (which I'll call `company`), First, make sure that you added the `people` package to the Cargo.toml.
|
|
|
|
Then say that we have the following file `schemas/Team.proto`
|
|
|
|
```protobuf
|
|
syntax = "proto3";
|
|
package company;
|
|
|
|
import "Person.proto"
|
|
|
|
message Team {
|
|
repeated people.Employee members = 1;
|
|
}
|
|
```
|
|
|
|
To compile our new message, we need to tell `build.rs` where it can find both the `Person.proto` and the `Team.proto` schema files, as well as how to reference the messages in the `people` namespace.
|
|
|
|
```rust
|
|
fn main() {
|
|
// Other awesome build stuff
|
|
generate_schemas();
|
|
}
|
|
fn generate_schemas() {
|
|
let mut config = prost_build::Config::new();
|
|
// Map the people protocol buffer namespace to the people::proto Rust module
|
|
config.extern_path(".people", "people::proto");
|
|
config
|
|
.compile_protos(
|
|
// Files we want to compile
|
|
&["./schema/Team.proto"],
|
|
// Folders where we can find our imports
|
|
&["./schema"],
|
|
)
|
|
.expect("Prost protobuf compilation error;");
|
|
}
|
|
```
|
|
|
|
The function `extern_path` takes two arguments, the first one is the name of the namespace within the Protocol Buffers schema, and the second argument is the namespace within Rust.
|
|
|
|
The first argument of `compile_protos` is the files that we want to compile, the second argument is the directories in which we can find our schemas.
|
|
|
|
Note that we import `People.proto` in our new Protocol Buffers schema. Currently the only way that I know to get this to work, is to manually copy the `.proto` file in the other package into your own application.
|
|
|
|
There you have it! Next you can include the generated output into your Rust application. If you know of a better way to include external schemas without copying the schemas, please reach out.
|