Skip to content

Commit e3093ee

Browse files
authored
Support reserved fields in enums (#205)
1 parent 52ab55d commit e3093ee

File tree

4 files changed

+28
-2
lines changed

4 files changed

+28
-2
lines changed

src/codegen/metadata_methods.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ function maybe_generate_reserved_fields_method(io, t::MessageType)
1010
println(io, "PB.reserved_fields(::Type{", safename(t), "}) = (names = ", string(t.reserved_names), ", numbers = Union{Int,UnitRange{Int}}[", join(t.reserved_nums, ", "), "])")
1111
end
1212

13+
function maybe_generate_reserved_fields_method(io, t::EnumType)
14+
isempty(t.reserved_names) && isempty(t.reserved_nums) && return
15+
println(io, "PB.reserved_fields(::Type{", safename(t), ".T}) = (names = ", string(t.reserved_names), ", numbers = Union{Int,UnitRange{Int}}[", join(t.reserved_nums, ", "), "])")
16+
end
17+
1318
function maybe_generate_extendable_field_numbers_method(io, t::MessageType)
1419
n = length(t.extensions)
1520
n == 0 && return

src/codegen/toplevel_definitions.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ function codegen(io, t::EnumType, ::Context)
120120
end
121121
println(io)
122122
maybe_generate_deprecation(io, t)
123+
maybe_generate_reserved_fields_method(io, t)
123124
end
124125

125126
function codegen(io, t::ServiceType, ::Context)

src/parsing/proto_types.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ struct EnumType <: AbstractProtoType
117117
element_names::Vector{Symbol}
118118
element_values::Vector{Int}
119119
options::Dict{String,Union{String,Dict{String}}}
120+
reserved_nums::Vector{Union{Int,UnitRange{Int}}}
121+
reserved_names::Vector{String}
120122
field_options::Dict{String,Union{String,Dict{String}}}
121123
end
122124

@@ -268,6 +270,8 @@ function parse_enum_type(ps::ParserState, name_prefix="")
268270
name = unsafe_name(ps)
269271

270272
options = Dict{String,Union{String,Dict{String}}}()
273+
reserved_nums = Vector{Union{Int,UnitRange{Int}}}()
274+
reserved_names = Vector{String}()
271275
field_options = Dict{String,Union{String,Dict{String}}}()
272276
element_names = Symbol[]
273277
element_values = Int[]
@@ -286,6 +290,8 @@ function parse_enum_type(ps::ParserState, name_prefix="")
286290
parse_field_options!(ps, get!(field_options, element_name, Dict{String,Union{String,Dict{String}}}()))
287291
end
288292
expectnext(ps, Tokens.SEMICOLON)
293+
elseif accept(ps, Tokens.RESERVED)
294+
_parse_reserved_statement!(ps, reserved_nums, reserved_names)
289295
else
290296
expectnext(ps, Tokens.RBRACE)
291297
break
@@ -300,7 +306,7 @@ function parse_enum_type(ps::ParserState, name_prefix="")
300306
error("In proto3, enums' first element must map to zero, $name has `$(first(element_names)) = $(first(element_values))` as first element.")
301307
end
302308
# TODO: validate field_numbers
303-
return EnumType(_dot_join(name_prefix, name), element_names, element_values, options, field_options)
309+
return EnumType(_dot_join(name_prefix, name), element_names, element_values, options, reserved_nums, reserved_names, field_options)
304310
end
305311

306312
# We consumed EXTEND

test/test_codegen.jl

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ using ProtoBuf.CodeGenerators: resolve_inter_package_references!, get_all_transi
55
using ProtoBuf.CodeGenerators: CodeGenerators
66
using ProtoBuf.Parsers: parse_proto_file, ParserState, Parsers
77
using ProtoBuf.Lexers: Lexer
8+
using EnumX
89
using Test
910

1011
strify(f, args...) = (io = IOBuffer(); f(io, args...); String(take!(io)))
@@ -634,15 +635,18 @@ end
634635

635636
@testset "Metadata methods" begin
636637
@testset "metadata_methods have generic fallback" begin
637-
s, p, ctx = translate_simple_proto("message A { }")
638+
s, p, ctx = translate_simple_proto("message A { } enum Foo { }")
638639
@test strify(CodeGenerators.maybe_generate_reserved_fields_method, p.definitions["A"]) == ""
640+
@test strify(CodeGenerators.maybe_generate_reserved_fields_method, p.definitions["Foo"]) == ""
639641
@test strify(CodeGenerators.maybe_generate_extendable_field_numbers_method, p.definitions["A"]) == ""
640642
@test strify(CodeGenerators.maybe_generate_default_values_method, p.definitions["A"], ctx) == ""
641643
@test strify(CodeGenerators.maybe_generate_oneof_field_types_method, p.definitions["A"], ctx) == ""
642644
@test strify(CodeGenerators.maybe_generate_field_numbers_method, p.definitions["A"]) == ""
643645

644646
struct A end
647+
@enumx Foo
645648
@test reserved_fields(A) == (names = String[], numbers = Union{Int,UnitRange{Int}}[])
649+
@test reserved_fields(Foo.T) == (names = String[], numbers = Union{Int,UnitRange{Int}}[])
646650
@test extendable_field_numbers(A) == Union{Int,UnitRange{Int}}[]
647651
@test default_values(A) == (;)
648652
@test oneof_field_types(A) == (;)
@@ -658,6 +662,16 @@ end
658662
@test strify(CodeGenerators.maybe_generate_field_numbers_method, p.definitions["A"]) == "PB.field_numbers(::Type{A}) = (;a = 1, s = 3)\n"
659663
@test strify(CodeGenerators.maybe_generate_kwarg_constructor_method, p.definitions["A"], ctx) == "A(;a = nothing, o = nothing) = A(a, o)\n"
660664
end
665+
666+
@testset "reserved fields are available for enums" begin
667+
s, p, ctx = translate_simple_proto("""
668+
enum Foo {
669+
reserved 2, 15, 9 to 11, 40 to max;
670+
reserved "FOO", "BAR";
671+
}
672+
""")
673+
@test strify(CodeGenerators.maybe_generate_reserved_fields_method, p.definitions["Foo"]) =="PB.reserved_fields(::Type{Foo.T}) = (names = [\"FOO\", \"BAR\"], numbers = Union{Int,UnitRange{Int}}[2, 15, 9:11, 40:536870911])\n"
674+
end
661675
end
662676

663677
@testset "Imports within a leaf module which name-clashes with top module" begin

0 commit comments

Comments
 (0)