Skip to content

Commit

Permalink
Tweak our generated lookup and resolve methods for enums to prevent a…
Browse files Browse the repository at this point in the history
… "nesting too deep" error
  • Loading branch information
davebenvenuti committed Jan 24, 2025
1 parent d51fe05 commit 4890b39
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 455 deletions.
72 changes: 47 additions & 25 deletions lib/protoboeuf/codegen.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,53 @@ def initialize(enum, generate_types:, options: {})
end

def result
"module #{enum.name}\n" + class_body + "; end\n"
<<~RESULT
module #{enum.name}
#{values}
#{lookup}
#{resolve}
end
RESULT
end

private

def class_body
enum.value.map { |const|
"#{const.name} = #{const.number}"
}.join("\n") + "\n\n" + lookup + "\n\n" + resolve
VALUES = ERB.new(<<~VALUES, trim_mode: "-")
<%- enum.value.each do |const| -%>
<%= const.name %> = <%= const.number %>
<%- end -%>
VALUES

def values
VALUES.result(binding)
end

LOOKUP = ERB.new(<<~LOOKUP, trim_mode: "-")
<%= type_signature(params: { val: "Integer" }, returns: "Symbol", newline: true) %>
def self.lookup(val)
<%- enum.value.each do |const| -%>
return :<%= const.name %> if val == <%= const.number %>
<%- end -%>
end
LOOKUP

def lookup
type_signature(params: { val: "Integer" }, returns: "Symbol", newline: true) +
"def self.lookup(val)\n" \
"if " + enum.value.map { |const|
"val == #{const.number} then :#{const.name}"
}.join(" elsif ") + " end; end"
LOOKUP.result(binding)
end

RESOLVE = ERB.new(<<~RESOLVE, trim_mode: "-")
<%= type_signature(params: { val: "Symbol" }, returns: "Integer", newline: true) %>
def self.resolve(val)
<%- enum.value.each do |const| -%>
return <%= const.number %> if val == :<%= const.name %>
<%- end -%>
end
RESOLVE

def resolve
type_signature(params: { val: "Symbol" }, returns: "Integer", newline: true) +
"def self.resolve(val)\n" \
"if " + enum.value.map { |const|
"val == :#{const.name} then #{const.number}"
}.join(" elsif ") + " end; end"
RESOLVE.result(binding)
end
end

Expand Down Expand Up @@ -699,25 +721,25 @@ def enum_writers
return "" if fields.empty?

"# enum writers\n" +
fields.map { |field|
fields.map do |field|
"def #{field.name}=(v); #{iv_name(field)} = #{enum_name(field)}.resolve(v) || v; end"
}.join("\n") + "\n\n"
end.join("\n") + "\n\n"
end

def required_writers
fields = @required_fields

return "" if fields.empty?

fields.map { |field|
fields.map do |field|
<<~RUBY
#{type_signature(params: { v: convert_field_type(field) })}
def #{field.name}=(v)
#{bounds_check(field, "v")}
#{iv_name(field)} = v
end
RUBY
}.join("\n") + "\n"
end.join("\n") + "\n"
end

def optional_writers
Expand All @@ -741,20 +763,20 @@ def oneof_writers
return "" if oneof_fields.empty?

"# BEGIN writers for oneof fields\n" +
oneof_fields.map.with_index { |sub_fields, i|
oneof_fields.map.with_index do |sub_fields, i|
next unless sub_fields

oneof = message.oneof_decl[i]
sub_fields.map { |field|
sub_fields.map do |field|
<<~RUBY
def #{field.name}=(v)
#{bounds_check(field, "v")}
@#{oneof.name} = :#{field.name}
#{iv_name(field)} = v
end
RUBY
}.join("\n")
}.join("\n") +
end.join("\n")
end.join("\n") +
"# END writers for oneof fields\n\n"
end

Expand Down Expand Up @@ -915,14 +937,14 @@ def to_proto(_options = {})
def optional_predicates
return "" if optional_fields.empty?

optional_fields.map { |field|
optional_fields.map do |field|
<<~RUBY
#{type_signature(returns: "T::Boolean")}
def has_#{field.name}?
#{test_bitmask(field)}
end
RUBY
}.join("\n") + "\n"
end.join("\n") + "\n"
end

def decode
Expand Down
56 changes: 18 additions & 38 deletions lib/protoboeuf/google/api/field_behavior.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 4890b39

Please sign in to comment.