Skip to content

Commit

Permalink
Fix bug with unordered oneof fields
Browse files Browse the repository at this point in the history
  • Loading branch information
andersfugmann committed Jan 26, 2024
1 parent cd50f0d commit 3b15f82
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 28 deletions.
49 changes: 21 additions & 28 deletions src/plugin/types.ml
Original file line number Diff line number Diff line change
Expand Up @@ -528,35 +528,27 @@ let c_of_oneof ~params ~syntax:_ ~scope OneofDescriptorProto.{ name; _ } fields
(** Return a list of plain fields + a list of fields per oneof_decl *)
let split_oneof_decl fields oneof_decls =
let open FieldDescriptorProto in
let rec inner oneofs oneof_decls = function
| { oneof_index = Some i; _ } as o1 :: fs -> begin
match oneofs with
| [] -> inner [o1] oneof_decls fs
| { oneof_index = Some j; _ } :: _ when i = j ->
inner (o1 :: oneofs) oneof_decls fs
| oneofs ->
`Oneof (List.hd oneof_decls, List.rev oneofs) :: inner [o1] (List.tl oneof_decls) fs
end
| f :: fs -> begin
match oneofs with
| [] -> `Field f :: inner [] oneof_decls fs
| oneofs ->
`Oneof (List.hd oneof_decls, List.rev oneofs) :: `Field f :: inner [] (List.tl oneof_decls) fs
end
| [] -> begin
match oneofs, oneof_decls with
| [], [] -> []
| oneofs, [oneof_decl] ->
[ `Oneof (oneof_decl, List.rev oneofs) ]
| _ -> failwith "No field or no oneof"
end
let rec filter_oneofs acc rest index = function
| { oneof_index = Some i; _ } as f :: fs when i = index ->
filter_oneofs (f :: acc) rest index fs
| f :: fs -> filter_oneofs acc (f :: rest) index fs
| [] -> List.rev acc, List.rev rest
in
inner [] oneof_decls fields
let rec inner = function
| { oneof_index = Some i; _ } as f :: fs ->
let oneofs, fs = filter_oneofs [f] [] i fs in
let decl = List.nth oneof_decls i in
`Oneof (decl, oneofs) :: inner fs
| f :: fs ->
`Field f :: inner fs
| [] -> []
in
inner fields

let sort_fields fields =
let number = function
| FieldDescriptorProto.{ number = Some number; _ } -> number
| _ -> failwith "XAll Fields must have a number"
| _ -> failwith "All Fields must have a number"
in
List.sort ~cmp:(fun v v' -> Int.compare (number v) (number v')) fields

Expand All @@ -565,10 +557,11 @@ let make ~params ~syntax ~is_cyclic ~is_map_entry ~has_extensions ~scope ~fields
let ts =
split_oneof_decl fields oneof_decls
|> List.map ~f:(function
| `Oneof (_, [ FieldDescriptorProto.{ proto3_optional = Some true; _ } as field] )
| `Field field -> c_of_field ~params ~syntax ~scope field
| `Oneof (decl, fields) -> c_of_oneof ~params ~syntax ~scope decl fields
)
(* proto3 Oneof fields with only one field is mapped as regular field *)
| `Oneof (_, [ FieldDescriptorProto.{ proto3_optional = Some true; _ } as field] )
| `Field field -> c_of_field ~params ~syntax ~scope field
| `Oneof (decl, fields) -> c_of_oneof ~params ~syntax ~scope decl fields
)
in

let constructor_sig_arg = function
Expand Down
10 changes: 10 additions & 0 deletions test/oneof.proto
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,13 @@ message Test5 {
message Empty { };
oneof a { Empty e = 1; };
}

message Test6 {
int64 i = 1;
oneof a {
int64 a1 = 10;
int64 a2 = 21;
};
int64 j = 20;
oneof b { int64 f = 30; };
}

0 comments on commit 3b15f82

Please sign in to comment.