Skip to content

Commit fb977f4

Browse files
authored
fix(prost-build): Remove derived(Copy) on boxed fields (#1157)
* fix(prost-build): Remove `derived(Copy)` on boxed fields * Add regression test
1 parent 8d4cac5 commit fb977f4

File tree

8 files changed

+47
-8
lines changed

8 files changed

+47
-8
lines changed

prost-build/src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,7 @@ impl Config {
10801080
let mut modules = HashMap::new();
10811081
let mut packages = HashMap::new();
10821082

1083-
let message_graph = MessageGraph::new(requests.iter().map(|x| &x.1));
1083+
let message_graph = MessageGraph::new(requests.iter().map(|x| &x.1), self.boxed.clone());
10841084
let extern_paths = ExternPaths::new(&self.extern_paths, self.prost_types)
10851085
.map_err(|error| Error::new(ErrorKind::InvalidInput, error))?;
10861086

prost-build/src/fixtures/field_attributes/_expected_field_attributes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub struct Foo {
1919
#[prost(string, tag="1")]
2020
pub foo: ::prost::alloc::string::String,
2121
}
22-
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
22+
#[derive(Clone, PartialEq, ::prost::Message)]
2323
pub struct Bar {
2424
#[prost(message, optional, boxed, tag="1")]
2525
pub qux: ::core::option::Option<::prost::alloc::boxed::Box<Qux>>,

prost-build/src/fixtures/field_attributes/_expected_field_attributes_formatted.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub struct Foo {
1919
#[prost(string, tag = "1")]
2020
pub foo: ::prost::alloc::string::String,
2121
}
22-
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
22+
#[derive(Clone, PartialEq, ::prost::Message)]
2323
pub struct Bar {
2424
#[prost(message, optional, boxed, tag = "1")]
2525
pub qux: ::core::option::Option<::prost::alloc::boxed::Box<Qux>>,

prost-build/src/message_graph.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,28 @@ use prost_types::{
99
DescriptorProto, FieldDescriptorProto, FileDescriptorProto,
1010
};
1111

12+
use crate::path::PathMap;
13+
1214
/// `MessageGraph` builds a graph of messages whose edges correspond to nesting.
1315
/// The goal is to recognize when message types are recursively nested, so
1416
/// that fields can be boxed when necessary.
1517
pub struct MessageGraph {
1618
index: HashMap<String, NodeIndex>,
1719
graph: Graph<String, ()>,
1820
messages: HashMap<String, DescriptorProto>,
21+
boxed: PathMap<()>,
1922
}
2023

2124
impl MessageGraph {
22-
pub fn new<'a>(files: impl Iterator<Item = &'a FileDescriptorProto>) -> MessageGraph {
25+
pub(crate) fn new<'a>(
26+
files: impl Iterator<Item = &'a FileDescriptorProto>,
27+
boxed: PathMap<()>,
28+
) -> MessageGraph {
2329
let mut msg_graph = MessageGraph {
2430
index: HashMap::new(),
2531
graph: Graph::new(),
2632
messages: HashMap::new(),
33+
boxed,
2734
};
2835

2936
for file in files {
@@ -74,6 +81,11 @@ impl MessageGraph {
7481
}
7582
}
7683

84+
/// Try get a message descriptor from current message graph
85+
pub fn get_message(&self, message: &str) -> Option<&DescriptorProto> {
86+
self.messages.get(message)
87+
}
88+
7789
/// Returns true if message type `inner` is nested in message type `outer`.
7890
pub fn is_nested(&self, outer: &str, inner: &str) -> bool {
7991
let outer = match self.index.get(outer) {
@@ -91,8 +103,9 @@ impl MessageGraph {
91103
/// Returns `true` if this message can automatically derive Copy trait.
92104
pub fn can_message_derive_copy(&self, fq_message_name: &str) -> bool {
93105
assert_eq!(".", &fq_message_name[..1]);
94-
let msg = self.messages.get(fq_message_name).unwrap();
95-
msg.field
106+
self.get_message(fq_message_name)
107+
.unwrap()
108+
.field
96109
.iter()
97110
.all(|field| self.can_field_derive_copy(fq_message_name, field))
98111
}
@@ -105,10 +118,17 @@ impl MessageGraph {
105118
) -> bool {
106119
assert_eq!(".", &fq_message_name[..1]);
107120

121+
// repeated field cannot derive Copy
108122
if field.label() == Label::Repeated {
109123
false
110124
} else if field.r#type() == Type::Message {
111-
if self.is_nested(field.type_name(), fq_message_name) {
125+
// nested and boxed messages cannot derive Copy
126+
if self.is_nested(field.type_name(), fq_message_name)
127+
|| self
128+
.boxed
129+
.get_first_field(fq_message_name, field.name())
130+
.is_some()
131+
{
112132
false
113133
} else {
114134
self.can_message_derive_copy(field.type_name())

prost-build/src/path.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::iter;
44

55
/// Maps a fully-qualified Protobuf path to a value using path matchers.
6-
#[derive(Debug, Default)]
6+
#[derive(Clone, Debug, Default)]
77
pub(crate) struct PathMap<T> {
88
// insertion order might actually matter (to avoid warning about legacy-derive-helpers)
99
// see: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#legacy-derive-helpers

tests/src/boxed_field.proto

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
syntax = "proto3";
2+
3+
package boxed_field;
4+
5+
message Foo {
6+
Bar bar = 1;
7+
}
8+
9+
message Bar {
10+
}

tests/src/build.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ fn main() {
171171
.compile_protos(&[src.join("type_names.proto")], includes)
172172
.unwrap();
173173

174+
prost_build::Config::new()
175+
.boxed("Foo.bar")
176+
.compile_protos(&[src.join("boxed_field.proto")], includes)
177+
.unwrap();
178+
174179
// Check that attempting to compile a .proto without a package declaration does not result in an error.
175180
config
176181
.compile_protos(&[src.join("no_package.proto")], includes)

tests/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ pub mod invalid {
140140
}
141141
}
142142

143+
pub mod boxed_field {
144+
include!(concat!(env!("OUT_DIR"), "/boxed_field.rs"));
145+
}
146+
143147
pub mod default_string_escape {
144148
include!(concat!(env!("OUT_DIR"), "/default_string_escape.rs"));
145149
}

0 commit comments

Comments
 (0)