From d8d9427e02606304ed673e4e0e8f85bdae59bbc9 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 30 Sep 2026 16:19:56 +0800 Subject: [PATCH 1/2] codegen: skip rustfmt for generated mod.rs Add a file-level rustfmt skip attribute below the generated marker when creating or updating mod.rs. Preserve existing declarations, comments, and attributes without duplicating the generated header. Cover fresh indexes and indexes previously written by rust-protobuf. Signed-off-by: Tim Zhang --- compiler/src/codegen.rs | 41 ++++++++++++++++++++++--------- ttrpc-codegen/tests/well_known.rs | 6 ++++- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/compiler/src/codegen.rs b/compiler/src/codegen.rs index 4a4560a1..c70552ae 100644 --- a/compiler/src/codegen.rs +++ b/compiler/src/codegen.rs @@ -743,7 +743,8 @@ pub fn gen( /// Generates ttrpc service files and writes them to `out_dir`. /// /// When [`Customize::gen_mod`](crate::Customize::gen_mod) is enabled, this function also creates -/// or updates `mod.rs` without discarding existing module declarations. +/// or updates `mod.rs` without discarding existing module declarations. Generated indexes opt out +/// of rustfmt, and existing comments and attributes retain their order. /// /// # Errors /// @@ -762,13 +763,18 @@ pub fn gen_and_write( if customize.gen_mod { let file_path = out_dir.join("mod.rs"); - let mut set = HashSet::new(); - let mut lines = Vec::new(); + let generated = "// @generated"; + let rustfmt_skip = "#![cfg_attr(rustfmt, rustfmt::skip)]"; + let mut lines = vec![generated.to_owned(), rustfmt_skip.to_owned()]; + let mut set: HashSet<_> = lines.iter().cloned().collect(); // Preserve existing order so comments and attributes stay with their modules. if let Ok(file) = File::open(&file_path) { let reader = io::BufReader::new(file); for line in reader.lines() { let line = line?; + if line == generated || line == rustfmt_skip { + continue; + } set.insert(line.clone()); lines.push(line); } @@ -842,7 +848,7 @@ mod tests { use super::*; #[test] - fn generated_mod_rs_is_stable_and_preserves_existing_lines() { + fn generated_mod_rs_skips_rustfmt_and_preserves_existing_lines() { let descriptors: Vec<_> = ["zeta.proto", "alpha.proto"] .iter() .map(|&name| FileDescriptorProto { @@ -858,9 +864,26 @@ mod tests { gen_mod: true, ..Default::default() }; - let existing = "// @generated\n\n// Keep this module gated.\n#[cfg(unix)]\npub mod custom;\n\n#[cfg(unix)]\npub mod another;\npub mod alpha_ttrpc;\n"; - - for initial in [None, Some(existing)] { + let existing = "\n// Keep this module gated.\n#[cfg(unix)]\npub mod custom;\n\n#[cfg(unix)]\npub mod another;\npub mod alpha_ttrpc;\n"; + let protobuf_modules = "\npub mod alpha;\npub mod zeta;\n"; + let header = "// @generated\n#![cfg_attr(rustfmt, rustfmt::skip)]\n"; + let existing_index = format!("// @generated\n{existing}"); + let protobuf_index = format!("// @generated\n{protobuf_modules}"); + + for (initial, expected) in [ + ( + None, + format!("{header}pub mod alpha_ttrpc;\npub mod zeta_ttrpc;\n"), + ), + ( + Some(existing_index.as_str()), + format!("{header}{existing}pub mod zeta_ttrpc;\n"), + ), + ( + Some(protobuf_index.as_str()), + format!("{header}{protobuf_modules}pub mod alpha_ttrpc;\npub mod zeta_ttrpc;\n"), + ), + ] { let dir = tempfile::tempdir().unwrap(); let path = dir.path().join("mod.rs"); if let Some(contents) = initial { @@ -872,10 +895,6 @@ mod tests { "alpha.proto".to_owned(), ]; gen_and_write(&descriptors, &inputs, dir.path(), &customize).unwrap(); - let expected = match initial { - Some(contents) => format!("{contents}pub mod zeta_ttrpc;\n"), - None => "pub mod alpha_ttrpc;\npub mod zeta_ttrpc;\n".to_owned(), - }; assert_eq!(fs::read_to_string(&path).unwrap(), expected); inputs.reverse(); diff --git a/ttrpc-codegen/tests/well_known.rs b/ttrpc-codegen/tests/well_known.rs index 8b37eeec..142d3fda 100644 --- a/ttrpc-codegen/tests/well_known.rs +++ b/ttrpc-codegen/tests/well_known.rs @@ -3,7 +3,7 @@ use std::fs; use std::path::{Path, PathBuf}; use tempfile::TempDir; -use ttrpc_codegen::{parse_and_typecheck, Codegen, Customize}; +use ttrpc_codegen::{parse_and_typecheck, Codegen, Customize, ProtobufCustomize}; fn proto_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/protos") @@ -46,11 +46,15 @@ fn generates_runtime_paths_for_embedded_types() { .rust_protobuf() .customize(Customize { async_all, + gen_mod: true, ..Default::default() }) + .rust_protobuf_customize(ProtobufCustomize::default().gen_mod_rs(true)) .run() .unwrap(); + let modules = fs::read_to_string(output.path().join("mod.rs")).unwrap(); + assert!(modules.starts_with("// @generated\n#![cfg_attr(rustfmt, rustfmt::skip)]\n")); let messages = fs::read_to_string(output.path().join("well_known.rs")).unwrap(); let services = fs::read_to_string(output.path().join("well_known_ttrpc.rs")).unwrap(); let timestamp = "::protobuf::well_known_types::timestamp::Timestamp"; From c51a97bd92ad982f3a09a8f4167d0e7422670e8d Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 30 Sep 2026 16:43:40 +0800 Subject: [PATCH 2/2] example: stop tracking generated mod.rs Remove the generated sync and async module indexes from version control. Keep the handwritten protocol entry point tracked and ignore regenerated indexes alongside the other generated bindings. Signed-off-by: Tim Zhang --- .gitignore | 2 +- example/protocols/asynchronous/mod.rs | 16 ---------------- example/protocols/sync/mod.rs | 12 ------------ 3 files changed, 1 insertion(+), 29 deletions(-) delete mode 100644 example/protocols/asynchronous/mod.rs delete mode 100644 example/protocols/sync/mod.rs diff --git a/.gitignore b/.gitignore index 305adf30..1ded98ed 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ Cargo.lock .idea *.o example/protocols/**/*.rs -!example/protocols/**/mod.rs +!example/protocols/mod.rs example-prost/protocols/**/*.rs !example-prost/protocols/**/mod.rs src/ttrpc.rs diff --git a/example/protocols/asynchronous/mod.rs b/example/protocols/asynchronous/mod.rs deleted file mode 100644 index c142ea64..00000000 --- a/example/protocols/asynchronous/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// @generated - -pub mod agent; -pub mod empty; -pub mod gogo; -pub mod health; -pub mod oci; -pub mod streaming; -pub mod types; -pub mod well_known; -pub mod well_known_streaming; -pub mod agent_ttrpc; -pub mod health_ttrpc; -pub mod streaming_ttrpc; -pub mod well_known_streaming_ttrpc; -pub mod well_known_ttrpc; diff --git a/example/protocols/sync/mod.rs b/example/protocols/sync/mod.rs deleted file mode 100644 index 2b34e668..00000000 --- a/example/protocols/sync/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -// @generated - -pub mod agent; -pub mod empty; -pub mod gogo; -pub mod health; -pub mod oci; -pub mod types; -pub mod well_known; -pub mod agent_ttrpc; -pub mod health_ttrpc; -pub mod well_known_ttrpc;