Skip to main content

oxiproto_codegen/
lib.rs

1#![forbid(unsafe_code)]
2
3//! `oxiproto-codegen` — Generate plain Rust source code from a `FileDescriptorSet`.
4//!
5//! This crate walks a `prost_types::FileDescriptorSet` and emits plain Rust
6//! structs and enums — no prost derive, no gRPC stubs, no validators.
7//!
8//! ## Quick start
9//!
10//! ```no_run
11//! use prost_types::FileDescriptorSet;
12//!
13//! let fds: FileDescriptorSet = /* parse your .proto */ Default::default();
14//! let rust_src = oxiproto_codegen::generate(&fds).expect("codegen failed");
15//! println!("{rust_src}");
16//! ```
17
18pub(crate) mod builder_impl;
19mod emit;
20mod format;
21mod json_impl;
22mod message_impl;
23mod options;
24pub(crate) mod text_impl;
25pub(crate) mod type_registry;
26pub mod wkt_map;
27
28pub use options::{CodegenError, CodegenOptions};
29
30pub use emit::{emit_file_descriptor_set, emit_file_descriptor_set_with_options, ModuleTree};
31
32/// Generate Rust source code from a `FileDescriptorSet`.
33///
34/// Returns a `String` of Rust source containing `struct` and `enum` definitions
35/// for every message and enum found in the descriptor set.  Fields are mapped
36/// to plain Rust types (no `prost` derive macros).
37pub fn generate(fds: &prost_types::FileDescriptorSet) -> Result<String, CodegenError> {
38    emit::emit_file_descriptor_set(fds)
39}
40
41/// Generate Rust source code with custom codegen options.
42///
43/// This allows enabling additional features like doc comment generation,
44/// `Default` impls, deprecation attributes, and BTreeMap for map fields.
45pub fn generate_with_options(
46    fds: &prost_types::FileDescriptorSet,
47    options: &CodegenOptions,
48) -> Result<String, CodegenError> {
49    let code = emit::emit_file_descriptor_set_with_options(fds, options)?;
50    #[cfg(feature = "format")]
51    let code = if options.format_output {
52        crate::format::format_source(&code)?
53    } else {
54        code
55    };
56    Ok(code)
57}
58
59/// Generate a structured module tree from a `FileDescriptorSet`.
60///
61/// Unlike [`generate_with_options`] which returns a flat `String`,
62/// this returns a [`ModuleTree`] that preserves the package hierarchy,
63/// enabling per-package or per-file output.
64///
65/// # Errors
66///
67/// Returns a [`CodegenError`] if the descriptor set is invalid.
68pub fn generate_module(
69    fds: &prost_types::FileDescriptorSet,
70    options: &CodegenOptions,
71) -> Result<ModuleTree, CodegenError> {
72    emit::generate_module_tree(fds, options)
73}
74
75/// Write generated code to a file path.
76///
77/// Equivalent to calling [`generate`] and then writing the resulting string to
78/// `path`.
79pub fn generate_to_file(
80    fds: &prost_types::FileDescriptorSet,
81    path: &std::path::Path,
82) -> Result<(), CodegenError> {
83    let code = generate(fds)?;
84    std::fs::write(path, code).map_err(CodegenError::Io)
85}
86
87/// Write generated code to a file path with custom options.
88pub fn generate_to_file_with_options(
89    fds: &prost_types::FileDescriptorSet,
90    path: &std::path::Path,
91    options: &CodegenOptions,
92) -> Result<(), CodegenError> {
93    let code = generate_with_options(fds, options)?;
94    std::fs::write(path, code).map_err(CodegenError::Io)
95}
96
97/// Stream generated code into any [`std::io::Write`] sink.
98///
99/// This is the lowest-allocation path: it generates the Rust source and
100/// writes it directly to `writer` without building an intermediate `String`
101/// copy beyond the one produced by `generate_with_options`.
102///
103/// # Note on streaming
104///
105/// Internally the code generator builds a `String` via string concatenation.
106/// This function writes that single buffer to `writer` without an extra copy,
107/// making it preferable to `generate_with_options` when the caller is writing
108/// to a file, socket, or other I/O sink.
109///
110/// For an in-memory buffer prefer [`generate_with_options`] directly.
111///
112/// # Errors
113///
114/// Returns [`CodegenError`] on descriptor errors or on I/O failure.
115pub fn generate_to_writer<W: std::io::Write>(
116    fds: &prost_types::FileDescriptorSet,
117    options: &CodegenOptions,
118    writer: &mut W,
119) -> Result<(), CodegenError> {
120    let code = generate_with_options(fds, options)?;
121    writer.write_all(code.as_bytes()).map_err(CodegenError::Io)
122}
123
124/// Stream the default generated output into any [`std::io::Write`] sink.
125///
126/// Convenience wrapper around [`generate_to_writer`] using default
127/// [`CodegenOptions`].
128pub fn generate_to_writer_default<W: std::io::Write>(
129    fds: &prost_types::FileDescriptorSet,
130    writer: &mut W,
131) -> Result<(), CodegenError> {
132    generate_to_writer(fds, &CodegenOptions::default(), writer)
133}