mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
Removed obsolete experimental code for tagged-ptr field promotion.
PiperOrigin-RevId: 823526718
This commit is contained in:
parent
89fb5ebf4b
commit
83d1db468b
22 changed files with 64 additions and 914 deletions
|
|
@ -181,7 +181,6 @@ upb/message/map.h
|
|||
upb/message/map_gencode_util.h
|
||||
upb/message/merge.h
|
||||
upb/message/message.h
|
||||
upb/message/tagged_ptr.h
|
||||
upb/message/value.h
|
||||
upb/mini_descriptor/build_enum.h
|
||||
upb/mini_descriptor/decode.h
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ pub enum DecodeStatus {
|
|||
BadUtf8 = 3,
|
||||
MaxDepthExceeded = 4,
|
||||
MissingRequired = 5,
|
||||
UnlinkedSubMessage = 6,
|
||||
}
|
||||
// LINT.ThenChange()
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ cc_library(
|
|||
"map.h",
|
||||
"map_gencode_util.h",
|
||||
"message.h",
|
||||
"tagged_ptr.h",
|
||||
"value.h",
|
||||
],
|
||||
copts = UPB_DEFAULT_COPTS,
|
||||
|
|
@ -84,7 +83,6 @@ cc_library(
|
|||
"internal/map.h",
|
||||
"internal/map_sorter.h",
|
||||
"internal/message.h",
|
||||
"internal/tagged_ptr.h",
|
||||
],
|
||||
copts = UPB_DEFAULT_COPTS,
|
||||
visibility = ["//visibility:public"],
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
#include "upb/message/internal/accessors.h"
|
||||
#include "upb/message/map.h"
|
||||
#include "upb/message/message.h"
|
||||
#include "upb/message/tagged_ptr.h"
|
||||
#include "upb/message/value.h"
|
||||
#include "upb/mini_table/extension.h"
|
||||
#include "upb/mini_table/field.h"
|
||||
|
|
@ -57,10 +56,6 @@ UPB_API_INLINE upb_MessageValue
|
|||
upb_Message_GetField(const upb_Message* msg, const upb_MiniTableField* f,
|
||||
upb_MessageValue default_val);
|
||||
|
||||
UPB_API_INLINE upb_TaggedMessagePtr upb_Message_GetTaggedMessagePtr(
|
||||
const upb_Message* msg, const upb_MiniTableField* field,
|
||||
upb_Message* default_val);
|
||||
|
||||
UPB_API_INLINE const upb_Array* upb_Message_GetArray(
|
||||
const upb_Message* msg, const upb_MiniTableField* f);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#include "upb/message/internal/message.h"
|
||||
#include "upb/message/map.h"
|
||||
#include "upb/message/message.h"
|
||||
#include "upb/message/tagged_ptr.h"
|
||||
#include "upb/mini_table/extension.h"
|
||||
#include "upb/mini_table/field.h"
|
||||
#include "upb/mini_table/internal/field.h"
|
||||
|
|
@ -72,14 +71,11 @@ static bool upb_Clone_MessageValue(void* value, upb_CType value_type,
|
|||
return true;
|
||||
} break;
|
||||
case kUpb_CType_Message: {
|
||||
const upb_TaggedMessagePtr source = *(upb_TaggedMessagePtr*)value;
|
||||
bool is_empty = upb_TaggedMessagePtr_IsEmpty(source);
|
||||
if (is_empty) sub = UPB_PRIVATE(_upb_MiniTable_Empty)();
|
||||
UPB_ASSERT(sub);
|
||||
const upb_Message* source = *(upb_Message**)value;
|
||||
UPB_ASSERT(source);
|
||||
upb_Message* clone = upb_Message_DeepClone(
|
||||
UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(source), sub, arena);
|
||||
*(upb_TaggedMessagePtr*)value =
|
||||
UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(clone, is_empty);
|
||||
upb_Message* clone = upb_Message_DeepClone(source, sub, arena);
|
||||
*(upb_Message**)value = clone;
|
||||
return clone != NULL;
|
||||
} break;
|
||||
}
|
||||
|
|
@ -199,27 +195,16 @@ upb_Message* _upb_Message_Copy(upb_Message* dst, const upb_Message* src,
|
|||
if (upb_MiniTableField_IsScalar(field)) {
|
||||
switch (upb_MiniTableField_CType(field)) {
|
||||
case kUpb_CType_Message: {
|
||||
upb_TaggedMessagePtr tagged =
|
||||
upb_Message_GetTaggedMessagePtr(src, field, NULL);
|
||||
const upb_Message* sub_message =
|
||||
UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(tagged);
|
||||
const upb_Message* sub_message = upb_Message_GetMessage(src, field);
|
||||
if (sub_message != NULL) {
|
||||
// If the message is currently in an unlinked, "empty" state we keep
|
||||
// it that way, because we don't want to deal with decode options,
|
||||
// decode status, or possible parse failure here.
|
||||
bool is_empty = upb_TaggedMessagePtr_IsEmpty(tagged);
|
||||
const upb_MiniTable* sub_message_table =
|
||||
is_empty ? UPB_PRIVATE(_upb_MiniTable_Empty)()
|
||||
: upb_MiniTable_GetSubMessageTable(mini_table, field);
|
||||
upb_MiniTable_GetSubMessageTable(mini_table, field);
|
||||
upb_Message* dst_sub_message =
|
||||
upb_Message_DeepClone(sub_message, sub_message_table, arena);
|
||||
if (dst_sub_message == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
UPB_PRIVATE(_upb_Message_SetTaggedMessagePtr)
|
||||
(dst, field,
|
||||
UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(dst_sub_message,
|
||||
is_empty));
|
||||
upb_Message_SetBaseFieldMessage(dst, field, dst_sub_message);
|
||||
}
|
||||
} break;
|
||||
case kUpb_CType_String:
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "upb/message/internal/extension.h"
|
||||
#include "upb/message/internal/map.h"
|
||||
#include "upb/message/internal/message.h"
|
||||
#include "upb/message/internal/tagged_ptr.h"
|
||||
#include "upb/message/internal/types.h"
|
||||
#include "upb/message/value.h"
|
||||
#include "upb/mini_table/enum.h"
|
||||
|
|
@ -417,57 +416,24 @@ UPB_API_INLINE int64_t upb_Message_GetInt64(const struct upb_Message* msg,
|
|||
return upb_Message_GetField(msg, f, def).int64_val;
|
||||
}
|
||||
|
||||
UPB_INLINE void UPB_PRIVATE(_upb_Message_AssertMapIsUntagged)(
|
||||
const struct upb_Message* msg, const upb_MiniTableField* field) {
|
||||
UPB_UNUSED(msg);
|
||||
UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)(field);
|
||||
#ifndef NDEBUG
|
||||
uintptr_t default_val = 0;
|
||||
uintptr_t tagged;
|
||||
_upb_Message_GetNonExtensionField(msg, field, &default_val, &tagged);
|
||||
UPB_ASSERT(!upb_TaggedMessagePtr_IsEmpty(tagged));
|
||||
#endif
|
||||
}
|
||||
|
||||
UPB_API_INLINE const struct upb_Map* upb_Message_GetMap(
|
||||
const struct upb_Message* msg, const upb_MiniTableField* f) {
|
||||
UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)(f);
|
||||
UPB_PRIVATE(_upb_Message_AssertMapIsUntagged)(msg, f);
|
||||
struct upb_Map* ret;
|
||||
const struct upb_Map* default_val = NULL;
|
||||
_upb_Message_GetNonExtensionField(msg, f, &default_val, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
UPB_API_INLINE uintptr_t upb_Message_GetTaggedMessagePtr(
|
||||
const struct upb_Message* msg, const upb_MiniTableField* f,
|
||||
struct upb_Message* default_val) {
|
||||
UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message);
|
||||
UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) ==
|
||||
UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte));
|
||||
UPB_ASSUME(upb_MiniTableField_IsScalar(f));
|
||||
uintptr_t tagged;
|
||||
_upb_Message_GetNonExtensionField(msg, f, &default_val, &tagged);
|
||||
return tagged;
|
||||
}
|
||||
|
||||
// For internal use only; users cannot set tagged messages because only the
|
||||
// parser and the message copier are allowed to directly create an empty
|
||||
// message.
|
||||
UPB_INLINE void UPB_PRIVATE(_upb_Message_SetTaggedMessagePtr)(
|
||||
struct upb_Message* msg, const upb_MiniTableField* f,
|
||||
uintptr_t sub_message) {
|
||||
UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message);
|
||||
UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) ==
|
||||
UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte));
|
||||
UPB_ASSUME(upb_MiniTableField_IsScalar(f));
|
||||
upb_Message_SetBaseField(msg, f, &sub_message);
|
||||
}
|
||||
|
||||
UPB_API_INLINE const struct upb_Message* upb_Message_GetMessage(
|
||||
const struct upb_Message* msg, const upb_MiniTableField* f) {
|
||||
uintptr_t tagged = upb_Message_GetTaggedMessagePtr(msg, f, NULL);
|
||||
return upb_TaggedMessagePtr_GetNonEmptyMessage(tagged);
|
||||
UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message);
|
||||
UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) ==
|
||||
UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte));
|
||||
UPB_ASSUME(upb_MiniTableField_IsScalar(f));
|
||||
upb_MessageValue def;
|
||||
def.msg_val = NULL;
|
||||
return upb_Message_GetField(msg, f, def).msg_val;
|
||||
}
|
||||
|
||||
UPB_API_INLINE upb_Array* upb_Message_GetMutableArray(
|
||||
|
|
@ -507,7 +473,6 @@ UPB_INLINE struct upb_Map* _upb_Message_GetOrCreateMutableMap(
|
|||
struct upb_Message* msg, const upb_MiniTableField* field, size_t key_size,
|
||||
size_t val_size, upb_Arena* arena) {
|
||||
UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)(field);
|
||||
UPB_PRIVATE(_upb_Message_AssertMapIsUntagged)(msg, field);
|
||||
struct upb_Map* map = NULL;
|
||||
struct upb_Map* default_map_value = NULL;
|
||||
_upb_Message_GetNonExtensionField(msg, field, &default_map_value, &map);
|
||||
|
|
@ -642,8 +607,12 @@ UPB_API_INLINE void upb_Message_SetBaseFieldInt64(struct upb_Message* msg,
|
|||
UPB_API_INLINE void upb_Message_SetBaseFieldMessage(struct upb_Message* msg,
|
||||
const upb_MiniTableField* f,
|
||||
struct upb_Message* value) {
|
||||
UPB_PRIVATE(_upb_Message_SetTaggedMessagePtr)
|
||||
(msg, f, UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(value, false));
|
||||
// TODO - Re-enable this assertion.
|
||||
// UPB_ASSERT(value);
|
||||
UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message);
|
||||
UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) ==
|
||||
UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte));
|
||||
upb_Message_SetBaseField(msg, f, &value);
|
||||
}
|
||||
|
||||
UPB_API_INLINE void upb_Message_SetBaseFieldString(struct upb_Message* msg,
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 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
|
||||
|
||||
#ifndef UPB_MINI_TABLE_INTERNAL_TAGGED_PTR_H_
|
||||
#define UPB_MINI_TABLE_INTERNAL_TAGGED_PTR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "upb/message/internal/message.h"
|
||||
|
||||
// Must be last.
|
||||
#include "upb/port/def.inc"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Internal-only because empty messages cannot be created by the user.
|
||||
UPB_INLINE uintptr_t
|
||||
UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(struct upb_Message* ptr, bool empty) {
|
||||
UPB_ASSERT(((uintptr_t)ptr & 1) == 0);
|
||||
return (uintptr_t)ptr | (empty ? 1 : 0);
|
||||
}
|
||||
|
||||
UPB_API_INLINE bool upb_TaggedMessagePtr_IsEmpty(uintptr_t ptr) {
|
||||
return ptr & 1;
|
||||
}
|
||||
|
||||
UPB_INLINE struct upb_Message* UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(
|
||||
uintptr_t ptr) {
|
||||
return (struct upb_Message*)(ptr & ~(uintptr_t)1);
|
||||
}
|
||||
|
||||
UPB_API_INLINE struct upb_Message* upb_TaggedMessagePtr_GetNonEmptyMessage(
|
||||
uintptr_t ptr) {
|
||||
UPB_ASSERT(!upb_TaggedMessagePtr_IsEmpty(ptr));
|
||||
return UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(ptr);
|
||||
}
|
||||
|
||||
UPB_INLINE struct upb_Message* UPB_PRIVATE(
|
||||
_upb_TaggedMessagePtr_GetEmptyMessage)(uintptr_t ptr) {
|
||||
UPB_ASSERT(upb_TaggedMessagePtr_IsEmpty(ptr));
|
||||
return UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(ptr);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#include "upb/port/undef.inc"
|
||||
|
||||
#endif /* UPB_MINI_TABLE_INTERNAL_TAGGED_PTR_H_ */
|
||||
|
|
@ -19,10 +19,8 @@
|
|||
#include "upb/message/internal/array.h"
|
||||
#include "upb/message/internal/extension.h"
|
||||
#include "upb/message/internal/message.h"
|
||||
#include "upb/message/internal/tagged_ptr.h"
|
||||
#include "upb/message/map.h"
|
||||
#include "upb/message/message.h"
|
||||
#include "upb/message/tagged_ptr.h"
|
||||
#include "upb/mini_table/extension.h"
|
||||
#include "upb/mini_table/field.h"
|
||||
#include "upb/mini_table/message.h"
|
||||
|
|
@ -191,86 +189,6 @@ upb_FindUnknownRet upb_Message_FindUnknown(const upb_Message* msg,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static upb_DecodeStatus upb_Message_PromoteOne(upb_TaggedMessagePtr* tagged,
|
||||
const upb_MiniTable* mini_table,
|
||||
int decode_options,
|
||||
upb_Arena* arena) {
|
||||
upb_Message* empty =
|
||||
UPB_PRIVATE(_upb_TaggedMessagePtr_GetEmptyMessage)(*tagged);
|
||||
upb_Message* promoted = upb_Message_New(mini_table, arena);
|
||||
if (!promoted) return kUpb_DecodeStatus_OutOfMemory;
|
||||
upb_StringView unknown_data;
|
||||
uintptr_t iter = kUpb_Message_UnknownBegin;
|
||||
while (upb_Message_NextUnknown(empty, &unknown_data, &iter)) {
|
||||
upb_DecodeStatus status =
|
||||
upb_Decode(unknown_data.data, unknown_data.size, promoted, mini_table,
|
||||
NULL, decode_options, arena);
|
||||
if (status != kUpb_DecodeStatus_Ok) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
*tagged = UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(promoted, false);
|
||||
return kUpb_DecodeStatus_Ok;
|
||||
}
|
||||
|
||||
upb_DecodeStatus upb_Message_PromoteMessage(upb_Message* parent,
|
||||
const upb_MiniTable* mini_table,
|
||||
const upb_MiniTableField* field,
|
||||
int decode_options,
|
||||
upb_Arena* arena,
|
||||
upb_Message** promoted) {
|
||||
UPB_ASSERT(!upb_Message_IsFrozen(parent));
|
||||
const upb_MiniTable* sub_table =
|
||||
upb_MiniTable_GetSubMessageTable(mini_table, field);
|
||||
UPB_ASSERT(sub_table);
|
||||
upb_TaggedMessagePtr tagged =
|
||||
upb_Message_GetTaggedMessagePtr(parent, field, NULL);
|
||||
upb_DecodeStatus ret =
|
||||
upb_Message_PromoteOne(&tagged, sub_table, decode_options, arena);
|
||||
if (ret == kUpb_DecodeStatus_Ok) {
|
||||
*promoted = upb_TaggedMessagePtr_GetNonEmptyMessage(tagged);
|
||||
upb_Message_SetMessage(parent, field, *promoted);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
upb_DecodeStatus upb_Array_PromoteMessages(upb_Array* arr,
|
||||
const upb_MiniTable* mini_table,
|
||||
int decode_options,
|
||||
upb_Arena* arena) {
|
||||
void** data = upb_Array_MutableDataPtr(arr);
|
||||
size_t size = upb_Array_Size(arr);
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
upb_TaggedMessagePtr tagged;
|
||||
memcpy(&tagged, &data[i], sizeof(tagged));
|
||||
if (!upb_TaggedMessagePtr_IsEmpty(tagged)) continue;
|
||||
upb_DecodeStatus status =
|
||||
upb_Message_PromoteOne(&tagged, mini_table, decode_options, arena);
|
||||
if (status != kUpb_DecodeStatus_Ok) return status;
|
||||
memcpy(&data[i], &tagged, sizeof(tagged));
|
||||
}
|
||||
return kUpb_DecodeStatus_Ok;
|
||||
}
|
||||
|
||||
upb_DecodeStatus upb_Map_PromoteMessages(upb_Map* map,
|
||||
const upb_MiniTable* mini_table,
|
||||
int decode_options, upb_Arena* arena) {
|
||||
size_t iter = kUpb_Map_Begin;
|
||||
upb_MessageValue key, val;
|
||||
while (upb_Map_Next(map, &key, &val, &iter)) {
|
||||
if (!upb_TaggedMessagePtr_IsEmpty(val.tagged_msg_val)) continue;
|
||||
upb_DecodeStatus status = upb_Message_PromoteOne(
|
||||
&val.tagged_msg_val, mini_table, decode_options, arena);
|
||||
if (status != kUpb_DecodeStatus_Ok) return status;
|
||||
upb_Map_SetEntryValue(map, iter, val);
|
||||
}
|
||||
return kUpb_DecodeStatus_Ok;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// OLD promotion functions, will be removed!
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Warning: See TODO
|
||||
upb_UnknownToMessageRet upb_MiniTable_PromoteUnknownToMessage(
|
||||
upb_Message* msg, const upb_MiniTable* mini_table,
|
||||
|
|
|
|||
|
|
@ -8,10 +8,16 @@
|
|||
#ifndef UPB_MESSAGE_PROMOTE_H_
|
||||
#define UPB_MESSAGE_PROMOTE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "upb/mem/arena.h"
|
||||
#include "upb/message/array.h"
|
||||
#include "upb/message/map.h"
|
||||
#include "upb/message/message.h"
|
||||
#include "upb/message/value.h"
|
||||
#include "upb/wire/decode.h"
|
||||
#include "upb/mini_table/extension.h"
|
||||
#include "upb/mini_table/field.h"
|
||||
#include "upb/mini_table/message.h"
|
||||
|
||||
// Must be last.
|
||||
#include "upb/port/def.inc"
|
||||
|
|
@ -74,57 +80,10 @@ typedef struct {
|
|||
upb_Message* message;
|
||||
} upb_UnknownToMessageRet;
|
||||
|
||||
// Promotes an "empty" non-repeated message field in `parent` to a message of
|
||||
// the correct type.
|
||||
//
|
||||
// Preconditions:
|
||||
//
|
||||
// 1. The message field must currently be in the "empty" state (this must have
|
||||
// been previously verified by the caller by calling
|
||||
// `upb_Message_GetTaggedMessagePtr()` and observing that the message is
|
||||
// indeed empty).
|
||||
//
|
||||
// 2. This `field` must have previously been linked.
|
||||
//
|
||||
// If the promotion succeeds, `parent` will have its data for `field` replaced
|
||||
// by the promoted message, which is also returned in `*promoted`. If the
|
||||
// return value indicates an error status, `parent` and `promoted` are
|
||||
// unchanged.
|
||||
upb_DecodeStatus upb_Message_PromoteMessage(upb_Message* parent,
|
||||
const upb_MiniTable* mini_table,
|
||||
const upb_MiniTableField* field,
|
||||
int decode_options,
|
||||
upb_Arena* arena,
|
||||
upb_Message** promoted);
|
||||
|
||||
// Promotes any "empty" messages in this array to a message of the correct type
|
||||
// `mini_table`. This function should only be called for arrays of messages.
|
||||
//
|
||||
// If the return value indicates an error status, some but not all elements may
|
||||
// have been promoted, but the array itself will not be corrupted.
|
||||
upb_DecodeStatus upb_Array_PromoteMessages(upb_Array* arr,
|
||||
const upb_MiniTable* mini_table,
|
||||
int decode_options,
|
||||
upb_Arena* arena);
|
||||
|
||||
// Promotes any "empty" entries in this map to a message of the correct type
|
||||
// `mini_table`. This function should only be called for maps that have a
|
||||
// message type as the map value.
|
||||
//
|
||||
// If the return value indicates an error status, some but not all elements may
|
||||
// have been promoted, but the map itself will not be corrupted.
|
||||
upb_DecodeStatus upb_Map_PromoteMessages(upb_Map* map,
|
||||
const upb_MiniTable* mini_table,
|
||||
int decode_options, upb_Arena* arena);
|
||||
|
||||
// Utility function for wrapper languages to get an error string from a
|
||||
// upb_UnknownToMessageStatus.
|
||||
const char* upb_FindUnknownStatus_String(upb_FindUnknown_Status status);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// OLD promotion interfaces, will be removed!
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Promotes unknown data inside message to a upb_Message parsing the unknown.
|
||||
//
|
||||
// The unknown data is removed from message after field value is set
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@
|
|||
#include "upb/message/internal/message.h"
|
||||
#include "upb/message/map.h"
|
||||
#include "upb/message/message.h"
|
||||
#include "upb/message/tagged_ptr.h"
|
||||
#include "upb/mini_descriptor/decode.h"
|
||||
#include "upb/mini_descriptor/internal/encode.hpp"
|
||||
#include "upb/mini_descriptor/internal/modifiers.h"
|
||||
|
|
@ -307,425 +306,6 @@ TEST(GeneratedCode, Extensions) {
|
|||
upb_Arena_Free(arena);
|
||||
}
|
||||
|
||||
// Create a minitable to mimic ModelWithSubMessages with unlinked subs
|
||||
// to lazily promote unknowns after parsing.
|
||||
upb_MiniTable* CreateMiniTableWithEmptySubTables(upb_Arena* arena) {
|
||||
upb::MtDataEncoder e;
|
||||
e.StartMessage(0);
|
||||
e.PutField(kUpb_FieldType_Int32, 4, 0);
|
||||
e.PutField(kUpb_FieldType_Message, 5, 0);
|
||||
e.PutField(kUpb_FieldType_Message, 6, kUpb_FieldModifier_IsRepeated);
|
||||
|
||||
upb_Status status;
|
||||
upb_Status_Clear(&status);
|
||||
upb_MiniTable* table =
|
||||
upb_MiniTable_Build(e.data().data(), e.data().size(), arena, &status);
|
||||
EXPECT_EQ(status.ok, true);
|
||||
return table;
|
||||
}
|
||||
|
||||
upb_MiniTable* CreateMapEntryMiniTable(upb_Arena* arena) {
|
||||
upb::MtDataEncoder e;
|
||||
e.EncodeMap(kUpb_FieldType_Int32, kUpb_FieldType_Message, 0, 0);
|
||||
upb_Status status;
|
||||
upb_Status_Clear(&status);
|
||||
upb_MiniTable* table =
|
||||
upb_MiniTable_Build(e.data().data(), e.data().size(), arena, &status);
|
||||
EXPECT_EQ(status.ok, true);
|
||||
return table;
|
||||
}
|
||||
|
||||
// Create a minitable to mimic ModelWithMaps with unlinked subs
|
||||
// to lazily promote unknowns after parsing.
|
||||
upb_MiniTable* CreateMiniTableWithEmptySubTablesForMaps(upb_Arena* arena) {
|
||||
upb::MtDataEncoder e;
|
||||
e.StartMessage(0);
|
||||
e.PutField(kUpb_FieldType_Int32, 1, 0);
|
||||
e.PutField(kUpb_FieldType_Message, 3, kUpb_FieldModifier_IsRepeated);
|
||||
e.PutField(kUpb_FieldType_Message, 5, kUpb_FieldModifier_IsRepeated);
|
||||
|
||||
upb_Status status;
|
||||
upb_Status_Clear(&status);
|
||||
upb_MiniTable* table =
|
||||
upb_MiniTable_Build(e.data().data(), e.data().size(), arena, &status);
|
||||
|
||||
// Field 5 corresponds to ModelWithMaps.map_sm.
|
||||
upb_MiniTableField* map_field = const_cast<upb_MiniTableField*>(
|
||||
upb_MiniTable_FindFieldByNumber(table, 5));
|
||||
EXPECT_NE(map_field, nullptr);
|
||||
upb_MiniTable* sub_table = CreateMapEntryMiniTable(arena);
|
||||
upb_MiniTable_SetSubMessage(table, map_field, sub_table);
|
||||
EXPECT_EQ(status.ok, true);
|
||||
return table;
|
||||
}
|
||||
|
||||
void CheckReserialize(const upb_Message* msg, const upb_MiniTable* mini_table,
|
||||
upb_Arena* arena, char* serialized,
|
||||
size_t serialized_size) {
|
||||
// We can safely encode the "empty" message. We expect to get the same bytes
|
||||
// out as were parsed.
|
||||
size_t reserialized_size;
|
||||
char* reserialized;
|
||||
upb_EncodeStatus encode_status =
|
||||
upb_Encode(msg, mini_table, kUpb_EncodeOption_Deterministic, arena,
|
||||
&reserialized, &reserialized_size);
|
||||
EXPECT_EQ(encode_status, kUpb_EncodeStatus_Ok);
|
||||
EXPECT_EQ(reserialized_size, serialized_size);
|
||||
EXPECT_EQ(0, memcmp(reserialized, serialized, serialized_size));
|
||||
|
||||
// We should get the same result if we copy+reserialize.
|
||||
upb_Message* clone = upb_Message_DeepClone(msg, mini_table, arena);
|
||||
encode_status = upb_Encode(clone, mini_table, kUpb_EncodeOption_Deterministic,
|
||||
arena, &reserialized, &reserialized_size);
|
||||
EXPECT_EQ(encode_status, kUpb_EncodeStatus_Ok);
|
||||
EXPECT_EQ(reserialized_size, serialized_size);
|
||||
EXPECT_EQ(0, memcmp(reserialized, serialized, serialized_size));
|
||||
}
|
||||
|
||||
TEST(GeneratedCode, PromoteUnknownMessage) {
|
||||
upb::Arena arena;
|
||||
upb_test_ModelWithSubMessages* input_msg =
|
||||
upb_test_ModelWithSubMessages_new(arena.ptr());
|
||||
upb_test_ModelWithExtensions* sub_message =
|
||||
upb_test_ModelWithExtensions_new(arena.ptr());
|
||||
upb_test_ModelWithSubMessages_set_id(input_msg, 11);
|
||||
upb_test_ModelWithExtensions_set_random_int32(sub_message, 12);
|
||||
upb_test_ModelWithSubMessages_set_optional_child(input_msg, sub_message);
|
||||
size_t serialized_size;
|
||||
char* serialized = upb_test_ModelWithSubMessages_serialize(
|
||||
input_msg, arena.ptr(), &serialized_size);
|
||||
|
||||
upb_MiniTable* mini_table = CreateMiniTableWithEmptySubTables(arena.ptr());
|
||||
upb_DecodeStatus decode_status;
|
||||
|
||||
// If we parse without allowing unlinked objects, the parse will fail.
|
||||
// TODO: re-enable this test once the old method of tree shaking is
|
||||
// removed
|
||||
// upb_Message* fail_msg = _upb_Message_New(mini_table, arena.ptr());
|
||||
// decode_status =
|
||||
// upb_Decode(serialized, serialized_size, fail_msg, mini_table, nullptr,
|
||||
// 0,
|
||||
// arena.ptr());
|
||||
// EXPECT_EQ(decode_status, kUpb_DecodeStatus_UnlinkedSubMessage);
|
||||
|
||||
// if we parse while allowing unlinked objects, the parse will succeed.
|
||||
upb_Message* msg = _upb_Message_New(mini_table, arena.ptr());
|
||||
decode_status =
|
||||
upb_Decode(serialized, serialized_size, msg, mini_table, nullptr,
|
||||
kUpb_DecodeOption_ExperimentalAllowUnlinked, arena.ptr());
|
||||
EXPECT_EQ(decode_status, kUpb_DecodeStatus_Ok);
|
||||
|
||||
CheckReserialize(msg, mini_table, arena.ptr(), serialized, serialized_size);
|
||||
|
||||
// We can encode the "empty" message and get the same output bytes.
|
||||
size_t reserialized_size;
|
||||
char* reserialized;
|
||||
upb_EncodeStatus encode_status = upb_Encode(
|
||||
msg, mini_table, 0, arena.ptr(), &reserialized, &reserialized_size);
|
||||
EXPECT_EQ(encode_status, kUpb_EncodeStatus_Ok);
|
||||
EXPECT_EQ(reserialized_size, serialized_size);
|
||||
EXPECT_EQ(0, memcmp(reserialized, serialized, serialized_size));
|
||||
|
||||
// Int32 field is present, as normal.
|
||||
int32_t val = upb_Message_GetInt32(
|
||||
msg, upb_MiniTable_FindFieldByNumber(mini_table, 4), 0);
|
||||
EXPECT_EQ(val, 11);
|
||||
|
||||
// Unlinked sub-message is present, but getting the value returns NULL.
|
||||
const upb_MiniTableField* submsg_field =
|
||||
upb_MiniTable_FindFieldByNumber(mini_table, 5);
|
||||
ASSERT_TRUE(submsg_field != nullptr);
|
||||
EXPECT_TRUE(upb_Message_HasBaseField(msg, submsg_field));
|
||||
upb_TaggedMessagePtr tagged =
|
||||
upb_Message_GetTaggedMessagePtr(msg, submsg_field, nullptr);
|
||||
EXPECT_TRUE(upb_TaggedMessagePtr_IsEmpty(tagged));
|
||||
|
||||
// Update mini table and promote unknown to a message.
|
||||
EXPECT_TRUE(
|
||||
upb_MiniTable_SetSubMessage(mini_table, (upb_MiniTableField*)submsg_field,
|
||||
&upb_0test__ModelWithExtensions_msg_init));
|
||||
|
||||
const int decode_options =
|
||||
upb_DecodeOptions_MaxDepth(0); // UPB_DECODE_ALIAS disabled.
|
||||
upb_test_ModelWithExtensions* promoted;
|
||||
upb_DecodeStatus promote_result =
|
||||
upb_Message_PromoteMessage(msg, mini_table, submsg_field, decode_options,
|
||||
arena.ptr(), (upb_Message**)&promoted);
|
||||
EXPECT_EQ(promote_result, kUpb_DecodeStatus_Ok);
|
||||
EXPECT_NE(nullptr, promoted);
|
||||
EXPECT_EQ(UPB_UPCAST(promoted), upb_Message_GetMessage(msg, submsg_field));
|
||||
EXPECT_EQ(upb_test_ModelWithExtensions_random_int32(promoted), 12);
|
||||
}
|
||||
|
||||
// Tests a second parse that reuses an empty/unlinked message while the message
|
||||
// is still unlinked.
|
||||
TEST(GeneratedCode, ReparseUnlinked) {
|
||||
upb::Arena arena;
|
||||
upb_test_ModelWithSubMessages* input_msg =
|
||||
upb_test_ModelWithSubMessages_new(arena.ptr());
|
||||
upb_test_ModelWithExtensions* sub_message =
|
||||
upb_test_ModelWithExtensions_new(arena.ptr());
|
||||
upb_test_ModelWithSubMessages_set_id(input_msg, 11);
|
||||
upb_test_ModelWithExtensions_add_repeated_int32(sub_message, 12, arena.ptr());
|
||||
upb_test_ModelWithSubMessages_set_optional_child(input_msg, sub_message);
|
||||
size_t serialized_size;
|
||||
char* serialized = upb_test_ModelWithSubMessages_serialize(
|
||||
input_msg, arena.ptr(), &serialized_size);
|
||||
|
||||
upb_MiniTable* mini_table = CreateMiniTableWithEmptySubTables(arena.ptr());
|
||||
|
||||
// Parse twice without linking the MiniTable.
|
||||
upb_Message* msg = _upb_Message_New(mini_table, arena.ptr());
|
||||
upb_DecodeStatus decode_status =
|
||||
upb_Decode(serialized, serialized_size, msg, mini_table, nullptr,
|
||||
kUpb_DecodeOption_ExperimentalAllowUnlinked, arena.ptr());
|
||||
EXPECT_EQ(decode_status, kUpb_DecodeStatus_Ok);
|
||||
|
||||
decode_status =
|
||||
upb_Decode(serialized, serialized_size, msg, mini_table, nullptr,
|
||||
kUpb_DecodeOption_ExperimentalAllowUnlinked, arena.ptr());
|
||||
EXPECT_EQ(decode_status, kUpb_DecodeStatus_Ok);
|
||||
|
||||
// Update mini table and promote unknown to a message.
|
||||
const upb_MiniTableField* submsg_field =
|
||||
upb_MiniTable_FindFieldByNumber(mini_table, 5);
|
||||
EXPECT_TRUE(
|
||||
upb_MiniTable_SetSubMessage(mini_table, (upb_MiniTableField*)submsg_field,
|
||||
&upb_0test__ModelWithExtensions_msg_init));
|
||||
|
||||
const int decode_options =
|
||||
upb_DecodeOptions_MaxDepth(0); // UPB_DECODE_ALIAS disabled.
|
||||
upb_test_ModelWithExtensions* promoted;
|
||||
upb_DecodeStatus promote_result =
|
||||
upb_Message_PromoteMessage(msg, mini_table, submsg_field, decode_options,
|
||||
arena.ptr(), (upb_Message**)&promoted);
|
||||
EXPECT_EQ(promote_result, kUpb_DecodeStatus_Ok);
|
||||
EXPECT_NE(nullptr, promoted);
|
||||
EXPECT_EQ(UPB_UPCAST(promoted), upb_Message_GetMessage(msg, submsg_field));
|
||||
|
||||
// The repeated field should have two entries for the two parses.
|
||||
size_t repeated_size;
|
||||
const int32_t* entries =
|
||||
upb_test_ModelWithExtensions_repeated_int32(promoted, &repeated_size);
|
||||
EXPECT_EQ(repeated_size, 2);
|
||||
EXPECT_EQ(entries[0], 12);
|
||||
EXPECT_EQ(entries[1], 12);
|
||||
}
|
||||
|
||||
// Tests a second parse that promotes a message within the parser because we are
|
||||
// merging into an empty/unlinked message after the message has been linked.
|
||||
TEST(GeneratedCode, PromoteInParser) {
|
||||
upb::Arena arena;
|
||||
upb_test_ModelWithSubMessages* input_msg =
|
||||
upb_test_ModelWithSubMessages_new(arena.ptr());
|
||||
upb_test_ModelWithExtensions* sub_message =
|
||||
upb_test_ModelWithExtensions_new(arena.ptr());
|
||||
upb_test_ModelWithSubMessages_set_id(input_msg, 11);
|
||||
upb_test_ModelWithExtensions_add_repeated_int32(sub_message, 12, arena.ptr());
|
||||
upb_test_ModelWithSubMessages_set_optional_child(input_msg, sub_message);
|
||||
size_t serialized_size;
|
||||
char* serialized = upb_test_ModelWithSubMessages_serialize(
|
||||
input_msg, arena.ptr(), &serialized_size);
|
||||
|
||||
upb_MiniTable* mini_table = CreateMiniTableWithEmptySubTables(arena.ptr());
|
||||
|
||||
// Parse once without linking the MiniTable.
|
||||
upb_Message* msg = _upb_Message_New(mini_table, arena.ptr());
|
||||
upb_DecodeStatus decode_status =
|
||||
upb_Decode(serialized, serialized_size, msg, mini_table, nullptr,
|
||||
kUpb_DecodeOption_ExperimentalAllowUnlinked, arena.ptr());
|
||||
EXPECT_EQ(decode_status, kUpb_DecodeStatus_Ok);
|
||||
|
||||
// Link the MiniTable.
|
||||
const upb_MiniTableField* submsg_field =
|
||||
upb_MiniTable_FindFieldByNumber(mini_table, 5);
|
||||
EXPECT_TRUE(
|
||||
upb_MiniTable_SetSubMessage(mini_table, (upb_MiniTableField*)submsg_field,
|
||||
&upb_0test__ModelWithExtensions_msg_init));
|
||||
|
||||
// Parse again. This will promote the message. An explicit promote will not
|
||||
// be required.
|
||||
decode_status =
|
||||
upb_Decode(serialized, serialized_size, msg, mini_table, nullptr,
|
||||
kUpb_DecodeOption_ExperimentalAllowUnlinked, arena.ptr());
|
||||
EXPECT_EQ(decode_status, kUpb_DecodeStatus_Ok);
|
||||
upb_test_ModelWithExtensions* promoted =
|
||||
(upb_test_ModelWithExtensions*)upb_Message_GetMessage(msg, submsg_field);
|
||||
|
||||
EXPECT_NE(nullptr, promoted);
|
||||
EXPECT_EQ(UPB_UPCAST(promoted), upb_Message_GetMessage(msg, submsg_field));
|
||||
|
||||
// The repeated field should have two entries for the two parses.
|
||||
size_t repeated_size;
|
||||
const int32_t* entries =
|
||||
upb_test_ModelWithExtensions_repeated_int32(promoted, &repeated_size);
|
||||
EXPECT_EQ(repeated_size, 2);
|
||||
EXPECT_EQ(entries[0], 12);
|
||||
EXPECT_EQ(entries[1], 12);
|
||||
}
|
||||
|
||||
TEST(GeneratedCode, PromoteUnknownRepeatedMessage) {
|
||||
upb::Arena arena;
|
||||
upb_test_ModelWithSubMessages* input_msg =
|
||||
upb_test_ModelWithSubMessages_new(arena.ptr());
|
||||
upb_test_ModelWithSubMessages_set_id(input_msg, 123);
|
||||
|
||||
// Add 2 repeated messages to input_msg.
|
||||
upb_test_ModelWithExtensions* item =
|
||||
upb_test_ModelWithSubMessages_add_items(input_msg, arena.ptr());
|
||||
upb_test_ModelWithExtensions_set_random_int32(item, 5);
|
||||
item = upb_test_ModelWithSubMessages_add_items(input_msg, arena.ptr());
|
||||
upb_test_ModelWithExtensions_set_random_int32(item, 6);
|
||||
|
||||
size_t serialized_size;
|
||||
char* serialized = upb_test_ModelWithSubMessages_serialize(
|
||||
input_msg, arena.ptr(), &serialized_size);
|
||||
|
||||
upb_MiniTable* mini_table = CreateMiniTableWithEmptySubTables(arena.ptr());
|
||||
upb_DecodeStatus decode_status;
|
||||
|
||||
// If we parse without allowing unlinked objects, the parse will fail.
|
||||
// TODO: re-enable this test once the old method of tree shaking is
|
||||
// removed
|
||||
// upb_Message* fail_msg = _upb_Message_New(mini_table, arena.ptr());
|
||||
// decode_status =
|
||||
// upb_Decode(serialized, serialized_size, fail_msg, mini_table, nullptr,
|
||||
// 0,
|
||||
// arena.ptr());
|
||||
// EXPECT_EQ(decode_status, kUpb_DecodeStatus_UnlinkedSubMessage);
|
||||
|
||||
// if we parse while allowing unlinked objects, the parse will succeed.
|
||||
upb_Message* msg = _upb_Message_New(mini_table, arena.ptr());
|
||||
decode_status =
|
||||
upb_Decode(serialized, serialized_size, msg, mini_table, nullptr,
|
||||
kUpb_DecodeOption_ExperimentalAllowUnlinked, arena.ptr());
|
||||
|
||||
CheckReserialize(msg, mini_table, arena.ptr(), serialized, serialized_size);
|
||||
|
||||
// Int32 field is present, as normal.
|
||||
EXPECT_EQ(decode_status, kUpb_DecodeStatus_Ok);
|
||||
int32_t val = upb_Message_GetInt32(
|
||||
msg, upb_MiniTable_FindFieldByNumber(mini_table, 4), 0);
|
||||
EXPECT_EQ(val, 123);
|
||||
|
||||
const upb_MiniTableField* repeated_field =
|
||||
upb_MiniTable_FindFieldByNumber(mini_table, 6);
|
||||
|
||||
upb_Array* array = upb_Message_GetMutableArray(msg, repeated_field);
|
||||
|
||||
// Array length is 2 even though the messages are empty.
|
||||
EXPECT_EQ(2, upb_Array_Size(array));
|
||||
|
||||
// Update mini table and promote unknown to a message.
|
||||
EXPECT_TRUE(upb_MiniTable_SetSubMessage(
|
||||
mini_table, (upb_MiniTableField*)repeated_field,
|
||||
&upb_0test__ModelWithExtensions_msg_init));
|
||||
const int decode_options =
|
||||
upb_DecodeOptions_MaxDepth(0); // UPB_DECODE_ALIAS disabled.
|
||||
upb_DecodeStatus promote_result =
|
||||
upb_Array_PromoteMessages(array, &upb_0test__ModelWithExtensions_msg_init,
|
||||
decode_options, arena.ptr());
|
||||
EXPECT_EQ(promote_result, kUpb_DecodeStatus_Ok);
|
||||
const upb_Message* promoted_message = upb_Array_Get(array, 0).msg_val;
|
||||
EXPECT_EQ(upb_test_ModelWithExtensions_random_int32(
|
||||
(upb_test_ModelWithExtensions*)promoted_message),
|
||||
5);
|
||||
promoted_message = upb_Array_Get(array, 1).msg_val;
|
||||
EXPECT_EQ(upb_test_ModelWithExtensions_random_int32(
|
||||
(upb_test_ModelWithExtensions*)promoted_message),
|
||||
6);
|
||||
}
|
||||
|
||||
TEST(GeneratedCode, PromoteUnknownToMap) {
|
||||
upb::Arena arena;
|
||||
upb_test_ModelWithMaps* input_msg = upb_test_ModelWithMaps_new(arena.ptr());
|
||||
upb_test_ModelWithMaps_set_id(input_msg, 123);
|
||||
|
||||
upb_test_ModelWithExtensions* submsg0 =
|
||||
upb_test_ModelWithExtensions_new(arena.ptr());
|
||||
upb_test_ModelWithExtensions_set_random_int32(submsg0, 100);
|
||||
upb_test_ModelWithExtensions* submsg1 =
|
||||
upb_test_ModelWithExtensions_new(arena.ptr());
|
||||
upb_test_ModelWithExtensions_set_random_int32(submsg1, 123);
|
||||
upb_test_ModelWithExtensions* submsg2 =
|
||||
upb_test_ModelWithExtensions_new(arena.ptr());
|
||||
upb_test_ModelWithExtensions_set_random_int32(submsg2, 456);
|
||||
|
||||
// Add 3 map entries.
|
||||
upb_test_ModelWithMaps_map_im_set(input_msg, 0, submsg0, arena.ptr());
|
||||
upb_test_ModelWithMaps_map_im_set(input_msg, 111, submsg1, arena.ptr());
|
||||
upb_test_ModelWithMaps_map_im_set(input_msg, 222, submsg2, arena.ptr());
|
||||
|
||||
size_t serialized_size;
|
||||
char* serialized = upb_test_ModelWithMaps_serialize_ex(
|
||||
input_msg, kUpb_EncodeOption_Deterministic, arena.ptr(),
|
||||
&serialized_size);
|
||||
|
||||
upb_MiniTable* mini_table =
|
||||
CreateMiniTableWithEmptySubTablesForMaps(arena.ptr());
|
||||
|
||||
// If we parse without allowing unlinked objects, the parse will fail.
|
||||
upb_Message* fail_msg1 = _upb_Message_New(mini_table, arena.ptr());
|
||||
upb_DecodeStatus decode_status =
|
||||
upb_Decode(serialized, serialized_size, fail_msg1, mini_table, nullptr, 0,
|
||||
arena.ptr());
|
||||
EXPECT_EQ(decode_status, kUpb_DecodeStatus_UnlinkedSubMessage);
|
||||
|
||||
// if we parse while allowing unlinked objects, the parse will succeed.
|
||||
upb_Message* msg = _upb_Message_New(mini_table, arena.ptr());
|
||||
decode_status =
|
||||
upb_Decode(serialized, serialized_size, msg, mini_table, nullptr,
|
||||
kUpb_DecodeOption_ExperimentalAllowUnlinked, arena.ptr());
|
||||
EXPECT_EQ(decode_status, kUpb_DecodeStatus_Ok);
|
||||
|
||||
CheckReserialize(msg, mini_table, arena.ptr(), serialized, serialized_size);
|
||||
|
||||
upb_MiniTableField* map_field = const_cast<upb_MiniTableField*>(
|
||||
upb_MiniTable_FindFieldByNumber(mini_table, 5));
|
||||
|
||||
upb_Map* map = upb_Message_GetMutableMap(msg, map_field);
|
||||
|
||||
// Map size is 3 even though messages are unlinked.
|
||||
EXPECT_EQ(3, upb_Map_Size(map));
|
||||
|
||||
// Update mini table and promote unknown to a message.
|
||||
upb_MiniTable* entry = const_cast<upb_MiniTable*>(
|
||||
upb_MiniTable_GetSubMessageTable(mini_table, map_field));
|
||||
upb_MiniTableField* entry_value = const_cast<upb_MiniTableField*>(
|
||||
upb_MiniTable_FindFieldByNumber(entry, 2));
|
||||
upb_MiniTable_SetSubMessage(entry, entry_value,
|
||||
&upb_0test__ModelWithExtensions_msg_init);
|
||||
upb_DecodeStatus promote_result = upb_Map_PromoteMessages(
|
||||
map, &upb_0test__ModelWithExtensions_msg_init, 0, arena.ptr());
|
||||
EXPECT_EQ(promote_result, kUpb_DecodeStatus_Ok);
|
||||
|
||||
upb_MessageValue key;
|
||||
upb_MessageValue val;
|
||||
key.int32_val = 0;
|
||||
EXPECT_TRUE(upb_Map_Get(map, key, &val));
|
||||
EXPECT_EQ(100, upb_test_ModelWithExtensions_random_int32(
|
||||
static_cast<const upb_test_ModelWithExtensions*>(
|
||||
(void*)(val.msg_val))));
|
||||
|
||||
key.int32_val = 111;
|
||||
EXPECT_TRUE(upb_Map_Get(map, key, &val));
|
||||
EXPECT_EQ(123, upb_test_ModelWithExtensions_random_int32(
|
||||
static_cast<const upb_test_ModelWithExtensions*>(
|
||||
(void*)(val.msg_val))));
|
||||
|
||||
key.int32_val = 222;
|
||||
EXPECT_TRUE(upb_Map_Get(map, key, &val));
|
||||
EXPECT_EQ(456, upb_test_ModelWithExtensions_random_int32(
|
||||
static_cast<const upb_test_ModelWithExtensions*>(
|
||||
(void*)(val.msg_val))));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// OLD tests, to be removed!
|
||||
|
||||
namespace {
|
||||
|
||||
// Create a minitable to mimic ModelWithSubMessages with unlinked subs
|
||||
// to lazily promote unknowns after parsing.
|
||||
upb_MiniTable* CreateMiniTableWithEmptySubTablesOld(upb_Arena* arena) {
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 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
|
||||
|
||||
#ifndef UPB_MINI_TABLE_TAGGED_PTR_H_
|
||||
#define UPB_MINI_TABLE_TAGGED_PTR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "upb/message/internal/tagged_ptr.h"
|
||||
#include "upb/message/message.h"
|
||||
|
||||
// Must be last.
|
||||
#include "upb/port/def.inc"
|
||||
|
||||
// When a upb_Message* is stored in a message, array, or map, it is stored in a
|
||||
// tagged form. If the tag bit is set, the referenced upb_Message is of type
|
||||
// _kUpb_MiniTable_Empty (a sentinel message type with no fields) instead of
|
||||
// that field's true message type. This forms the basis of what we call
|
||||
// "dynamic tree shaking."
|
||||
//
|
||||
// See the documentation for kUpb_DecodeOption_ExperimentalAllowUnlinked for
|
||||
// more information.
|
||||
|
||||
typedef uintptr_t upb_TaggedMessagePtr;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Users who enable unlinked sub-messages must use this to test whether a
|
||||
// message is empty before accessing it. If a message is empty, it must be
|
||||
// first promoted using the interfaces in message/promote.h.
|
||||
UPB_API_INLINE bool upb_TaggedMessagePtr_IsEmpty(upb_TaggedMessagePtr ptr);
|
||||
|
||||
UPB_API_INLINE upb_Message* upb_TaggedMessagePtr_GetNonEmptyMessage(
|
||||
upb_TaggedMessagePtr ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#include "upb/port/undef.inc"
|
||||
|
||||
#endif /* UPB_MINI_TABLE_TAGGED_PTR_H_ */
|
||||
|
|
@ -733,7 +733,7 @@ TEST(MessageTest, MapFieldDeterministicEncoding) {
|
|||
}
|
||||
|
||||
TEST(MessageTest, AdjacentAliasedUnknown) {
|
||||
const upb_MiniTable* table = UPB_PRIVATE(_upb_MiniTable_Empty)();
|
||||
const upb_MiniTable* table = &upb_0test__EmptyMessage_msg_init;
|
||||
upb::Arena arena;
|
||||
upb_Message* msg = upb_Message_New(table, arena.ptr());
|
||||
char region[900];
|
||||
|
|
@ -955,20 +955,17 @@ TEST(MessageTest, MessageTooBig) {
|
|||
}
|
||||
|
||||
TEST(MessageTest, ArenaSpaceAllocatedAfterDecode) {
|
||||
const upb_MiniTable* table = UPB_PRIVATE(_upb_MiniTable_Empty)();
|
||||
upb::Arena arena(table->UPB_PRIVATE(size));
|
||||
|
||||
upb::Arena arena;
|
||||
uintptr_t space_allocated_before =
|
||||
upb_Arena_SpaceAllocated(arena.ptr(), nullptr);
|
||||
upb_Message* msg = upb_Message_New(table, arena.ptr());
|
||||
char region[300];
|
||||
memset(region, 0, sizeof(region));
|
||||
region[0] = 0x0A; // Tag number 1
|
||||
region[1] = 0xA9;
|
||||
region[2] = 0x02;
|
||||
upb_DecodeStatus status =
|
||||
upb_Decode(region, sizeof(region), msg, table, nullptr, 0, arena.ptr());
|
||||
EXPECT_EQ(status, kUpb_DecodeStatus_Ok);
|
||||
upb_test_EmptyMessage* msg =
|
||||
upb_test_EmptyMessage_parse(region, sizeof(region), arena.ptr());
|
||||
EXPECT_NE(msg, nullptr);
|
||||
uintptr_t space_allocated_after =
|
||||
upb_Arena_SpaceAllocated(arena.ptr(), nullptr);
|
||||
EXPECT_GT(space_allocated_after, space_allocated_before + 297);
|
||||
|
|
|
|||
|
|
@ -37,12 +37,6 @@ typedef union {
|
|||
const struct upb_Message* msg_val;
|
||||
upb_StringView str_val;
|
||||
|
||||
// EXPERIMENTAL: A tagged upb_Message*. Users must use this instead of
|
||||
// msg_val if unlinked sub-messages may possibly be in use. See the
|
||||
// documentation in kUpb_DecodeOption_ExperimentalAllowUnlinked for more
|
||||
// information.
|
||||
uintptr_t tagged_msg_val; // upb_TaggedMessagePtr
|
||||
|
||||
// For an extension field, we are essentially treating ext->data (a
|
||||
// upb_MessageValue) as if it were a message with one field that lives at
|
||||
// offset 0. This works because upb_MessageValue is precisely one value that
|
||||
|
|
|
|||
|
|
@ -451,7 +451,7 @@ static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d,
|
|||
ptrs_bytes ? upb_MtDecoder_CheckedMalloc(d, ptrs_bytes) : NULL;
|
||||
uint32_t i = 0;
|
||||
for (; i < sub_counts.submsg_count; i++) {
|
||||
subs_ptrs[i] = UPB_PRIVATE(_upb_MiniTable_Empty)();
|
||||
subs_ptrs[i] = NULL;
|
||||
subs[i].UPB_PRIVATE(submsg) = &subs_ptrs[i];
|
||||
}
|
||||
if (sub_counts.subenum_count) {
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ TEST(MiniTableEnumTest, Enum) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST_P(MiniTableTest, SubsInitializedToEmpty) {
|
||||
TEST_P(MiniTableTest, SubsInitializedToNull) {
|
||||
upb::Arena arena;
|
||||
upb::MtDataEncoder e;
|
||||
// Create mini table with 2 message fields.
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ bool upb_MiniTable_SetSubMessage(upb_MiniTable* table,
|
|||
upb_MiniTableSubInternal* table_subs = (void*)table->UPB_PRIVATE(subs);
|
||||
// TODO: Add this assert back once YouTube is updated to not call
|
||||
// this function repeatedly.
|
||||
// UPB_ASSERT(UPB_PRIVATE(_upb_MiniTable_IsEmpty)(table_sub->submsg));
|
||||
// UPB_ASSERT(upb_MiniTable_GetSubMessageTable(table, field) == NULL);
|
||||
memcpy((void*)table_subs[idx].UPB_PRIVATE(submsg), &sub, sizeof(void*));
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,23 +14,6 @@
|
|||
// Must be last.
|
||||
#include "upb/port/def.inc"
|
||||
|
||||
// A MiniTable for an empty message, used for unlinked sub-messages that are
|
||||
// built via MiniDescriptors. Messages that use this MiniTable may possibly
|
||||
// be linked later, in which case this MiniTable will be replaced with a real
|
||||
// one. This pattern is known as "dynamic tree shaking", and it introduces
|
||||
// complication because sub-messages may either be the "empty" type or the
|
||||
// "real" type. A tagged bit indicates the difference.
|
||||
const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_Empty) = {
|
||||
.UPB_PRIVATE(subs) = NULL,
|
||||
.UPB_PRIVATE(fields) = NULL,
|
||||
.UPB_PRIVATE(size) = sizeof(struct upb_Message),
|
||||
.UPB_PRIVATE(field_count) = 0,
|
||||
.UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable,
|
||||
.UPB_PRIVATE(dense_below) = 0,
|
||||
.UPB_PRIVATE(table_mask) = -1,
|
||||
.UPB_PRIVATE(required_count) = 0,
|
||||
};
|
||||
|
||||
// A MiniTable for a statically tree shaken message. Messages that use this
|
||||
// MiniTable are guaranteed to remain unlinked; unlike the empty message, this
|
||||
// MiniTable is never replaced, which greatly simplifies everything, because the
|
||||
|
|
|
|||
|
|
@ -100,12 +100,6 @@ UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE(
|
|||
return mt;
|
||||
}
|
||||
|
||||
UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE(_upb_MiniTable_Empty)(void) {
|
||||
extern const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_Empty);
|
||||
|
||||
return &UPB_PRIVATE(_kUpb_MiniTable_Empty);
|
||||
}
|
||||
|
||||
UPB_API_INLINE int upb_MiniTable_FieldCount(const struct upb_MiniTable* m) {
|
||||
return m->UPB_ONLYBITS(field_count);
|
||||
}
|
||||
|
|
@ -158,13 +152,6 @@ const struct upb_MiniTableField* upb_MiniTable_FindFieldByNumber(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
UPB_INLINE bool UPB_PRIVATE(_upb_MiniTable_IsEmpty)(
|
||||
const struct upb_MiniTable* m) {
|
||||
extern const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_Empty);
|
||||
|
||||
return m == &UPB_PRIVATE(_kUpb_MiniTable_Empty);
|
||||
}
|
||||
|
||||
UPB_API_INLINE const struct upb_MiniTableField* upb_MiniTable_GetFieldByIndex(
|
||||
const struct upb_MiniTable* m, uint32_t i) {
|
||||
return &m->UPB_ONLYBITS(fields)[i];
|
||||
|
|
@ -188,9 +175,7 @@ UPB_API_INLINE const struct upb_MiniTable* upb_MiniTable_SubMessage(
|
|||
UPB_API_INLINE const struct upb_MiniTable* upb_MiniTable_GetSubMessageTable(
|
||||
const struct upb_MiniTable* m, const struct upb_MiniTableField* f) {
|
||||
UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message);
|
||||
const struct upb_MiniTable* ret = upb_MiniTable_SubMessage(m, f);
|
||||
UPB_ASSUME(ret);
|
||||
return UPB_PRIVATE(_upb_MiniTable_IsEmpty)(ret) ? NULL : ret;
|
||||
return upb_MiniTable_SubMessage(m, f);
|
||||
}
|
||||
|
||||
UPB_API_INLINE bool upb_MiniTable_FieldIsLinked(
|
||||
|
|
|
|||
|
|
@ -38,13 +38,8 @@ UPB_API_INLINE bool upb_MiniTable_IsMessageSet(const upb_MiniTable* m);
|
|||
UPB_API_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable(
|
||||
const upb_MiniTable* m, const upb_MiniTableField* f);
|
||||
|
||||
// Returns the MiniTable for a message field if it is a submessage, otherwise
|
||||
// returns NULL.
|
||||
//
|
||||
// WARNING: if dynamic tree shaking is in use, the return value may be the
|
||||
// "empty", zero-field placeholder message instead of the real message type.
|
||||
// If the message is later linked, this function will begin returning the real
|
||||
// message type.
|
||||
// Returns the MiniTable for a message field if it is a submessage and the field
|
||||
// is linked, otherwise returns NULL.
|
||||
UPB_API_INLINE const upb_MiniTable* upb_MiniTable_SubMessage(
|
||||
const upb_MiniTable* m, const upb_MiniTableField* f);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,10 +25,8 @@
|
|||
#include "upb/message/internal/map.h"
|
||||
#include "upb/message/internal/map_entry.h"
|
||||
#include "upb/message/internal/message.h"
|
||||
#include "upb/message/internal/tagged_ptr.h"
|
||||
#include "upb/message/map.h"
|
||||
#include "upb/message/message.h"
|
||||
#include "upb/message/tagged_ptr.h"
|
||||
#include "upb/mini_table/enum.h"
|
||||
#include "upb/mini_table/extension.h"
|
||||
#include "upb/mini_table/extension_registry.h"
|
||||
|
|
@ -249,62 +247,22 @@ static void _upb_Decoder_Munge(const upb_MiniTableField* field, wireval* val) {
|
|||
static upb_Message* _upb_Decoder_NewSubMessage2(upb_Decoder* d,
|
||||
const upb_MiniTable* subl,
|
||||
const upb_MiniTableField* field,
|
||||
upb_TaggedMessagePtr* target) {
|
||||
upb_Message** target) {
|
||||
UPB_ASSERT(subl);
|
||||
upb_Message* msg = _upb_Message_New(subl, &d->arena);
|
||||
if (!msg) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory);
|
||||
|
||||
// Extensions should not be unlinked. A message extension should not be
|
||||
// registered until its sub-message type is available to be linked.
|
||||
bool is_empty = UPB_PRIVATE(_upb_MiniTable_IsEmpty)(subl);
|
||||
bool is_extension = field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsExtension;
|
||||
UPB_ASSERT(!(is_empty && is_extension));
|
||||
|
||||
if (is_empty && !(d->options & kUpb_DecodeOption_ExperimentalAllowUnlinked)) {
|
||||
_upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_UnlinkedSubMessage);
|
||||
}
|
||||
|
||||
upb_TaggedMessagePtr tagged =
|
||||
UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(msg, is_empty);
|
||||
memcpy(target, &tagged, sizeof(tagged));
|
||||
*target = msg;
|
||||
return msg;
|
||||
}
|
||||
|
||||
static upb_Message* _upb_Decoder_NewSubMessage(
|
||||
upb_Decoder* d, const upb_MiniTableSubInternal* subs,
|
||||
const upb_MiniTableField* field, upb_TaggedMessagePtr* target) {
|
||||
const upb_MiniTableField* field, upb_Message** target) {
|
||||
const upb_MiniTable* subl = _upb_MiniTableSubs_MessageByField(subs, field);
|
||||
return _upb_Decoder_NewSubMessage2(d, subl, field, target);
|
||||
}
|
||||
|
||||
static upb_Message* _upb_Decoder_ReuseSubMessage(
|
||||
upb_Decoder* d, const upb_MiniTableSubInternal* subs,
|
||||
const upb_MiniTableField* field, upb_TaggedMessagePtr* target) {
|
||||
upb_TaggedMessagePtr tagged = *target;
|
||||
const upb_MiniTable* subl = _upb_MiniTableSubs_MessageByField(subs, field);
|
||||
UPB_ASSERT(subl);
|
||||
if (!upb_TaggedMessagePtr_IsEmpty(tagged) ||
|
||||
UPB_PRIVATE(_upb_MiniTable_IsEmpty)(subl)) {
|
||||
return UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(tagged);
|
||||
}
|
||||
|
||||
// We found an empty message from a previous parse that was performed before
|
||||
// this field was linked. But it is linked now, so we want to allocate a new
|
||||
// message of the correct type and promote data into it before continuing.
|
||||
upb_Message* existing =
|
||||
UPB_PRIVATE(_upb_TaggedMessagePtr_GetEmptyMessage)(tagged);
|
||||
upb_Message* promoted = _upb_Decoder_NewSubMessage(d, subs, field, target);
|
||||
uintptr_t iter = kUpb_Message_UnknownBegin;
|
||||
upb_StringView unknown;
|
||||
while (upb_Message_NextUnknown(existing, &unknown, &iter)) {
|
||||
upb_DecodeStatus status =
|
||||
upb_Decode(unknown.data, unknown.size, promoted, subl, d->extreg,
|
||||
d->options, &d->arena);
|
||||
if (status != kUpb_DecodeStatus_Ok) _upb_Decoder_ErrorJmp(d, status);
|
||||
}
|
||||
return promoted;
|
||||
}
|
||||
|
||||
static const char* _upb_Decoder_ReadString(upb_Decoder* d, const char* ptr,
|
||||
int size, upb_StringView* str) {
|
||||
const char* str_ptr = ptr;
|
||||
|
|
@ -546,9 +504,9 @@ static const char* _upb_Decoder_DecodeToArray(
|
|||
}
|
||||
case kUpb_DecodeOp_SubMessage: {
|
||||
/* Append submessage / group. */
|
||||
upb_TaggedMessagePtr* target = UPB_PTR_AT(
|
||||
upb_Array_MutableDataPtr(arr), arr->UPB_PRIVATE(size) * sizeof(void*),
|
||||
upb_TaggedMessagePtr);
|
||||
upb_Message** target =
|
||||
UPB_PTR_AT(upb_Array_MutableDataPtr(arr),
|
||||
arr->UPB_PRIVATE(size) * sizeof(void*), upb_Message*);
|
||||
upb_Message* submsg = _upb_Decoder_NewSubMessage(d, subs, field, target);
|
||||
arr->UPB_PRIVATE(size)++;
|
||||
if (UPB_UNLIKELY(field->UPB_PRIVATE(descriptortype) ==
|
||||
|
|
@ -665,10 +623,10 @@ static const char* _upb_Decoder_DecodeToMap(
|
|||
entry->UPB_PRIVATE(fields)[1].UPB_PRIVATE(descriptortype) ==
|
||||
kUpb_FieldType_Group) {
|
||||
// Create proactively to handle the case where it doesn't appear.
|
||||
upb_TaggedMessagePtr msg;
|
||||
upb_Message* msg;
|
||||
_upb_Decoder_NewSubMessage(d, entry->UPB_PRIVATE(subs),
|
||||
&entry->UPB_PRIVATE(fields)[1], &msg);
|
||||
ent.v.val = upb_value_uintptr(msg);
|
||||
ent.v.val = upb_value_ptr(msg);
|
||||
}
|
||||
|
||||
ptr = _upb_Decoder_DecodeSubMessage(d, ptr, &ent.message, subs, field,
|
||||
|
|
@ -707,13 +665,9 @@ static const char* _upb_Decoder_DecodeToSubMessage(
|
|||
// Store into message.
|
||||
switch (op) {
|
||||
case kUpb_DecodeOp_SubMessage: {
|
||||
upb_TaggedMessagePtr* submsgp = mem;
|
||||
upb_Message* submsg;
|
||||
if (*submsgp) {
|
||||
submsg = _upb_Decoder_ReuseSubMessage(d, subs, field, submsgp);
|
||||
} else {
|
||||
submsg = _upb_Decoder_NewSubMessage(d, subs, field, submsgp);
|
||||
}
|
||||
upb_Message** submsgp = mem;
|
||||
upb_Message* submsg = *submsgp;
|
||||
if (!submsg) submsg = _upb_Decoder_NewSubMessage(d, subs, field, submsgp);
|
||||
if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) {
|
||||
ptr = _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field);
|
||||
} else {
|
||||
|
|
@ -783,9 +737,10 @@ static void upb_Decoder_AddKnownMessageSetItem(
|
|||
if (UPB_UNLIKELY(!ext)) {
|
||||
_upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory);
|
||||
}
|
||||
upb_Message** submsgp = (upb_Message**)&ext->data.msg_val;
|
||||
upb_Message* submsg = _upb_Decoder_NewSubMessage2(
|
||||
d, ext->ext->UPB_PRIVATE(sub).UPB_PRIVATE(submsg),
|
||||
&ext->ext->UPB_PRIVATE(field), &ext->data.tagged_msg_val);
|
||||
&ext->ext->UPB_PRIVATE(field), submsgp);
|
||||
upb_DecodeStatus status = upb_Decode(
|
||||
data, size, submsg, upb_MiniTableExtension_GetSubMessage(item_mt),
|
||||
d->extreg, d->options, &d->arena);
|
||||
|
|
@ -961,10 +916,7 @@ void _upb_Decoder_CheckUnlinked(upb_Decoder* d, const upb_MiniTable* mt,
|
|||
if (field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsExtension) return;
|
||||
const upb_MiniTable* mt_sub =
|
||||
_upb_MiniTableSubs_MessageByField(mt->UPB_PRIVATE(subs), field);
|
||||
if ((d->options & kUpb_DecodeOption_ExperimentalAllowUnlinked) ||
|
||||
!UPB_PRIVATE(_upb_MiniTable_IsEmpty)(mt_sub)) {
|
||||
return;
|
||||
}
|
||||
if (mt_sub != NULL) return; // Normal case, sub-message is linked.
|
||||
#ifndef NDEBUG
|
||||
const upb_MiniTableField* oneof = upb_MiniTable_GetOneof(mt, field);
|
||||
if (oneof) {
|
||||
|
|
@ -1452,8 +1404,6 @@ const char* upb_DecodeStatus_String(upb_DecodeStatus status) {
|
|||
return "Exceeded upb_DecodeOptions_MaxDepth";
|
||||
case kUpb_DecodeStatus_MissingRequired:
|
||||
return "Missing required field";
|
||||
case kUpb_DecodeStatus_UnlinkedSubMessage:
|
||||
return "Unlinked sub-message field was present";
|
||||
default:
|
||||
return "Unknown decode status";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,41 +50,6 @@ enum {
|
|||
* post-parse validation step will always be necessary. */
|
||||
kUpb_DecodeOption_CheckRequired = 2,
|
||||
|
||||
/* EXPERIMENTAL:
|
||||
*
|
||||
* If set, the parser will allow parsing of sub-message fields that were not
|
||||
* previously linked using upb_MiniTable_SetSubMessage(). The data will be
|
||||
* parsed into an internal "empty" message type that cannot be accessed
|
||||
* directly, but can be later promoted into the true message type if the
|
||||
* sub-message fields are linked at a later time.
|
||||
*
|
||||
* Users should set this option if they intend to perform dynamic tree shaking
|
||||
* and promoting using the interfaces in message/promote.h. If this option is
|
||||
* enabled, it is important that the resulting messages are only accessed by
|
||||
* code that is aware of promotion rules:
|
||||
*
|
||||
* 1. Message pointers in upb_Message, upb_Array, and upb_Map are represented
|
||||
* by a tagged pointer upb_TaggedMessagePointer. The tag indicates whether
|
||||
* the message uses the internal "empty" type.
|
||||
*
|
||||
* 2. Any code *reading* these message pointers must test whether the "empty"
|
||||
* tag bit is set, using the interfaces in mini_table/types.h. However
|
||||
* writing of message pointers should always use plain upb_Message*, since
|
||||
* users are not allowed to create "empty" messages.
|
||||
*
|
||||
* 3. It is always safe to test whether a field is present or test the array
|
||||
* length; these interfaces will reflect that empty messages are present,
|
||||
* even though their data cannot be accessed without promoting first.
|
||||
*
|
||||
* 4. If a message pointer is indeed tagged as empty, the message may not be
|
||||
* accessed directly, only promoted through the interfaces in
|
||||
* message/promote.h.
|
||||
*
|
||||
* 5. Tagged/empty messages may never be created by the user. They may only
|
||||
* be created by the parser or the message-copying logic in message/copy.h.
|
||||
*/
|
||||
kUpb_DecodeOption_ExperimentalAllowUnlinked = 4,
|
||||
|
||||
/* EXPERIMENTAL:
|
||||
*
|
||||
* If set, decoding will enforce UTF-8 validation for string fields, even for
|
||||
|
|
@ -127,13 +92,8 @@ typedef enum {
|
|||
// kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise
|
||||
// succeeded.
|
||||
kUpb_DecodeStatus_MissingRequired = 5,
|
||||
|
||||
// Unlinked sub-message field was present, but
|
||||
// kUpb_DecodeOptions_ExperimentalAllowUnlinked was not specified in the list
|
||||
// of options.
|
||||
kUpb_DecodeStatus_UnlinkedSubMessage = 6,
|
||||
} upb_DecodeStatus;
|
||||
// LINT.ThenChange(//depot/google3/third_party/protobuf/rust/upb.rs:decode_status)
|
||||
// LINT.ThenChange(//depot/google3/third_party/upb/rust/sys/wire/wire.rs:decode_status)
|
||||
|
||||
UPB_API upb_DecodeStatus upb_Decode(const char* buf, size_t size,
|
||||
upb_Message* msg, const upb_MiniTable* mt,
|
||||
|
|
|
|||
|
|
@ -30,10 +30,8 @@
|
|||
#include "upb/message/internal/map_entry.h"
|
||||
#include "upb/message/internal/map_sorter.h"
|
||||
#include "upb/message/internal/message.h"
|
||||
#include "upb/message/internal/tagged_ptr.h"
|
||||
#include "upb/message/map.h"
|
||||
#include "upb/message/message.h"
|
||||
#include "upb/message/tagged_ptr.h"
|
||||
#include "upb/mini_table/extension.h"
|
||||
#include "upb/mini_table/field.h"
|
||||
#include "upb/mini_table/internal/field.h"
|
||||
|
|
@ -302,16 +300,6 @@ static char* encode_fixedarray(char* ptr, upb_encstate* e, const upb_Array* arr,
|
|||
static char* encode_message(char* ptr, upb_encstate* e, const upb_Message* msg,
|
||||
const upb_MiniTable* m, size_t* size);
|
||||
|
||||
static char* encode_TaggedMessagePtr(char* ptr, upb_encstate* e,
|
||||
upb_TaggedMessagePtr tagged,
|
||||
const upb_MiniTable* m, size_t* size) {
|
||||
if (upb_TaggedMessagePtr_IsEmpty(tagged)) {
|
||||
m = UPB_PRIVATE(_upb_MiniTable_Empty)();
|
||||
}
|
||||
return encode_message(
|
||||
ptr, e, UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(tagged), m, size);
|
||||
}
|
||||
|
||||
static char* encode_scalar(char* ptr, upb_encstate* e, const void* _field_mem,
|
||||
const upb_MiniTableSubInternal* subs,
|
||||
const upb_MiniTableField* f) {
|
||||
|
|
@ -361,7 +349,7 @@ static char* encode_scalar(char* ptr, upb_encstate* e, const void* _field_mem,
|
|||
}
|
||||
case kUpb_FieldType_Group: {
|
||||
size_t size;
|
||||
upb_TaggedMessagePtr submsg = *(upb_TaggedMessagePtr*)field_mem;
|
||||
upb_Message* submsg = *(upb_Message**)field_mem;
|
||||
const upb_MiniTable* subm = _upb_Encoder_GetSubMiniTable(subs, f);
|
||||
if (submsg == 0) {
|
||||
return ptr;
|
||||
|
|
@ -369,20 +357,20 @@ static char* encode_scalar(char* ptr, upb_encstate* e, const void* _field_mem,
|
|||
if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
|
||||
ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f),
|
||||
kUpb_WireType_EndGroup);
|
||||
ptr = encode_TaggedMessagePtr(ptr, e, submsg, subm, &size);
|
||||
ptr = encode_message(ptr, e, submsg, subm, &size);
|
||||
wire_type = kUpb_WireType_StartGroup;
|
||||
e->depth++;
|
||||
break;
|
||||
}
|
||||
case kUpb_FieldType_Message: {
|
||||
size_t size;
|
||||
upb_TaggedMessagePtr submsg = *(upb_TaggedMessagePtr*)field_mem;
|
||||
upb_Message* submsg = *(upb_Message**)field_mem;
|
||||
const upb_MiniTable* subm = _upb_Encoder_GetSubMiniTable(subs, f);
|
||||
if (submsg == 0) {
|
||||
return ptr;
|
||||
}
|
||||
if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
|
||||
ptr = encode_TaggedMessagePtr(ptr, e, submsg, subm, &size);
|
||||
ptr = encode_message(ptr, e, submsg, subm, &size);
|
||||
ptr = encode_length(ptr, e, size);
|
||||
wire_type = kUpb_WireType_Delimited;
|
||||
e->depth++;
|
||||
|
|
@ -472,8 +460,8 @@ static char* encode_array(char* ptr, upb_encstate* e, const upb_Message* msg,
|
|||
return ptr;
|
||||
}
|
||||
case kUpb_FieldType_Group: {
|
||||
const upb_TaggedMessagePtr* start = upb_Array_DataPtr(arr);
|
||||
const upb_TaggedMessagePtr* arr_ptr = start + upb_Array_Size(arr);
|
||||
const upb_Message* const* start = upb_Array_DataPtr(arr);
|
||||
const upb_Message* const* arr_ptr = start + upb_Array_Size(arr);
|
||||
const upb_MiniTable* subm = _upb_Encoder_GetSubMiniTable(subs, f);
|
||||
if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
|
||||
do {
|
||||
|
|
@ -481,7 +469,7 @@ static char* encode_array(char* ptr, upb_encstate* e, const upb_Message* msg,
|
|||
arr_ptr--;
|
||||
ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f),
|
||||
kUpb_WireType_EndGroup);
|
||||
ptr = encode_TaggedMessagePtr(ptr, e, *arr_ptr, subm, &size);
|
||||
ptr = encode_message(ptr, e, *arr_ptr, subm, &size);
|
||||
ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f),
|
||||
kUpb_WireType_StartGroup);
|
||||
} while (arr_ptr != start);
|
||||
|
|
@ -489,14 +477,14 @@ static char* encode_array(char* ptr, upb_encstate* e, const upb_Message* msg,
|
|||
return ptr;
|
||||
}
|
||||
case kUpb_FieldType_Message: {
|
||||
const upb_TaggedMessagePtr* start = upb_Array_DataPtr(arr);
|
||||
const upb_TaggedMessagePtr* arr_ptr = start + upb_Array_Size(arr);
|
||||
const upb_Message* const* start = upb_Array_DataPtr(arr);
|
||||
const upb_Message* const* arr_ptr = start + upb_Array_Size(arr);
|
||||
const upb_MiniTable* subm = _upb_Encoder_GetSubMiniTable(subs, f);
|
||||
if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
|
||||
do {
|
||||
size_t size;
|
||||
arr_ptr--;
|
||||
ptr = encode_TaggedMessagePtr(ptr, e, *arr_ptr, subm, &size);
|
||||
ptr = encode_message(ptr, e, *arr_ptr, subm, &size);
|
||||
ptr = encode_length(ptr, e, size);
|
||||
ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f),
|
||||
kUpb_WireType_Delimited);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue