blob: 2f9d464a1c9a78d7db3a8a7ec66cfae11d9dc359 [file] [log] [blame]
// Protocol Buffers - Google's data interchange format
// Copyright 2025 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include <stddef.h>
#include <stdint.h>
#include "upb/message/internal/message.h"
#include "upb/message/message.h"
#include "upb/mini_table/message.h"
#include "upb/wire/decode.h"
#include "upb/wire/decode_fast/cardinality.h"
#include "upb/wire/decode_fast/combinations.h"
#include "upb/wire/decode_fast/dispatch.h"
#include "upb/wire/decode_fast/field_parsers.h"
#include "upb/wire/eps_copy_input_stream.h"
#include "upb/wire/internal/decoder.h"
// Must be last.
#include "upb/port/def.inc"
typedef struct {
intptr_t table;
upb_Message* msg;
} fastdecode_submsgdata;
UPB_FORCEINLINE
const char* fastdecode_tosubmsg(upb_EpsCopyInputStream* e, const char* ptr,
void* ctx) {
upb_Decoder* d = (upb_Decoder*)e;
fastdecode_submsgdata* submsg = ctx;
ptr = upb_DecodeFast_Dispatch(d, ptr, submsg->msg, submsg->table, 0, 0);
UPB_ASSUME(ptr != NULL);
return ptr;
}
#define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, type, card, \
tagsize) \
int tagbytes = upb_DecodeFast_TagSizeBytes(tagsize); \
\
if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \
RETURN_GENERIC("submessage field tag mismatch\n"); \
} \
\
if (--d->depth == 0) { \
_upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded); \
} \
\
upb_Message** dst; \
uint32_t submsg_idx = (data >> 16) & 0xff; \
const upb_MiniTable* tablep = decode_totablep(table); \
const upb_MiniTable* subtablep = \
UPB_PRIVATE(_upb_MiniTable_GetSubTableByIndex)(tablep, submsg_idx); \
fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \
fastdecode_arr farr; \
\
if (subtablep->UPB_PRIVATE(table_mask) == (uint8_t)-1) { \
d->depth++; \
RETURN_GENERIC("submessage doesn't have fast tables."); \
} \
\
dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \
sizeof(upb_Message*), card); \
\
if (card == kUpb_DecodeFast_Scalar) { \
upb_DecodeFast_SetHasbits(msg, hasbits); \
hasbits = 0; \
} \
\
again: \
if (card == kUpb_DecodeFast_Repeated) { \
dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_Message*)); \
} \
\
submsg.msg = *dst; \
\
if (card == kUpb_DecodeFast_Repeated || UPB_LIKELY(!submsg.msg)) { \
*dst = submsg.msg = _upb_Message_New(subtablep, &d->arena); \
} \
\
ptr += tagbytes; \
ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \
\
if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \
_upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \
} \
\
if (card == kUpb_DecodeFast_Repeated) { \
fastdecode_nextret ret = fastdecode_nextrepeated( \
d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_Message*)); \
switch (ret.next) { \
case FD_NEXT_SAMEFIELD: \
dst = ret.dst; \
goto again; \
case FD_NEXT_OTHERFIELD: \
d->depth++; \
data = ret.tag; \
UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \
case FD_NEXT_ATLIMIT: \
d->depth++; \
return ptr; \
} \
} \
\
d->depth++; \
UPB_MUSTTAIL return upb_DecodeFast_Dispatch(UPB_PARSE_ARGS);
#define F(type, card, tagsize) \
UPB_PRESERVE_NONE const char* UPB_DECODEFAST_FUNCNAME( \
type, card, tagsize)(UPB_PARSE_PARAMS) { \
FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, \
kUpb_DecodeFast_##type, kUpb_DecodeFast_##card, \
kUpb_DecodeFast_##tagsize); \
}
UPB_DECODEFAST_CARDINALITIES(UPB_DECODEFAST_TAGSIZES, F, Message)
#undef F
#undef FASTDECODE_SUBMSG