Skip to content

Commit 1f38ea6

Browse files
prost-build: CodeGenerator::boxed method (#1019)
* prost-build: CodeGenerator::boxed method A helper method to capture the logic of deciding whether a field needs to be boxed. This follows the pattern with other methods like `optional`, and will allow reusing the logic in the upcoming builder codegen. * prost-build: more reuse with CodeGenerator::boxed The bit in CodeGenerator::append_oneof was pretty much the same, except the configuration is looked up for the oneof name. Rearrange the logic so that intermediate values are bound when needed. If a repeated fields is configured to be boxed, a deprecation warning will be emitted by the build script. * prost-build: document CodeGenerator::boxed * prost-build: only emit warning on repeated fields Co-authored-by: Casper Meijn <[email protected]> --------- Co-authored-by: Casper Meijn <[email protected]>
1 parent 2308ba4 commit 1f38ea6

File tree

1 file changed

+49
-22
lines changed

1 file changed

+49
-22
lines changed

prost-build/src/code_generator.rs

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -402,19 +402,9 @@ impl<'a> CodeGenerator<'a> {
402402
let repeated = field.descriptor.label == Some(Label::Repeated as i32);
403403
let deprecated = self.deprecated(&field.descriptor);
404404
let optional = self.optional(&field.descriptor);
405+
let boxed = self.boxed(&field.descriptor, fq_message_name, None);
405406
let ty = self.resolve_type(&field.descriptor, fq_message_name);
406407

407-
let boxed = !repeated
408-
&& ((type_ == Type::Message || type_ == Type::Group)
409-
&& self
410-
.message_graph
411-
.is_nested(field.descriptor.type_name(), fq_message_name))
412-
|| (self
413-
.config
414-
.boxed
415-
.get_first_field(fq_message_name, field.descriptor.name())
416-
.is_some());
417-
418408
debug!(
419409
" field: {:?}, type: {:?}, boxed: {}",
420410
field.descriptor.name(),
@@ -636,8 +626,6 @@ impl<'a> CodeGenerator<'a> {
636626
self.path.push(2);
637627
self.depth += 1;
638628
for field in &oneof.fields {
639-
let type_ = field.descriptor.r#type();
640-
641629
self.path.push(field.path_index);
642630
self.append_doc(fq_message_name, Some(field.descriptor.name()));
643631
self.path.pop();
@@ -654,15 +642,11 @@ impl<'a> CodeGenerator<'a> {
654642
self.push_indent();
655643
let ty = self.resolve_type(&field.descriptor, fq_message_name);
656644

657-
let boxed = ((type_ == Type::Message || type_ == Type::Group)
658-
&& self
659-
.message_graph
660-
.is_nested(field.descriptor.type_name(), fq_message_name))
661-
|| (self
662-
.config
663-
.boxed
664-
.get_first_field(&oneof_name, field.descriptor.name())
665-
.is_some());
645+
let boxed = self.boxed(
646+
&field.descriptor,
647+
fq_message_name,
648+
Some(oneof.descriptor.name()),
649+
);
666650

667651
debug!(
668652
" oneof: {:?}, type: {:?}, boxed: {}",
@@ -1068,6 +1052,49 @@ impl<'a> CodeGenerator<'a> {
10681052
}
10691053
}
10701054

1055+
/// Returns whether the Rust type for this field needs to be `Box<_>`.
1056+
///
1057+
/// This can be explicitly configured with `Config::boxed`, or necessary
1058+
/// to prevent an infinitely sized type definition in case when the type of
1059+
/// a non-repeated message field transitively contains the message itself.
1060+
fn boxed(
1061+
&self,
1062+
field: &FieldDescriptorProto,
1063+
fq_message_name: &str,
1064+
oneof: Option<&str>,
1065+
) -> bool {
1066+
let repeated = field.label == Some(Label::Repeated as i32);
1067+
let fd_type = field.r#type();
1068+
if !repeated
1069+
&& (fd_type == Type::Message || fd_type == Type::Group)
1070+
&& self
1071+
.message_graph
1072+
.is_nested(field.type_name(), fq_message_name)
1073+
{
1074+
return true;
1075+
}
1076+
let config_path = match oneof {
1077+
None => Cow::Borrowed(fq_message_name),
1078+
Some(ooname) => Cow::Owned(format!("{fq_message_name}.{ooname}")),
1079+
};
1080+
if self
1081+
.config
1082+
.boxed
1083+
.get_first_field(&config_path, field.name())
1084+
.is_some()
1085+
{
1086+
if repeated {
1087+
println!(
1088+
"cargo:warning=\
1089+
Field X is repeated and manually marked as boxed. \
1090+
This is deprecated and support will be removed in a later release"
1091+
);
1092+
}
1093+
return true;
1094+
}
1095+
false
1096+
}
1097+
10711098
/// Returns `true` if the field options includes the `deprecated` option.
10721099
fn deprecated(&self, field: &FieldDescriptorProto) -> bool {
10731100
field

0 commit comments

Comments
 (0)