Skip to main content

oxiproto_codegen/
options.rs

1#![forbid(unsafe_code)]
2
3//! Code-generation options and error types.
4
5use std::collections::BTreeMap;
6
7/// Options controlling code generation from a `FileDescriptorSet`.
8#[derive(Debug, Clone)]
9pub struct CodegenOptions {
10    /// Generate doc comments from proto source info (default: true)
11    pub generate_docs: bool,
12    /// Generate `Default` impls for enums (default: true)
13    pub generate_default: bool,
14    /// Use `#[deprecated]` for deprecated fields/messages/enums (default: true)
15    pub generate_deprecated: bool,
16    /// Use `BTreeMap` for proto map fields instead of `HashMap` (default: false)
17    pub btree_map: bool,
18    /// Alias for `btree_map` kept for backward compat with existing tests
19    pub use_btree_map: bool,
20    /// Emit `pub mod` hierarchy matching the proto package structure (default: true).
21    /// When false, all types are emitted flat (no module nesting).
22    pub package_namespacing: bool,
23    /// Per-type custom attributes. Key: fully-qualified proto type name.
24    /// Value: list of attribute strings (e.g., `["#[derive(serde::Serialize)]"]`).
25    pub type_attributes: BTreeMap<String, Vec<String>>,
26    /// Per-field custom attributes. Key: "TypeName.field_name".
27    /// Value: list of attribute strings.
28    pub field_attributes: BTreeMap<String, Vec<String>>,
29    /// Emit `impl OxiMessage for T` + `impl OxiName for T` blocks (default: false).
30    /// Requires `oxiproto-core` as a dependency of the crate using generated code.
31    pub emit_oxi_message_impl: bool,
32    /// Use prettyplease to format generated code (requires `format` feature).
33    pub format_output: bool,
34    /// Emit `pub trait …` service definitions (default: true).
35    /// Set to `false` to suppress service-trait emission (e.g. `--grpc=false` in the CLI).
36    pub emit_services: bool,
37    /// Emit self-contained `to_json`/`from_json` methods on generated types
38    /// (canonical Protobuf-JSON mapping). Requires `serde_json` and `base64`
39    /// in the consumer crate. Default: false.
40    pub emit_json: bool,
41    /// Emit a `FooBuilder` struct with fluent setters for each message (default: false).
42    pub emit_builder: bool,
43    /// Emit a `to_text_format() -> String` method on each generated message struct (default: false).
44    pub emit_text_format: bool,
45}
46
47impl Default for CodegenOptions {
48    fn default() -> Self {
49        Self::new()
50    }
51}
52
53impl CodegenOptions {
54    /// Create options with sensible proto3 defaults.
55    pub fn new() -> Self {
56        Self {
57            generate_docs: true,
58            generate_default: true,
59            generate_deprecated: true,
60            btree_map: false,
61            use_btree_map: false,
62            // Default false for backward compatibility with existing tests and users.
63            // Set to true to emit `pub mod` hierarchy matching the proto package.
64            package_namespacing: false,
65            type_attributes: BTreeMap::new(),
66            field_attributes: BTreeMap::new(),
67            emit_oxi_message_impl: false,
68            format_output: false,
69            emit_services: true,
70            emit_json: false,
71            emit_builder: false,
72            emit_text_format: false,
73        }
74    }
75
76    /// Returns true if BTreeMap should be used for map fields.
77    pub fn use_btree_map_effective(&self) -> bool {
78        self.btree_map || self.use_btree_map
79    }
80}
81
82/// Errors produced during code generation.
83#[derive(Debug)]
84pub enum CodegenError {
85    /// A required descriptor field is missing or invalid.
86    InvalidDescriptor(String),
87    /// An I/O operation failed.
88    Io(std::io::Error),
89    /// A `syn` parse error (only with `format` feature).
90    #[cfg(feature = "format")]
91    Parse(syn::Error),
92}
93
94impl std::fmt::Display for CodegenError {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        match self {
97            CodegenError::InvalidDescriptor(s) => write!(f, "invalid descriptor: {s}"),
98            CodegenError::Io(e) => write!(f, "I/O error: {e}"),
99            #[cfg(feature = "format")]
100            CodegenError::Parse(e) => write!(f, "parse error: {e}"),
101        }
102    }
103}
104
105impl std::error::Error for CodegenError {
106    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
107        match self {
108            CodegenError::Io(e) => Some(e),
109            CodegenError::InvalidDescriptor(_) => None,
110            #[cfg(feature = "format")]
111            CodegenError::Parse(e) => Some(e),
112        }
113    }
114}
115
116impl From<std::io::Error> for CodegenError {
117    fn from(e: std::io::Error) -> Self {
118        CodegenError::Io(e)
119    }
120}
121
122impl From<oxiproto_core::OxiProtoError> for CodegenError {
123    fn from(e: oxiproto_core::OxiProtoError) -> Self {
124        CodegenError::InvalidDescriptor(e.to_string())
125    }
126}
127
128impl From<CodegenError> for oxiproto_core::OxiProtoError {
129    fn from(e: CodegenError) -> Self {
130        oxiproto_core::OxiProtoError::CodegenError(e.to_string())
131    }
132}