From 3ea9f408113e3317cbc509abcd99dfa3bdfc9d84 Mon Sep 17 00:00:00 2001 From: Maxi Barmetler Date: Wed, 13 Mar 2024 22:57:56 +0100 Subject: [PATCH 1/9] fix #1001 and add tests --- prost-build/src/lib.rs | 25 ++++++++ tests/src/build.rs | 30 +++++++++ tests/src/complex_package_structure/mod.rs | 61 +++++++++++++++++++ .../proto/.editorconfig | 3 + .../proto/post/content.proto | 13 ++++ .../proto/post/post.proto | 17 ++++++ .../proto/std/time.proto | 6 ++ .../proto/user/user.proto | 13 ++++ .../proto/wrong/image.proto | 12 ++++ tests/src/lib.rs | 4 ++ tests/src/no_package_with_message.proto | 5 ++ tests/src/no_package_with_message.rs | 11 ++++ 12 files changed, 200 insertions(+) create mode 100644 tests/src/complex_package_structure/mod.rs create mode 100644 tests/src/complex_package_structure/proto/.editorconfig create mode 100644 tests/src/complex_package_structure/proto/post/content.proto create mode 100644 tests/src/complex_package_structure/proto/post/post.proto create mode 100644 tests/src/complex_package_structure/proto/std/time.proto create mode 100644 tests/src/complex_package_structure/proto/user/user.proto create mode 100644 tests/src/complex_package_structure/proto/wrong/image.proto create mode 100644 tests/src/no_package_with_message.proto create mode 100644 tests/src/no_package_with_message.rs diff --git a/prost-build/src/lib.rs b/prost-build/src/lib.rs index 992efd4c8..c89d34e07 100644 --- a/prost-build/src/lib.rs +++ b/prost-build/src/lib.rs @@ -1174,6 +1174,31 @@ impl Config { let mut written = 0; entries.sort(); + if depth == 0 { + let (empty, remaining): (Vec<&Module>, Vec<&Module>) = + entries.into_iter().partition(|m| m.is_empty()); + for _ in empty { + if basepath.is_some() { + self.write_line( + outfile, + depth, + &format!("include!(\"{}.rs\");", self.default_package_filename), + )?; + } else { + self.write_line( + outfile, + depth, + &format!( + "include!(concat!(env!(\"OUT_DIR\"), \"/{}.rs\"));", + self.default_package_filename + ), + )?; + } + written += 1; + } + entries = remaining; + } + while !entries.is_empty() { let modident = entries[0].part(depth); let matching: Vec<&Module> = entries diff --git a/tests/src/build.rs b/tests/src/build.rs index e2b95e6c4..63e6ea135 100644 --- a/tests/src/build.rs +++ b/tests/src/build.rs @@ -146,6 +146,36 @@ fn main() { .compile_protos(&[src.join("well_known_types.proto")], includes) .unwrap(); + { + let out = std::env::var("OUT_DIR").unwrap(); + let out_path = PathBuf::from(out).join("no_package"); + + std::fs::create_dir_all(&out_path).unwrap(); + + prost_build::Config::new() + .out_dir(out_path) + .include_file("_includes.rs") + .compile_protos(&[src.join("no_package_with_message.proto")], includes) + .unwrap(); + } + + { + let out = std::env::var("OUT_DIR").unwrap(); + let out_path = PathBuf::from(out).join("complex_package_structure"); + + std::fs::create_dir_all(&out_path).unwrap(); + + prost_build::Config::new() + .out_dir(out_path) + .include_file("__.rs") + .default_package_filename("__.default") + .compile_protos( + &[src.join("complex_package_structure/proto/post/post.proto")], + &[src.join("complex_package_structure/proto")], + ) + .unwrap(); + } + config .compile_protos( &[src.join("packages/widget_factory.proto")], diff --git a/tests/src/complex_package_structure/mod.rs b/tests/src/complex_package_structure/mod.rs new file mode 100644 index 000000000..3f45fa016 --- /dev/null +++ b/tests/src/complex_package_structure/mod.rs @@ -0,0 +1,61 @@ +use self::proto::image::Image; +use self::proto::post::content::post_content_fragment; +use self::proto::post::content::PostContentFragment; +use self::proto::post::Post; +use self::proto::user::User; +use self::proto::Timestamp; + +mod proto { + include!(concat!(env!("OUT_DIR"), "/complex_package_structure/__.rs")); +} + +#[test] +fn test_complex_package_structure() { + let user = User { + id: "69a4cd96-b956-4fb1-9a97-b222eac33b8a".to_string(), + name: "Test User".to_string(), + created_at: Some(Timestamp { + seconds: 1710366135, + nanos: 0, + }), + ..User::default() + }; + let posts = vec![ + Post::default(), + Post { + id: "aa1e751f-e287-4c6e-aa0f-f838f96a1a60".to_string(), + author: Some(user), + content: vec![ + PostContentFragment { + content: Some(post_content_fragment::Content::Text( + "Hello, world!".to_string(), + )), + }, + PostContentFragment { + content: Some(post_content_fragment::Content::Image(Image { + name: "doggo.jpg".to_string(), + description: Some("A dog".to_string()), + data: vec![0, 1, 2, 3], + })), + }, + PostContentFragment { + content: Some(post_content_fragment::Content::Link( + "https://example.com".to_string(), + )), + }, + ], + ..Post::default() + }, + Post::default(), + ]; + assert_eq!(posts.len(), 3); + assert_eq!(posts[1].content.len(), 3); + if let PostContentFragment { + content: Some(post_content_fragment::Content::Image(Image { name, .. })), + } = &posts[1].content[1] + { + assert_eq!(name, "doggo.jpg"); + } else { + assert!(false, "Expected an image") + } +} diff --git a/tests/src/complex_package_structure/proto/.editorconfig b/tests/src/complex_package_structure/proto/.editorconfig new file mode 100644 index 000000000..bd57d0bf1 --- /dev/null +++ b/tests/src/complex_package_structure/proto/.editorconfig @@ -0,0 +1,3 @@ +[*] +ij_protobuf_keep_blank_lines_in_code = 0 +insert_final_newline = true diff --git a/tests/src/complex_package_structure/proto/post/content.proto b/tests/src/complex_package_structure/proto/post/content.proto new file mode 100644 index 000000000..d2e2b7b46 --- /dev/null +++ b/tests/src/complex_package_structure/proto/post/content.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package post.content; + +import "wrong/image.proto"; + +message PostContentFragment { + oneof content { + string text = 1; + image.Image image = 2; + string link = 3; + } +} diff --git a/tests/src/complex_package_structure/proto/post/post.proto b/tests/src/complex_package_structure/proto/post/post.proto new file mode 100644 index 000000000..8c30b005f --- /dev/null +++ b/tests/src/complex_package_structure/proto/post/post.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package post; + +import "std/time.proto"; +import "user/user.proto"; +import "post/content.proto"; + +message Post { + string id = 1; + string title = 2; + reserved 3; + user.User author = 4; + Timestamp created_at = 5; + Timestamp updated_at = 6; + repeated content.PostContentFragment content = 7; +} diff --git a/tests/src/complex_package_structure/proto/std/time.proto b/tests/src/complex_package_structure/proto/std/time.proto new file mode 100644 index 000000000..877615dce --- /dev/null +++ b/tests/src/complex_package_structure/proto/std/time.proto @@ -0,0 +1,6 @@ +syntax = "proto3"; + +message Timestamp { + int64 seconds = 1; + int32 nanos = 2; +} diff --git a/tests/src/complex_package_structure/proto/user/user.proto b/tests/src/complex_package_structure/proto/user/user.proto new file mode 100644 index 000000000..25ced1255 --- /dev/null +++ b/tests/src/complex_package_structure/proto/user/user.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package user; + +import "std/time.proto"; + +message User { + string id = 1; + Timestamp created_at = 2; + Timestamp updated_at = 3; + string name = 4; + string email = 5; +} diff --git a/tests/src/complex_package_structure/proto/wrong/image.proto b/tests/src/complex_package_structure/proto/wrong/image.proto new file mode 100644 index 000000000..1aac737f5 --- /dev/null +++ b/tests/src/complex_package_structure/proto/wrong/image.proto @@ -0,0 +1,12 @@ +// This file makes sure that the file path of the proto file has nothing to do with the package name, +// therefore testing the validity of write_includes. + +syntax = "proto3"; + +package image; + +message Image { + string name = 1; + optional string description = 2; + bytes data = 3; +} diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 7d3d94867..5dd5f1c60 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -33,6 +33,8 @@ pub mod unittest; #[cfg(test)] mod bootstrap; #[cfg(test)] +mod complex_package_structure; +#[cfg(test)] mod debug; #[cfg(test)] mod deprecated_field; @@ -41,6 +43,8 @@ mod generic_derive; #[cfg(test)] mod message_encoding; #[cfg(test)] +mod no_package_with_message; +#[cfg(test)] mod no_unused_results; #[cfg(test)] #[cfg(feature = "std")] diff --git a/tests/src/no_package_with_message.proto b/tests/src/no_package_with_message.proto new file mode 100644 index 000000000..c92e04ff4 --- /dev/null +++ b/tests/src/no_package_with_message.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message NoPackageWithMessageExampleMsg { + string some_field = 1; +} diff --git a/tests/src/no_package_with_message.rs b/tests/src/no_package_with_message.rs new file mode 100644 index 000000000..70785feb6 --- /dev/null +++ b/tests/src/no_package_with_message.rs @@ -0,0 +1,11 @@ +mod proto { + include!(concat!(env!("OUT_DIR"), "/no_package/_includes.rs")); +} + +#[test] +fn it_works() { + assert_eq!( + proto::NoPackageWithMessageExampleMsg::default(), + proto::NoPackageWithMessageExampleMsg::default() + ); +} From ae360ef8859820c9d6a1b2c5eeb2fbe4ed2b037d Mon Sep 17 00:00:00 2001 From: Maxi Barmetler Date: Wed, 13 Mar 2024 23:52:05 +0100 Subject: [PATCH 2/9] add alloc:: imports --- tests/src/complex_package_structure/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/src/complex_package_structure/mod.rs b/tests/src/complex_package_structure/mod.rs index 3f45fa016..0b2a03648 100644 --- a/tests/src/complex_package_structure/mod.rs +++ b/tests/src/complex_package_structure/mod.rs @@ -1,3 +1,5 @@ +use alloc::{string::ToString, vec}; + use self::proto::image::Image; use self::proto::post::content::post_content_fragment; use self::proto::post::content::PostContentFragment; From 511fdd5fef76e5b0d25dcaebb4b4e661b99aa081 Mon Sep 17 00:00:00 2001 From: Maxi Barmetler Date: Sat, 6 Apr 2024 01:25:11 +0200 Subject: [PATCH 3/9] rewrite write_includes to allow for empty modules. --- prost-build/src/lib.rs | 171 +++++++++++++++++++++++------------------ 1 file changed, 95 insertions(+), 76 deletions(-) diff --git a/prost-build/src/lib.rs b/prost-build/src/lib.rs index e5c608869..a6ea8ef64 100644 --- a/prost-build/src/lib.rs +++ b/prost-build/src/lib.rs @@ -1029,8 +1029,8 @@ impl Config { self.write_includes( modules.keys().collect(), &mut file, - 0, if target_is_env { None } else { Some(&target) }, + &file_names, )?; file.flush()?; } @@ -1160,90 +1160,56 @@ impl Config { fn write_includes( &self, - mut entries: Vec<&Module>, - outfile: &mut fs::File, - depth: usize, + mut modules: Vec<&Module>, + outfile: &mut impl Write, basepath: Option<&PathBuf>, - ) -> Result { - let mut written = 0; - entries.sort(); - - if depth == 0 { - let (empty, remaining): (Vec<&Module>, Vec<&Module>) = - entries.into_iter().partition(|m| m.is_empty()); - for _ in empty { - if basepath.is_some() { - self.write_line( - outfile, - depth, - &format!("include!(\"{}.rs\");", self.default_package_filename), - )?; - } else { - self.write_line( - outfile, - depth, - &format!( - "include!(concat!(env!(\"OUT_DIR\"), \"/{}.rs\"));", - self.default_package_filename - ), - )?; - } - written += 1; - } - entries = remaining; - } + file_names: &HashMap, + ) -> Result<()> { + modules.sort(); - while !entries.is_empty() { - let modident = entries[0].part(depth); - let matching: Vec<&Module> = entries - .iter() - .filter(|&v| v.part(depth) == modident) - .copied() - .collect(); - { - // Will NLL sort this mess out? - let _temp = entries - .drain(..) - .filter(|&v| v.part(depth) != modident) - .collect(); - entries = _temp; + let mut stack = Vec::new(); + + for module in modules { + while !module.components.starts_with(&stack) { + stack.pop(); + self.write_line(outfile, stack.len(), "}")?; } - self.write_line(outfile, depth, &format!("pub mod {} {{", modident))?; - let subwritten = self.write_includes( - matching - .iter() - .filter(|v| v.len() > depth + 1) - .copied() - .collect(), - outfile, - depth + 1, - basepath, - )?; - written += subwritten; - if subwritten != matching.len() { - let modname = matching[0].to_partial_file_name(..=depth); - if basepath.is_some() { - self.write_line( - outfile, - depth + 1, - &format!("include!(\"{}.rs\");", modname), - )?; - } else { - self.write_line( - outfile, - depth + 1, - &format!("include!(concat!(env!(\"OUT_DIR\"), \"/{}.rs\"));", modname), - )?; - } - written += 1; + while stack.len() < module.components.len() { + self.write_line( + outfile, + stack.len(), + &format!("pub mod {} {{", module.part(stack.len())), + )?; + stack.push(module.part(stack.len()).to_owned()); } + let file_name = file_names + .get(module) + .expect("every module should have a filename"); + + if basepath.is_some() { + self.write_line( + outfile, + stack.len(), + &format!("include!(\"{}\");", file_name), + )?; + } else { + self.write_line( + outfile, + stack.len(), + &format!("include!(concat!(env!(\"OUT_DIR\"), \"/{}\"));", file_name), + )?; + } + } + + for depth in (0..stack.len()).rev() { self.write_line(outfile, depth, "}")?; } - Ok(written) + + Ok(()) } - fn write_line(&self, outfile: &mut fs::File, depth: usize, line: &str) -> Result<()> { + fn write_line(&self, outfile: &mut impl Write, depth: usize, line: &str) -> Result<()> { outfile.write_all(format!("{}{}\n", (" ").to_owned().repeat(depth), line).as_bytes()) } @@ -1858,4 +1824,57 @@ mod tests { f.read_to_string(&mut content).unwrap(); content } + + #[test] + fn test_write_includes() { + let modules = [ + Module::from_protobuf_package_name("foo.bar.baz"), + Module::from_protobuf_package_name(""), + Module::from_protobuf_package_name("foo.bar"), + Module::from_protobuf_package_name("bar"), + Module::from_protobuf_package_name("foo"), + Module::from_protobuf_package_name("foo.bar.qux"), + Module::from_protobuf_package_name("foo.bar.a.b.c"), + ]; + + let file_names = modules + .iter() + .map(|m| (m.clone(), m.to_file_name_or("_.default"))) + .collect(); + + let mut buf = Vec::new(); + Config::new() + .default_package_filename("_.default") + .write_includes(modules.iter().collect(), &mut buf, None, &file_names) + .unwrap(); + let expected = [ + r#"include!(concat!(env!("OUT_DIR"), "/_.default.rs"));"#, + r#"pub mod bar {"#, + r#" include!(concat!(env!("OUT_DIR"), "/bar.rs"));"#, + r#"}"#, + r#"pub mod foo {"#, + r#" include!(concat!(env!("OUT_DIR"), "/foo.rs"));"#, + r#" pub mod bar {"#, + r#" include!(concat!(env!("OUT_DIR"), "/foo.bar.rs"));"#, + r#" pub mod a {"#, + r#" pub mod b {"#, + r#" pub mod c {"#, + r#" include!(concat!(env!("OUT_DIR"), "/foo.bar.a.b.c.rs"));"#, + r#" }"#, + r#" }"#, + r#" }"#, + r#" pub mod baz {"#, + r#" include!(concat!(env!("OUT_DIR"), "/foo.bar.baz.rs"));"#, + r#" }"#, + r#" pub mod qux {"#, + r#" include!(concat!(env!("OUT_DIR"), "/foo.bar.qux.rs"));"#, + r#" }"#, + r#" }"#, + r#"}"#, + r#""#, + ] + .join("\n"); + let actual = String::from_utf8(buf).unwrap(); + assert_eq!(expected, actual); + } } From 4c52df92fea22fe7ea497d44fa88360590ec64b8 Mon Sep 17 00:00:00 2001 From: Maxi Barmetler Date: Fri, 12 Apr 2024 18:37:57 +0200 Subject: [PATCH 4/9] create test fixture for `write_includes` --- .../src/fixtures/write_includes/_.includes.rs | 23 +++++++++++++ prost-build/src/lib.rs | 32 +++---------------- 2 files changed, 27 insertions(+), 28 deletions(-) create mode 100644 prost-build/src/fixtures/write_includes/_.includes.rs diff --git a/prost-build/src/fixtures/write_includes/_.includes.rs b/prost-build/src/fixtures/write_includes/_.includes.rs new file mode 100644 index 000000000..99b555635 --- /dev/null +++ b/prost-build/src/fixtures/write_includes/_.includes.rs @@ -0,0 +1,23 @@ +include!(concat!(env!("OUT_DIR"), "/_.default.rs")); +pub mod bar { + include!(concat!(env!("OUT_DIR"), "/bar.rs")); +} +pub mod foo { + include!(concat!(env!("OUT_DIR"), "/foo.rs")); + pub mod bar { + include!(concat!(env!("OUT_DIR"), "/foo.bar.rs")); + pub mod a { + pub mod b { + pub mod c { + include!(concat!(env!("OUT_DIR"), "/foo.bar.a.b.c.rs")); + } + } + } + pub mod baz { + include!(concat!(env!("OUT_DIR"), "/foo.bar.baz.rs")); + } + pub mod qux { + include!(concat!(env!("OUT_DIR"), "/foo.bar.qux.rs")); + } + } +} diff --git a/prost-build/src/lib.rs b/prost-build/src/lib.rs index a6ea8ef64..3db5d1bc3 100644 --- a/prost-build/src/lib.rs +++ b/prost-build/src/lib.rs @@ -1398,6 +1398,8 @@ impl Module { self.components.is_empty() } + // TODO: remove if it stays unused + #[allow(dead_code)] fn to_partial_file_name(&self, range: RangeToInclusive) -> String { self.components[range].join(".") } @@ -1826,7 +1828,7 @@ mod tests { } #[test] - fn test_write_includes() { + fn write_includes() { let modules = [ Module::from_protobuf_package_name("foo.bar.baz"), Module::from_protobuf_package_name(""), @@ -1847,33 +1849,7 @@ mod tests { .default_package_filename("_.default") .write_includes(modules.iter().collect(), &mut buf, None, &file_names) .unwrap(); - let expected = [ - r#"include!(concat!(env!("OUT_DIR"), "/_.default.rs"));"#, - r#"pub mod bar {"#, - r#" include!(concat!(env!("OUT_DIR"), "/bar.rs"));"#, - r#"}"#, - r#"pub mod foo {"#, - r#" include!(concat!(env!("OUT_DIR"), "/foo.rs"));"#, - r#" pub mod bar {"#, - r#" include!(concat!(env!("OUT_DIR"), "/foo.bar.rs"));"#, - r#" pub mod a {"#, - r#" pub mod b {"#, - r#" pub mod c {"#, - r#" include!(concat!(env!("OUT_DIR"), "/foo.bar.a.b.c.rs"));"#, - r#" }"#, - r#" }"#, - r#" }"#, - r#" pub mod baz {"#, - r#" include!(concat!(env!("OUT_DIR"), "/foo.bar.baz.rs"));"#, - r#" }"#, - r#" pub mod qux {"#, - r#" include!(concat!(env!("OUT_DIR"), "/foo.bar.qux.rs"));"#, - r#" }"#, - r#" }"#, - r#"}"#, - r#""#, - ] - .join("\n"); + let expected = read_all_content("src/fixtures/write_includes/_.includes.rs"); let actual = String::from_utf8(buf).unwrap(); assert_eq!(expected, actual); } From 4ff26e53c2ec2d7211cbbfc8470861ed5a273ea4 Mon Sep 17 00:00:00 2001 From: Maxi Barmetler Date: Fri, 12 Apr 2024 21:08:14 +0200 Subject: [PATCH 5/9] fix lints, remove line feeds --- prost-build/src/lib.rs | 3 ++- tests/src/complex_package_structure/mod.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/prost-build/src/lib.rs b/prost-build/src/lib.rs index 3db5d1bc3..90fa2d560 100644 --- a/prost-build/src/lib.rs +++ b/prost-build/src/lib.rs @@ -1849,7 +1849,8 @@ mod tests { .default_package_filename("_.default") .write_includes(modules.iter().collect(), &mut buf, None, &file_names) .unwrap(); - let expected = read_all_content("src/fixtures/write_includes/_.includes.rs"); + let expected = + read_all_content("src/fixtures/write_includes/_.includes.rs").replace("\r\n", "\n"); let actual = String::from_utf8(buf).unwrap(); assert_eq!(expected, actual); } diff --git a/tests/src/complex_package_structure/mod.rs b/tests/src/complex_package_structure/mod.rs index 0b2a03648..e7249a7f4 100644 --- a/tests/src/complex_package_structure/mod.rs +++ b/tests/src/complex_package_structure/mod.rs @@ -58,6 +58,6 @@ fn test_complex_package_structure() { { assert_eq!(name, "doggo.jpg"); } else { - assert!(false, "Expected an image") + panic!("Expected an image") } } From 56c1a2fe052b21f2b3b2abb1d475b2981a534420 Mon Sep 17 00:00:00 2001 From: Maxi Barmetler Date: Fri, 26 Apr 2024 12:26:53 +0200 Subject: [PATCH 6/9] fixes after merge master --- prost-build/src/config.rs | 97 ++++++++++++++++++--------------------- prost-build/src/module.rs | 14 ++++-- 2 files changed, 53 insertions(+), 58 deletions(-) diff --git a/prost-build/src/config.rs b/prost-build/src/config.rs index 670c0befe..99b5addca 100644 --- a/prost-build/src/config.rs +++ b/prost-build/src/config.rs @@ -823,8 +823,8 @@ impl Config { self.write_includes( modules.keys().collect(), &mut file, - 0, if target_is_env { None } else { Some(&target) }, + &file_names, )?; file.flush()?; } @@ -952,67 +952,58 @@ impl Config { self.compile_fds(file_descriptor_set) } - fn write_includes( + pub(crate) fn write_includes( &self, - mut entries: Vec<&Module>, - outfile: &mut fs::File, - depth: usize, + mut modules: Vec<&Module>, + outfile: &mut impl Write, basepath: Option<&PathBuf>, - ) -> Result { - let mut written = 0; - entries.sort(); - - while !entries.is_empty() { - let modident = entries[0].part(depth); - let matching: Vec<&Module> = entries - .iter() - .filter(|&v| v.part(depth) == modident) - .copied() - .collect(); - { - // Will NLL sort this mess out? - let _temp = entries - .drain(..) - .filter(|&v| v.part(depth) != modident) - .collect(); - entries = _temp; + file_names: &HashMap, + ) -> Result<()> { + modules.sort(); + + let mut stack = Vec::new(); + + for module in modules { + while !module.starts_with(&stack) { + stack.pop(); + self.write_line(outfile, stack.len(), "}")?; } - self.write_line(outfile, depth, &format!("pub mod {} {{", modident))?; - let subwritten = self.write_includes( - matching - .iter() - .filter(|v| v.len() > depth + 1) - .copied() - .collect(), - outfile, - depth + 1, - basepath, - )?; - written += subwritten; - if subwritten != matching.len() { - let modname = matching[0].to_partial_file_name(..=depth); - if basepath.is_some() { - self.write_line( - outfile, - depth + 1, - &format!("include!(\"{}.rs\");", modname), - )?; - } else { - self.write_line( - outfile, - depth + 1, - &format!("include!(concat!(env!(\"OUT_DIR\"), \"/{}.rs\"));", modname), - )?; - } - written += 1; + while stack.len() < module.len() { + self.write_line( + outfile, + stack.len(), + &format!("pub mod {} {{", module.part(stack.len())), + )?; + stack.push(module.part(stack.len()).to_owned()); } + let file_name = file_names + .get(module) + .expect("every module should have a filename"); + + if basepath.is_some() { + self.write_line( + outfile, + stack.len(), + &format!("include!(\"{}\");", file_name), + )?; + } else { + self.write_line( + outfile, + stack.len(), + &format!("include!(concat!(env!(\"OUT_DIR\"), \"/{}\"));", file_name), + )?; + } + } + + for depth in (0..stack.len()).rev() { self.write_line(outfile, depth, "}")?; } - Ok(written) + + Ok(()) } - fn write_line(&self, outfile: &mut fs::File, depth: usize, line: &str) -> Result<()> { + fn write_line(&self, outfile: &mut impl Write, depth: usize, line: &str) -> Result<()> { outfile.write_all(format!("{}{}\n", (" ").to_owned().repeat(depth), line).as_bytes()) } diff --git a/prost-build/src/module.rs b/prost-build/src/module.rs index 21cab1163..f868a2a80 100644 --- a/prost-build/src/module.rs +++ b/prost-build/src/module.rs @@ -1,5 +1,4 @@ use std::fmt; -use std::ops::RangeToInclusive; use crate::ident::to_snake; @@ -40,6 +39,15 @@ impl Module { self.components.iter().map(|s| s.as_str()) } + #[must_use] + #[inline(always)] + pub fn starts_with(&self, needle: &[String]) -> bool + where + String: PartialEq, + { + self.components.starts_with(needle) + } + /// Format the module path into a filename for generated Rust code. /// /// If the module path is empty, `default` is used to provide the root of the filename. @@ -65,10 +73,6 @@ impl Module { self.components.is_empty() } - pub(crate) fn to_partial_file_name(&self, range: RangeToInclusive) -> String { - self.components[range].join(".") - } - pub(crate) fn part(&self, idx: usize) -> &str { self.components[idx].as_str() } From 8ea9ec98573b0ad6421b754f5bb790ae387e66bd Mon Sep 17 00:00:00 2001 From: Maxi Barmetler Date: Fri, 26 Apr 2024 12:41:45 +0200 Subject: [PATCH 7/9] remove some duplicate tests and alter existing ones to test write_includes --- tests/src/build.rs | 31 +-------- tests/src/complex_package_structure/mod.rs | 63 ------------------- .../proto/.editorconfig | 3 - .../proto/post/content.proto | 13 ---- .../proto/post/post.proto | 17 ----- .../proto/std/time.proto | 6 -- .../proto/user/user.proto | 13 ---- .../proto/wrong/image.proto | 12 ---- tests/src/lib.rs | 4 -- tests/src/no_package_with_message.proto | 5 -- tests/src/no_package_with_message.rs | 11 ---- tests/src/no_root_packages/mod.rs | 4 ++ 12 files changed, 5 insertions(+), 177 deletions(-) delete mode 100644 tests/src/complex_package_structure/mod.rs delete mode 100644 tests/src/complex_package_structure/proto/.editorconfig delete mode 100644 tests/src/complex_package_structure/proto/post/content.proto delete mode 100644 tests/src/complex_package_structure/proto/post/post.proto delete mode 100644 tests/src/complex_package_structure/proto/std/time.proto delete mode 100644 tests/src/complex_package_structure/proto/user/user.proto delete mode 100644 tests/src/complex_package_structure/proto/wrong/image.proto delete mode 100644 tests/src/no_package_with_message.proto delete mode 100644 tests/src/no_package_with_message.rs diff --git a/tests/src/build.rs b/tests/src/build.rs index ce080ec9a..0403d2603 100644 --- a/tests/src/build.rs +++ b/tests/src/build.rs @@ -150,36 +150,6 @@ fn main() { .compile_protos(&[src.join("well_known_types.proto")], includes) .unwrap(); - { - let out = std::env::var("OUT_DIR").unwrap(); - let out_path = PathBuf::from(out).join("no_package"); - - std::fs::create_dir_all(&out_path).unwrap(); - - prost_build::Config::new() - .out_dir(out_path) - .include_file("_includes.rs") - .compile_protos(&[src.join("no_package_with_message.proto")], includes) - .unwrap(); - } - - { - let out = std::env::var("OUT_DIR").unwrap(); - let out_path = PathBuf::from(out).join("complex_package_structure"); - - std::fs::create_dir_all(&out_path).unwrap(); - - prost_build::Config::new() - .out_dir(out_path) - .include_file("__.rs") - .default_package_filename("__.default") - .compile_protos( - &[src.join("complex_package_structure/proto/post/post.proto")], - &[src.join("complex_package_structure/proto")], - ) - .unwrap(); - } - config .compile_protos( &[src.join("packages/widget_factory.proto")], @@ -208,6 +178,7 @@ fn main() { no_root_packages_config .out_dir(&no_root_packages) .default_package_filename("__.default") + .include_file("__.include.rs") .compile_protos( &[src.join("no_root_packages/widget_factory.proto")], &[src.join("no_root_packages")], diff --git a/tests/src/complex_package_structure/mod.rs b/tests/src/complex_package_structure/mod.rs deleted file mode 100644 index e7249a7f4..000000000 --- a/tests/src/complex_package_structure/mod.rs +++ /dev/null @@ -1,63 +0,0 @@ -use alloc::{string::ToString, vec}; - -use self::proto::image::Image; -use self::proto::post::content::post_content_fragment; -use self::proto::post::content::PostContentFragment; -use self::proto::post::Post; -use self::proto::user::User; -use self::proto::Timestamp; - -mod proto { - include!(concat!(env!("OUT_DIR"), "/complex_package_structure/__.rs")); -} - -#[test] -fn test_complex_package_structure() { - let user = User { - id: "69a4cd96-b956-4fb1-9a97-b222eac33b8a".to_string(), - name: "Test User".to_string(), - created_at: Some(Timestamp { - seconds: 1710366135, - nanos: 0, - }), - ..User::default() - }; - let posts = vec![ - Post::default(), - Post { - id: "aa1e751f-e287-4c6e-aa0f-f838f96a1a60".to_string(), - author: Some(user), - content: vec![ - PostContentFragment { - content: Some(post_content_fragment::Content::Text( - "Hello, world!".to_string(), - )), - }, - PostContentFragment { - content: Some(post_content_fragment::Content::Image(Image { - name: "doggo.jpg".to_string(), - description: Some("A dog".to_string()), - data: vec![0, 1, 2, 3], - })), - }, - PostContentFragment { - content: Some(post_content_fragment::Content::Link( - "https://example.com".to_string(), - )), - }, - ], - ..Post::default() - }, - Post::default(), - ]; - assert_eq!(posts.len(), 3); - assert_eq!(posts[1].content.len(), 3); - if let PostContentFragment { - content: Some(post_content_fragment::Content::Image(Image { name, .. })), - } = &posts[1].content[1] - { - assert_eq!(name, "doggo.jpg"); - } else { - panic!("Expected an image") - } -} diff --git a/tests/src/complex_package_structure/proto/.editorconfig b/tests/src/complex_package_structure/proto/.editorconfig deleted file mode 100644 index bd57d0bf1..000000000 --- a/tests/src/complex_package_structure/proto/.editorconfig +++ /dev/null @@ -1,3 +0,0 @@ -[*] -ij_protobuf_keep_blank_lines_in_code = 0 -insert_final_newline = true diff --git a/tests/src/complex_package_structure/proto/post/content.proto b/tests/src/complex_package_structure/proto/post/content.proto deleted file mode 100644 index d2e2b7b46..000000000 --- a/tests/src/complex_package_structure/proto/post/content.proto +++ /dev/null @@ -1,13 +0,0 @@ -syntax = "proto3"; - -package post.content; - -import "wrong/image.proto"; - -message PostContentFragment { - oneof content { - string text = 1; - image.Image image = 2; - string link = 3; - } -} diff --git a/tests/src/complex_package_structure/proto/post/post.proto b/tests/src/complex_package_structure/proto/post/post.proto deleted file mode 100644 index 8c30b005f..000000000 --- a/tests/src/complex_package_structure/proto/post/post.proto +++ /dev/null @@ -1,17 +0,0 @@ -syntax = "proto3"; - -package post; - -import "std/time.proto"; -import "user/user.proto"; -import "post/content.proto"; - -message Post { - string id = 1; - string title = 2; - reserved 3; - user.User author = 4; - Timestamp created_at = 5; - Timestamp updated_at = 6; - repeated content.PostContentFragment content = 7; -} diff --git a/tests/src/complex_package_structure/proto/std/time.proto b/tests/src/complex_package_structure/proto/std/time.proto deleted file mode 100644 index 877615dce..000000000 --- a/tests/src/complex_package_structure/proto/std/time.proto +++ /dev/null @@ -1,6 +0,0 @@ -syntax = "proto3"; - -message Timestamp { - int64 seconds = 1; - int32 nanos = 2; -} diff --git a/tests/src/complex_package_structure/proto/user/user.proto b/tests/src/complex_package_structure/proto/user/user.proto deleted file mode 100644 index 25ced1255..000000000 --- a/tests/src/complex_package_structure/proto/user/user.proto +++ /dev/null @@ -1,13 +0,0 @@ -syntax = "proto3"; - -package user; - -import "std/time.proto"; - -message User { - string id = 1; - Timestamp created_at = 2; - Timestamp updated_at = 3; - string name = 4; - string email = 5; -} diff --git a/tests/src/complex_package_structure/proto/wrong/image.proto b/tests/src/complex_package_structure/proto/wrong/image.proto deleted file mode 100644 index 1aac737f5..000000000 --- a/tests/src/complex_package_structure/proto/wrong/image.proto +++ /dev/null @@ -1,12 +0,0 @@ -// This file makes sure that the file path of the proto file has nothing to do with the package name, -// therefore testing the validity of write_includes. - -syntax = "proto3"; - -package image; - -message Image { - string name = 1; - optional string description = 2; - bytes data = 3; -} diff --git a/tests/src/lib.rs b/tests/src/lib.rs index a4cf77790..00926afe0 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -33,8 +33,6 @@ pub mod unittest; #[cfg(test)] mod bootstrap; #[cfg(test)] -mod complex_package_structure; -#[cfg(test)] mod debug; #[cfg(test)] mod deprecated_field; @@ -45,8 +43,6 @@ mod generic_derive; #[cfg(test)] mod message_encoding; #[cfg(test)] -mod no_package_with_message; -#[cfg(test)] mod no_unused_results; #[cfg(test)] #[cfg(feature = "std")] diff --git a/tests/src/no_package_with_message.proto b/tests/src/no_package_with_message.proto deleted file mode 100644 index c92e04ff4..000000000 --- a/tests/src/no_package_with_message.proto +++ /dev/null @@ -1,5 +0,0 @@ -syntax = "proto3"; - -message NoPackageWithMessageExampleMsg { - string some_field = 1; -} diff --git a/tests/src/no_package_with_message.rs b/tests/src/no_package_with_message.rs deleted file mode 100644 index 70785feb6..000000000 --- a/tests/src/no_package_with_message.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod proto { - include!(concat!(env!("OUT_DIR"), "/no_package/_includes.rs")); -} - -#[test] -fn it_works() { - assert_eq!( - proto::NoPackageWithMessageExampleMsg::default(), - proto::NoPackageWithMessageExampleMsg::default() - ); -} diff --git a/tests/src/no_root_packages/mod.rs b/tests/src/no_root_packages/mod.rs index 2025eb983..b4c628760 100644 --- a/tests/src/no_root_packages/mod.rs +++ b/tests/src/no_root_packages/mod.rs @@ -16,6 +16,10 @@ pub mod widget { } } +pub mod generated_include { + include!(concat!(env!("OUT_DIR"), "/no_root_packages/__.include.rs")); +} + #[test] fn test() { use prost::Message; From 7b0ccb2f14f0c30efca526999bb1ba5e414f273a Mon Sep 17 00:00:00 2001 From: Maxi Barmetler Date: Fri, 26 Apr 2024 12:54:33 +0200 Subject: [PATCH 8/9] more test --- tests/src/no_root_packages/mod.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/src/no_root_packages/mod.rs b/tests/src/no_root_packages/mod.rs index b4c628760..7ef3b4c4e 100644 --- a/tests/src/no_root_packages/mod.rs +++ b/tests/src/no_root_packages/mod.rs @@ -48,3 +48,32 @@ fn test() { widget_factory.gizmo_inner = Some(gizmo::gizmo::Inner {}); assert_eq!(14, widget_factory.encoded_len()); } + +#[test] +fn generated_include() { + use prost::Message; + + let mut widget_factory = generated_include::widget::factory::WidgetFactory::default(); + assert_eq!(0, widget_factory.encoded_len()); + + widget_factory.inner = Some(generated_include::widget::factory::widget_factory::Inner {}); + assert_eq!(2, widget_factory.encoded_len()); + + widget_factory.root = Some(generated_include::Root {}); + assert_eq!(4, widget_factory.encoded_len()); + + widget_factory.root_inner = Some(generated_include::root::Inner {}); + assert_eq!(6, widget_factory.encoded_len()); + + widget_factory.widget = Some(generated_include::widget::Widget {}); + assert_eq!(8, widget_factory.encoded_len()); + + widget_factory.widget_inner = Some(generated_include::widget::widget::Inner {}); + assert_eq!(10, widget_factory.encoded_len()); + + widget_factory.gizmo = Some(generated_include::gizmo::Gizmo {}); + assert_eq!(12, widget_factory.encoded_len()); + + widget_factory.gizmo_inner = Some(generated_include::gizmo::gizmo::Inner {}); + assert_eq!(14, widget_factory.encoded_len()); +} From bfb08962918166a3773be9f1d25b80255251b1d0 Mon Sep 17 00:00:00 2001 From: Maxi Barmetler Date: Sat, 4 May 2024 20:29:52 +0200 Subject: [PATCH 9/9] module.rs Module::starts_with visibility --- prost-build/src/module.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prost-build/src/module.rs b/prost-build/src/module.rs index f868a2a80..02715c16e 100644 --- a/prost-build/src/module.rs +++ b/prost-build/src/module.rs @@ -41,7 +41,7 @@ impl Module { #[must_use] #[inline(always)] - pub fn starts_with(&self, needle: &[String]) -> bool + pub(crate) fn starts_with(&self, needle: &[String]) -> bool where String: PartialEq, {