From 02888414a87c19fe234efaf0f7565f4b536deaa0 Mon Sep 17 00:00:00 2001 From: Johann Borck Date: Sun, 23 Apr 2023 17:21:42 +0200 Subject: [PATCH 1/5] generate associated constants in enums representing protobuf enum aliases, resolves #792 --- prost-build/src/code_generator.rs | 34 +++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/prost-build/src/code_generator.rs b/prost-build/src/code_generator.rs index 2a4d24181..b07be7431 100644 --- a/prost-build/src/code_generator.rs +++ b/prost-build/src/code_generator.rs @@ -662,7 +662,12 @@ impl<'a> CodeGenerator<'a> { self.depth += 1; self.path.push(2); + let mut aliases = vec![]; for variant in variant_mappings.iter() { + if variant.alias_of.is_some(){ + aliases.push(variant); + continue; + } self.path.push(variant.path_idx as i32); self.append_doc(&fq_proto_enum_name, Some(variant.proto_name)); @@ -688,7 +693,21 @@ impl<'a> CodeGenerator<'a> { self.buf.push_str(" {\n"); self.depth += 1; self.path.push(2); - + self.push_indent(); + self.buf.push_str( + "/// Aliases.\n", + ); + for variant in &aliases { + self.push_indent(); + self.buf.push_str("#[allow(non_upper_case_globals)]"); + self.push_indent(); + self.buf.push_str(&format!("pub const {}: {} = {}::{};\n", + variant.generated_variant_name, + enum_name, + enum_name, + variant.alias_of.as_ref().unwrap()) + ); + } self.push_indent(); self.buf.push_str( "/// String value of the enum field names used in the ProtoBuf definition.\n", @@ -713,6 +732,7 @@ impl<'a> CodeGenerator<'a> { self.depth += 1; for variant in variant_mappings.iter() { + if variant.alias_of.is_some() {continue;} self.push_indent(); self.buf.push_str(&enum_name); self.buf.push_str("::"); @@ -1136,6 +1156,7 @@ struct EnumVariantMapping<'a> { proto_name: &'a str, proto_number: i32, generated_variant_name: String, + alias_of: Option, } fn build_enum_value_mappings<'a>( @@ -1145,15 +1166,19 @@ fn build_enum_value_mappings<'a>( ) -> Vec> { let mut numbers = HashSet::new(); let mut generated_names = HashMap::new(); - let mut mappings = Vec::new(); + let mut mappings:Vec> = Vec::new(); for (idx, value) in enum_values.iter().enumerate() { // Skip duplicate enum values. Protobuf allows this when the // 'allow_alias' option is set. + let mut alias_of = None; if !numbers.insert(value.number()) { - continue; + for m in &mappings { + if m.proto_number == value.number() { + alias_of = Some(m.generated_variant_name.clone()) + } + } } - let mut generated_variant_name = to_upper_camel(value.name()); if do_strip_enum_prefix { generated_variant_name = @@ -1171,6 +1196,7 @@ fn build_enum_value_mappings<'a>( proto_name: value.name(), proto_number: value.number(), generated_variant_name, + alias_of, }) } mappings From 09f2e9930a43470b720afe7fe0249431eb8082d6 Mon Sep 17 00:00:00 2001 From: Johann Borck Date: Sun, 23 Apr 2023 18:32:08 +0200 Subject: [PATCH 2/5] rustfmt; Handle collisions of generated names between aliases and existing variants. --- prost-build/src/code_generator.rs | 37 ++++++++++++++++++------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/prost-build/src/code_generator.rs b/prost-build/src/code_generator.rs index b07be7431..793d270c6 100644 --- a/prost-build/src/code_generator.rs +++ b/prost-build/src/code_generator.rs @@ -664,7 +664,7 @@ impl<'a> CodeGenerator<'a> { self.path.push(2); let mut aliases = vec![]; for variant in variant_mappings.iter() { - if variant.alias_of.is_some(){ + if variant.alias_of.is_some() { aliases.push(variant); continue; } @@ -694,19 +694,18 @@ impl<'a> CodeGenerator<'a> { self.depth += 1; self.path.push(2); self.push_indent(); - self.buf.push_str( - "/// Aliases.\n", - ); + self.buf.push_str("/// Aliases.\n"); for variant in &aliases { self.push_indent(); self.buf.push_str("#[allow(non_upper_case_globals)]"); self.push_indent(); - self.buf.push_str(&format!("pub const {}: {} = {}::{};\n", - variant.generated_variant_name, - enum_name, - enum_name, - variant.alias_of.as_ref().unwrap()) - ); + self.buf.push_str(&format!( + "pub const {}: {} = {}::{};\n", + variant.generated_variant_name, + enum_name, + enum_name, + variant.alias_of.as_ref().unwrap() + )); } self.push_indent(); self.buf.push_str( @@ -732,7 +731,9 @@ impl<'a> CodeGenerator<'a> { self.depth += 1; for variant in variant_mappings.iter() { - if variant.alias_of.is_some() {continue;} + if variant.alias_of.is_some() { + continue; + } self.push_indent(); self.buf.push_str(&enum_name); self.buf.push_str("::"); @@ -1166,10 +1167,10 @@ fn build_enum_value_mappings<'a>( ) -> Vec> { let mut numbers = HashSet::new(); let mut generated_names = HashMap::new(); - let mut mappings:Vec> = Vec::new(); + let mut mappings: Vec> = Vec::new(); for (idx, value) in enum_values.iter().enumerate() { - // Skip duplicate enum values. Protobuf allows this when the + // Remember name for duplicate enum values. Protobuf allows this when the // 'allow_alias' option is set. let mut alias_of = None; if !numbers.insert(value.number()) { @@ -1187,8 +1188,14 @@ fn build_enum_value_mappings<'a>( if let Some(old_v) = generated_names.insert(generated_variant_name.to_owned(), value.name()) { - panic!("Generated enum variant names overlap: `{}` variant name to be used both by `{}` and `{}` ProtoBuf enum values", - generated_variant_name, old_v, value.name()); + // if alias ends up being a duplicate, we don't need it, and can skip it. + // TODO: check if enum values are actually the same + if alias_of.is_some() { + continue; + } else { + panic!("Generated enum variant names overlap: `{}` variant name to be used both by `{}` and `{}` ProtoBuf enum values", + generated_variant_name, old_v, value.name()); + } } mappings.push(EnumVariantMapping { From 4fe05fcd74010377b2fe505f197673c76b824142 Mon Sep 17 00:00:00 2001 From: Johann Borck Date: Sun, 23 Apr 2023 18:46:37 +0200 Subject: [PATCH 3/5] accomodate funny (comment aware) test --- prost-build/src/code_generator.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/prost-build/src/code_generator.rs b/prost-build/src/code_generator.rs index 793d270c6..6948f3944 100644 --- a/prost-build/src/code_generator.rs +++ b/prost-build/src/code_generator.rs @@ -693,8 +693,10 @@ impl<'a> CodeGenerator<'a> { self.buf.push_str(" {\n"); self.depth += 1; self.path.push(2); - self.push_indent(); - self.buf.push_str("/// Aliases.\n"); + if aliases.len() > 0 { + self.push_indent(); + self.buf.push_str("/// Aliases.\n"); + } for variant in &aliases { self.push_indent(); self.buf.push_str("#[allow(non_upper_case_globals)]"); From 03781079e774f6fa23a8df1ab072df885c38e7b7 Mon Sep 17 00:00:00 2001 From: Johann Borck Date: Mon, 24 Apr 2023 13:26:17 +0200 Subject: [PATCH 4/5] always refer to first variant with a given value in case of multiple aliases --- prost-build/src/code_generator.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/prost-build/src/code_generator.rs b/prost-build/src/code_generator.rs index 6948f3944..2e39ec838 100644 --- a/prost-build/src/code_generator.rs +++ b/prost-build/src/code_generator.rs @@ -1178,7 +1178,8 @@ fn build_enum_value_mappings<'a>( if !numbers.insert(value.number()) { for m in &mappings { if m.proto_number == value.number() { - alias_of = Some(m.generated_variant_name.clone()) + alias_of = Some(m.generated_variant_name.clone()); + break; } } } From 93d039bf9400362aa24267f33f894fbcc05aa843 Mon Sep 17 00:00:00 2001 From: ousado Date: Mon, 22 Apr 2024 00:23:55 +0200 Subject: [PATCH 5/5] fix comment, move loop into if block --- prost-build/src/code_generator.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/prost-build/src/code_generator.rs b/prost-build/src/code_generator.rs index 2e39ec838..f03bb4ed8 100644 --- a/prost-build/src/code_generator.rs +++ b/prost-build/src/code_generator.rs @@ -695,19 +695,20 @@ impl<'a> CodeGenerator<'a> { self.path.push(2); if aliases.len() > 0 { self.push_indent(); - self.buf.push_str("/// Aliases.\n"); - } - for variant in &aliases { - self.push_indent(); - self.buf.push_str("#[allow(non_upper_case_globals)]"); - self.push_indent(); - self.buf.push_str(&format!( - "pub const {}: {} = {}::{};\n", - variant.generated_variant_name, - enum_name, - enum_name, - variant.alias_of.as_ref().unwrap() - )); + self.buf.push_str("// Aliases.\n"); + + for variant in &aliases { + self.push_indent(); + self.buf.push_str("#[allow(non_upper_case_globals)]"); + self.push_indent(); + self.buf.push_str(&format!( + "pub const {}: {} = {}::{};\n", + variant.generated_variant_name, + enum_name, + enum_name, + variant.alias_of.as_ref().unwrap() + )); + } } self.push_indent(); self.buf.push_str(