Skip to content

Commit

Permalink
Make #[non_exhaustive] for oneofs configurable
Browse files Browse the repository at this point in the history
Add a configuration option to disable annotating generated enum types
for proto `oneof`s with `#[non_exhaustive]`. The annotation makes sense
for self-contained crates, but it's convenient to be able to turn it
off.

One use case is for larger projects that consist of multiple crates that
are developed together. Being unable to exhaustively match on the
contents of `oneof`s not just in the crate that includes the generated
protobuf code is very useful.
  • Loading branch information
akonradi-signal committed May 15, 2024
1 parent 16c9dc5 commit 8069017
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 80 deletions.
6 changes: 6 additions & 0 deletions proto/rustproto.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ extend google.protobuf.FileOptions {
optional bool tokio_bytes_all = 17011;
// Use `bytes::Bytes` for `string` fields
optional bool tokio_bytes_for_string_all = 17012;
// When false, `#[non_exhaustive]` is not generated for `oneof` fields.
optional bool oneofs_non_exhaustive_all = 17013;

// When true, will only generate codes that works with lite runtime.
optional bool lite_runtime_all = 17035;
Expand All @@ -33,6 +35,8 @@ extend google.protobuf.MessageOptions {
optional bool tokio_bytes = 17011;
// Use `bytes::Bytes` for `string` fields
optional bool tokio_bytes_for_string = 17012;
// When false, `#[non_exhaustive]` is not generated for `oneof` fields.
optional bool oneofs_non_exhaustive = 17013;
}

extend google.protobuf.FieldOptions {
Expand All @@ -44,4 +48,6 @@ extend google.protobuf.FieldOptions {
optional bool tokio_bytes_field = 17011;
// Use `bytes::Bytes` for `string` fields
optional bool tokio_bytes_for_string_field = 17012;
// When false, `#[non_exhaustive]` is not generated for `oneof` fields.
optional bool oneofs_non_exhaustive_field = 17013;
}
7 changes: 7 additions & 0 deletions protobuf-codegen/src/customize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ pub struct Customize {
pub(crate) tokio_bytes: Option<bool>,
/// Use `bytes::Bytes` for `string` fields
pub(crate) tokio_bytes_for_string: Option<bool>,
/// When false, `#[non_exhaustive]` is not generated for `oneof` fields.
pub(crate) oneofs_non_exhaustive: Option<bool>,
/// Enable lite runtime.
pub(crate) lite_runtime: Option<bool>,
/// Generate `mod.rs` in the output directory.
Expand Down Expand Up @@ -148,6 +150,11 @@ impl Customize {
self
}

pub fn oneofs_non_exhaustive(mut self, non_exhaustive: bool) -> Self {
self.oneofs_non_exhaustive = Some(non_exhaustive);
self
}

/// Generate code for "lite runtime". Generated code contains no code for reflection.
/// So the generated code (and more importantly, generated binary size) is smaller,
/// but reflection, text format, JSON serialization won't work.
Expand Down
6 changes: 6 additions & 0 deletions protobuf-codegen/src/customize/rustproto_proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub(crate) fn customize_from_rustproto_for_message(source: &MessageOptions) -> C
let generate_getter = rustproto::exts::generate_getter.get(source);
let tokio_bytes = rustproto::exts::tokio_bytes.get(source);
let tokio_bytes_for_string = rustproto::exts::tokio_bytes_for_string.get(source);
let oneofs_non_exhaustive = rustproto::exts::oneofs_non_exhaustive.get(source);
let lite_runtime = None;
let gen_mod_rs = None;
let inside_protobuf = None;
Expand All @@ -21,6 +22,7 @@ pub(crate) fn customize_from_rustproto_for_message(source: &MessageOptions) -> C
generate_getter,
tokio_bytes,
tokio_bytes_for_string,
oneofs_non_exhaustive,
lite_runtime,
gen_mod_rs,
inside_protobuf,
Expand All @@ -37,6 +39,7 @@ pub(crate) fn customize_from_rustproto_for_field(source: &FieldOptions) -> Custo
let generate_getter = rustproto::exts::generate_getter_field.get(source);
let tokio_bytes = rustproto::exts::tokio_bytes_field.get(source);
let tokio_bytes_for_string = rustproto::exts::tokio_bytes_for_string_field.get(source);
let oneofs_non_exhaustive = rustproto::exts::oneofs_non_exhaustive_field.get(source);
let lite_runtime = None;
let gen_mod_rs = None;
let inside_protobuf = None;
Expand All @@ -46,6 +49,7 @@ pub(crate) fn customize_from_rustproto_for_field(source: &FieldOptions) -> Custo
generate_getter,
tokio_bytes,
tokio_bytes_for_string,
oneofs_non_exhaustive,
lite_runtime,
gen_mod_rs,
inside_protobuf,
Expand All @@ -58,6 +62,7 @@ pub(crate) fn customize_from_rustproto_for_file(source: &FileOptions) -> Customi
let generate_getter = rustproto::exts::generate_getter_all.get(source);
let tokio_bytes = rustproto::exts::tokio_bytes_all.get(source);
let tokio_bytes_for_string = rustproto::exts::tokio_bytes_for_string_all.get(source);
let oneofs_non_exhaustive = rustproto::exts::oneofs_non_exhaustive_all.get(source);
let lite_runtime = rustproto::exts::lite_runtime_all.get(source);
let gen_mod_rs = None;
let inside_protobuf = None;
Expand All @@ -67,6 +72,7 @@ pub(crate) fn customize_from_rustproto_for_file(source: &FileOptions) -> Customi
generate_getter,
tokio_bytes,
tokio_bytes_for_string,
oneofs_non_exhaustive,
lite_runtime,
inside_protobuf,
gen_mod_rs,
Expand Down
9 changes: 8 additions & 1 deletion protobuf-codegen/src/gen/oneof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,14 @@ impl<'a> OneofGen<'a> {
fn write_enum(&self, w: &mut CodeWriter) {
let derive = vec!["Clone", "PartialEq", "Debug"];
w.derive(&derive);
w.write_line("#[non_exhaustive]");
if self
.customize
.for_elem
.oneofs_non_exhaustive
.unwrap_or(true)
{
w.write_line("#[non_exhaustive]");
}
write_protoc_insertion_point_for_oneof(w, &self.customize.for_elem, &self.oneof.oneof);
w.pub_enum(&self.oneof.rust_name().ident.to_string(), |w| {
for variant in self.variants_except_group() {
Expand Down
6 changes: 6 additions & 0 deletions protobuf-parse/src/proto/rustproto.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ extend google.protobuf.FileOptions {
optional bool tokio_bytes_all = 17011;
// Use `bytes::Bytes` for `string` fields
optional bool tokio_bytes_for_string_all = 17012;
// When false, `#[non_exhaustive]` is not generated for `oneof` fields.
optional bool oneofs_non_exhaustive_all = 17013;

// When true, will only generate codes that works with lite runtime.
optional bool lite_runtime_all = 17035;
Expand All @@ -33,6 +35,8 @@ extend google.protobuf.MessageOptions {
optional bool tokio_bytes = 17011;
// Use `bytes::Bytes` for `string` fields
optional bool tokio_bytes_for_string = 17012;
// When false, `#[non_exhaustive]` is not generated for `oneof` fields.
optional bool oneofs_non_exhaustive = 17013;
}

extend google.protobuf.FieldOptions {
Expand All @@ -44,4 +48,6 @@ extend google.protobuf.FieldOptions {
optional bool tokio_bytes_field = 17011;
// Use `bytes::Bytes` for `string` fields
optional bool tokio_bytes_for_string_field = 17012;
// When false, `#[non_exhaustive]` is not generated for `oneof` fields.
optional bool oneofs_non_exhaustive_field = 17013;
}
Loading

0 comments on commit 8069017

Please sign in to comment.