diff --git a/src/capnp_compile.erl b/src/capnp_compile.erl index a6cac8a..b25c6bf 100644 --- a/src/capnp_compile.erl +++ b/src/capnp_compile.erl @@ -533,18 +533,40 @@ generate_follow_struct_list_pointer() -> -ast_forms_function(#{name => ast_follow_struct_list_pointer}). follow_tagged_struct_list_pointer(_DecodeFun, 0, _MessageRef) -> undefined; - follow_tagged_struct_list_pointer(DecodeFun, PointerInt, MessageRef) when PointerInt band 3 == 1 -> + follow_tagged_struct_list_pointer(DecodeFun, PointerInt, MessageRef) + when PointerInt band 3 == 1 andalso (PointerInt bsr 32) band 7 >= 5 -> PointerOffset = case PointerInt band (1 bsl 31) of 0 -> ((PointerInt bsr 2) band (1 bsl 30 - 1)) + 1; _ -> ((PointerInt bsr 2) band (1 bsl 30 - 1)) - (1 bsl 30) + 1 end, + LengthFromPointer = (PointerInt bsr 35) band (1 bsl 28), NewOffset = MessageRef#message_ref.current_offset + PointerOffset, - SkipBits = NewOffset bsl 6, - <<_:SkipBits, Tag:64/little-unsigned-integer, _/binary>> = MessageRef#message_ref.current_segment, - Length = ((Tag bsr 2) band (1 bsl 30 - 1)), - DWords = (Tag bsr 32) band (1 bsl 16 - 1), - PWords = (Tag bsr 48) band (1 bsl 16 - 1), - decode_struct_list(DecodeFun, Length, DWords, PWords, MessageRef#message_ref{current_offset=NewOffset+1}); + case (PointerInt bsr 32) band 7 of + 5 -> + % Pointer to a list of primitive words. + Length = LengthFromPointer, + DWords = 1, + PWords = 0, + ListStartOffset = NewOffset; + 6 -> + % Pointer to a list of pointers. + Length = LengthFromPointer, + DWords = 0, + PWords = 1, + ListStartOffset = NewOffset; + 7 -> + SkipBits = NewOffset bsl 6, + <<_:SkipBits, Tag:64/little-unsigned-integer, _/binary>> = MessageRef#message_ref.current_segment, + 1 = (Tag band 3), % Sanity check. + Length = ((Tag bsr 2) band (1 bsl 30 - 1)), + DWords = (Tag bsr 32) band (1 bsl 16 - 1), + PWords = (Tag bsr 48) band (1 bsl 16 - 1), + ListStartOffset = NewOffset + 1 + end, + decode_struct_list(DecodeFun, Length, DWords, PWords, MessageRef#message_ref{current_offset=ListStartOffset}); + follow_tagged_struct_list_pointer(DecodeFun, _PointerInt, _MessageRef) + when PointerInt band 3 == 1 andalso (PointerInt bsr 32) band 7 < 5 -> + erlang:error({not_supported, "cannot currently decode List(struct {}) which is stored as a list of subword values"}); follow_tagged_struct_list_pointer(DecodeFun, PointerInt, MessageRef=#message_ref{}) when PointerInt band 3 == 2 -> {NewPointerInt, NewMessageRef} = decode_far_pointer(PointerInt, MessageRef), follow_tagged_struct_list_pointer(DecodeFun, NewPointerInt, NewMessageRef).