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}