Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an option to box oneof fields of kind message #420

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions proto/rustproto.proto
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ extend google.protobuf.FileOptions {

// When true, will only generate codes that works with lite runtime.
optional bool lite_runtime_all = 17035;

// Use `std::Box<T>` to store oneof message fields.
// This is useful for mutually recursive messages with oneofs.
optional bool oneof_field_box_all = 17036;
}

extend google.protobuf.MessageOptions {
Expand All @@ -64,6 +68,10 @@ extend google.protobuf.MessageOptions {
optional bool serde_derive = 17030;
// Guard serde annotations with cfg attr.
optional string serde_derive_cfg = 17031;

// Use `std::Box<T>` to store oneof message fields.
// This is useful for mutually recursive messages with oneofs.
optional bool oneof_field_box = 17036;
}

extend google.protobuf.FieldOptions {
Expand All @@ -84,4 +92,8 @@ extend google.protobuf.FieldOptions {
// Use `std::Option<T>` to store singular messages fields.
// Note, it's not possible to have recursive messages with this option enabled.
optional bool singular_field_option_field = 17025;

// Use `std::Box<T>` to store oneof message fields.
// This is useful for mutually recursive messages with oneofs.
optional bool oneof_field_box_field = 17036;
}
15 changes: 15 additions & 0 deletions protobuf-codegen/src/customize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ pub struct Customize {
/// Use `std::Option<T>` to store singular messages fields.
/// Note, it's not possible to have recursive messages with this option enabled.
pub singular_field_option: Option<bool>,

/// Use `std::Box<T>` to store oneof message fields.
/// This is useful for mutually recursive messages with oneofs.
pub oneof_field_box: Option<bool>,
/// Implement serde_derive for messages
pub serde_derive: Option<bool>,
/// When `serde_derive` is set, serde annotations will be guarded with `#[cfg(cfg, ...)]`.
Expand Down Expand Up @@ -82,6 +86,9 @@ impl Customize {
if let Some(v) = that.singular_field_option {
self.singular_field_option = Some(v);
}
if let Some(v) = that.oneof_field_box {
self.oneof_field_box = Some(v);
}
if let Some(v) = that.serde_derive {
self.serde_derive = Some(v);
}
Expand Down Expand Up @@ -138,6 +145,8 @@ impl Customize {
r.singular_field_option_box = Some(parse_bool(v)?);
} else if n == "singular_field_option" {
r.singular_field_option = Some(parse_bool(v)?);
} else if n == "oneof_field_box" {
r.oneof_field_box = Some(parse_bool(v)?);
} else if n == "serde_derive" {
r.serde_derive = Some(parse_bool(v)?);
} else if n == "serde_derive_cfg" {
Expand Down Expand Up @@ -166,6 +175,7 @@ pub fn customize_from_rustproto_for_message(source: &MessageOptions) -> Customiz
let repeated_field_vec = rustproto::exts::repeated_field_vec.get(source);
let singular_field_option_box = rustproto::exts::singular_field_option_box.get(source);
let singular_field_option = rustproto::exts::singular_field_option.get(source);
let oneof_field_box = rustproto::exts::oneof_field_box.get(source);
let serde_derive = rustproto::exts::serde_derive.get(source);
let serde_derive_cfg = rustproto::exts::serde_derive_cfg.get(source);
let lite_runtime = None;
Expand All @@ -180,6 +190,7 @@ pub fn customize_from_rustproto_for_message(source: &MessageOptions) -> Customiz
repeated_field_vec,
singular_field_option_box,
singular_field_option,
oneof_field_box,
serde_derive,
serde_derive_cfg,
lite_runtime,
Expand All @@ -199,6 +210,7 @@ pub fn customize_from_rustproto_for_field(source: &FieldOptions) -> Customize {
let repeated_field_vec = rustproto::exts::repeated_field_vec_field.get(source);
let singular_field_option_box = rustproto::exts::singular_field_option_box_field.get(source);
let singular_field_option = rustproto::exts::singular_field_option_field.get(source);
let oneof_field_box = rustproto::exts::oneof_field_box_field.get(source);
let serde_derive = None;
let serde_derive_cfg = None;
let lite_runtime = None;
Expand All @@ -213,6 +225,7 @@ pub fn customize_from_rustproto_for_field(source: &FieldOptions) -> Customize {
repeated_field_vec,
singular_field_option_box,
singular_field_option,
oneof_field_box,
serde_derive,
serde_derive_cfg,
lite_runtime,
Expand All @@ -231,6 +244,7 @@ pub fn customize_from_rustproto_for_file(source: &FileOptions) -> Customize {
let repeated_field_vec = rustproto::exts::repeated_field_vec_all.get(source);
let singular_field_option_box = rustproto::exts::singular_field_option_box_all.get(source);
let singular_field_option = rustproto::exts::singular_field_option_all.get(source);
let oneof_field_box = rustproto::exts::oneof_field_box_all.get(source);
let serde_derive = rustproto::exts::serde_derive_all.get(source);
let serde_derive_cfg = rustproto::exts::serde_derive_cfg_all.get(source);
let lite_runtime = rustproto::exts::lite_runtime_all.get(source);
Expand All @@ -245,6 +259,7 @@ pub fn customize_from_rustproto_for_file(source: &FileOptions) -> Customize {
repeated_field_vec,
singular_field_option_box,
singular_field_option,
oneof_field_box,
serde_derive,
serde_derive_cfg,
lite_runtime,
Expand Down
4 changes: 2 additions & 2 deletions protobuf-codegen/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ pub(crate) struct FieldGen<'a> {
pub expose_field: bool,
pub generate_accessors: bool,
pub generate_getter: bool,
customize: Customize,
pub customize: Customize,
}

impl<'a> FieldGen<'a> {
Expand Down Expand Up @@ -643,7 +643,7 @@ impl<'a> FieldGen<'a> {
}),
}
} else if let Some(oneof) = field.oneof() {
FieldKind::Oneof(OneofField::parse(&oneof, &field, elem))
FieldKind::Oneof(OneofField::parse(&oneof, &field, elem, &customize))
} else {
let flag = if field.message.scope.file_scope.syntax() == Syntax::PROTO3
&& field.field.get_field_type() != field_descriptor_proto::Type::TYPE_MESSAGE
Expand Down
8 changes: 5 additions & 3 deletions protobuf-codegen/src/oneof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ impl<'a> OneofField<'a> {
oneof: &OneofWithContext<'a>,
field: &FieldWithContext<'a>,
elem: FieldElem<'a>,
customize: &Customize,
) -> OneofField<'a> {
// detecting recursion
let boxed = if let &FieldElem::Message(ref m) = &elem {
m.message.name_absolute() == oneof.message.name_absolute()
customize.oneof_field_box.unwrap_or(false)
// detecting recursion
|| m.message.name_absolute() == oneof.message.name_absolute()
} else {
false
};
Expand Down Expand Up @@ -101,7 +103,7 @@ impl<'a> OneofVariantGen<'a> {
),
field.rust_name
),
oneof_field: OneofField::parse(variant.oneof, &field.proto_field, field.elem().clone()),
oneof_field: OneofField::parse(variant.oneof, &field.proto_field, field.elem().clone(), &field.customize),
}
}

Expand Down
37 changes: 37 additions & 0 deletions protobuf-test/src/common/v2/test_oneof_field_box.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use super::test_oneof_field_box_pb::*;

#[test]
fn test_without_option() {
let inner = Inner::new();
let _x1 = without_option::X::inner(inner);

let s = String::new();
let _x2 = without_option::X::s(s);
}

#[test]
fn test_without_option_recursive() {
let w = WithoutOptionRecursive::new();
let _x1 = without_option_recursive::X::inner(Box::new(w));

let s = String::new();
let _x2 = without_option_recursive::X::s(s);
}

#[test]
fn test_with_message_option() {
let inner = Inner::new();
let _x1 = with_message_option::X::inner(Box::new(inner));

let s = String::new();
let _x2 = with_message_option::X::s(s);
}

#[test]
fn test_with_field_option() {
let inner = Inner::new();
let _x1 = with_field_option::X::inner(inner);

let inner = Inner::new();
let _x2 = with_field_option::X::inner_box(Box::new(inner));
}
39 changes: 39 additions & 0 deletions protobuf-test/src/common/v2/test_oneof_field_box_pb.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
syntax = "proto2";

import "rustproto.proto";

package test_oneof_field_box;

message Inner {
optional int32 size = 1;
}

message WithoutOption {
oneof x {
Inner inner = 1;
string s = 2;
}
}

message WithoutOptionRecursive {
oneof x {
WithoutOptionRecursive inner = 1;
string s = 2;
}
}

message WithMessageOption {
option (rustproto.oneof_field_box) = true;

oneof x {
Inner inner = 1;
string s = 2;
}
}

message WithFieldOption {
oneof x {
Inner inner = 1;
Inner inner_box = 2 [(rustproto.oneof_field_box_field) = true];
}
}
2 changes: 2 additions & 0 deletions protobuf-test/src/common/v2/test_oneof_recursive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ use super::test_oneof_recursive_pb::*;
#[test]
fn test() {
let _ = LinkedList::new();
let _ = A::new();
let _ = B::new();
}
18 changes: 18 additions & 0 deletions protobuf-test/src/common/v2/test_oneof_recursive_pb.proto
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
syntax = "proto2";

import "rustproto.proto";

package test_oneof_recursive;

message LinkedList {
Expand All @@ -8,3 +10,19 @@ message LinkedList {
LinkedList node = 2;
}
}

message A {
option (rustproto.oneof_field_box) = true;
oneof a {
int32 i = 1;
B b = 2;
}
}

message B {
option (rustproto.oneof_field_box) = true;
oneof b {
int32 i = 1;
A a = 2;
}
}
Loading