blob: fc2f54f95256425d3f51b22cf7c666a3f110fcd1 [file]
// 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/field.h"
#include "upb/mini_table/internal/sub.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/data.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 {
const upb_MiniTable* table;
bool is_repeated;
upb_Message* msg;
} upb_DecodeFast_MessageContext;
UPB_FORCEINLINE
const char* upb_DecodeFast_MessageData(upb_EpsCopyInputStream* st,
const char* ptr, int size, void* ctx) {
upb_Decoder* d = (upb_Decoder*)st;
upb_DecodeFast_MessageContext* c = ctx;
ptr = _upb_Decoder_DecodeMessage((upb_Decoder*)st, ptr, c->msg, c->table);
if (d->end_group != DECODE_NOGROUP) {
_upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed);
}
return ptr;
}
UPB_FORCEINLINE
bool upb_DecodeFast_SingleMessage(upb_Decoder* d, const char** ptr, void* dst,
upb_DecodeFast_Type type,
upb_DecodeFastNext* next, void* ctx) {
upb_DecodeFast_MessageContext* c = ctx;
void** submsg_dst = dst;
if (c->is_repeated || UPB_LIKELY(*submsg_dst == NULL)) {
c->msg = *submsg_dst = _upb_Message_New(c->table, &d->arena);
} else {
c->msg = *submsg_dst; // Reusing non-repeated message.
}
return upb_DecodeFast_Delimited(d, ptr, &upb_DecodeFast_MessageData, next, c);
}
UPB_FORCEINLINE
void upb_DecodeFast_Message(upb_Decoder* d, const char** ptr, upb_Message* msg,
const upb_MiniTable* table, uint64_t* hasbits,
uint64_t* data, upb_DecodeFastNext* ret,
upb_DecodeFast_Type type,
upb_DecodeFast_Cardinality card,
upb_DecodeFast_TagSize tagsize, uint64_t data2) {
uint32_t submsg_ofs = upb_DecodeFastData_GetSubofs(*data) * 8;
const upb_MiniTableSubInternal* sub = UPB_PTR_AT(
table->UPB_ONLYBITS(fields), submsg_ofs, upb_MiniTableSubInternal);
const upb_MiniTable* subtablep = sub->UPB_PRIVATE(submsg);
upb_DecodeFast_MessageContext ctx = {subtablep,
card == kUpb_DecodeFast_Repeated};
if (subtablep == NULL) {
// Unlinked messages are treated as unknown fields. Go straight to unknown
// decoder.
#ifndef NDEBUG
uint16_t case_offset = upb_DecodeFastData_GetCaseOffset(*data);
if (case_offset != 0) {
uint8_t field_number = upb_DecodeFastData_GetPresence(*data);
const upb_MiniTableField* field =
upb_MiniTable_FindFieldByNumber(table, field_number);
UPB_ASSERT(field);
_upb_Decoder_VerifyOneofUnlinked(table, field);
}
#endif
UPB_DECODEFAST_EXIT(kUpb_DecodeFastNext_DecodeUnknown, ret);
return;
}
if (--d->depth < 0) {
_upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded);
}
upb_DecodeFast_Unpacked(d, ptr, msg, data, hasbits, ret, type, card, tagsize,
&upb_DecodeFast_SingleMessage, &ctx, data2);
d->depth++;
}
#define F(type, card, tagsize) \
upb_FastDecoder_Return UPB_PRESERVE_NONE UPB_DECODEFAST_FUNCNAME( \
type, card, tagsize)(UPB_PARSE_PARAMS) { \
upb_DecodeFastNext next = kUpb_DecodeFastNext_Dispatch; \
upb_DecodeFast_Message(d, &ptr, msg, table, &hasbits, &data, &next, \
kUpb_DecodeFast_##type, kUpb_DecodeFast_##card, \
kUpb_DecodeFast_##tagsize, data2); \
UPB_DECODEFAST_NEXT(next); \
}
UPB_DECODEFAST_CARDINALITIES(UPB_DECODEFAST_TAGSIZES, F, Message)
#undef F
#undef FASTDECODE_SUBMSG