blob: ba60c39ce675c775f523fbc1ff104f9f5e7c4abd [file] [edit]
// Protocol Buffers - Google's data interchange format
// Copyright 2026 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_MESSAGE_UNKNOWN_FIELDS_H_
#define UPB_MESSAGE_UNKNOWN_FIELDS_H_
#include <stddef.h>
#include <stdint.h>
#include "upb/mem/internal/arena.h"
#include "upb/message/internal/message.h"
#include "upb/message/internal/types.h"
// Must be last.
#include "upb/port/def.inc"
#ifdef __cplusplus
extern "C" {
#endif
// Support iteration over unknown (upb_MessageUnknown*), including unknown
// upb_StringView and non-canonical extensions (upb_Extension*).
UPB_INLINE bool upb_Message_NextUnknown2(const struct upb_Message* msg,
struct upb_MessageUnknown* data,
uintptr_t* iter) {
const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
size_t i = *iter;
if (in) {
while (i < in->size) {
upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++];
if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) {
data->type = kUpb_MessageUnknownType_StringView;
data->value.bytes = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr);
*iter = i;
return true;
} else if (upb_TaggedAuxPtr_IsNonCanonicalExtension(tagged_ptr)) {
data->type = kUpb_MessageUnknownType_NonCanonicalExtension;
data->value.extension =
upb_TaggedAuxPtr_NonCanonicalExtension(tagged_ptr);
*iter = i;
return true;
}
}
}
data->type = kUpb_MessageUnknownType_StringView;
data->value.bytes.size = 0;
data->value.bytes.data = NULL;
*iter = i;
return false;
}
typedef enum {
kUpb_FindUnknown_Ok,
kUpb_FindUnknown_NotPresent,
kUpb_FindUnknown_ParseError,
} upb_FindUnknown_Status;
typedef struct {
upb_FindUnknown_Status status;
struct upb_MessageUnknown unknown;
uintptr_t iter;
} upb_FindUnknownRet2;
// Finds first occurrence of unknown data (upb_MessageUnknown) by tag id in
// message, including unknown upb_StringView and non-canonical extensions
// (upb_Extension*).
//
// If multiple matching entries exist for the same field number (e.g. both a
// raw unknown upb_StringView and a non-canonical extension), this function
// returns the one encountered first in internal iteration order (which follows
// the order they were added or parsed).
//
// A depth_limit of zero means to just use the upb default depth limit.
upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg,
uint32_t field_number,
int depth_limit);
// Removes a segment of unknown data from the message, advancing to the next
// segment. Returns false if the removed segment was at the end of the last
// chunk.
//
// This must be done while iterating:
//
// uintptr_t iter = kUpb_Message_UnknownBegin;
// upb_MessageUnknown data;
// // Iterate chunks
// while (upb_Message_NextUnknown2(msg, &data, &iter)) {
// // Iterate within a chunk, deleting ranges
// while (ShouldDeleteSubSegment(&data)) {
// // Data now points to the region to be deleted
// switch (upb_Message_DeleteUnknown2(msg, &data, &iter)) {
// case kUpb_Message_DeleteUnknown_DeletedLast: return ok;
// case kUpb_Message_DeleteUnknown_IterUpdated: break;
// // If DeleteUnknown returned kUpb_Message_DeleteUnknown_IterUpdated,
// // then data now points to the remaining unknown fields after the
// // region that was just deleted.
// case kUpb_Message_DeleteUnknown_AllocFail: return err;
// }
// }
// }
//
// The range given in `data` must be contained inside the most recently
// returned region.
//
// Support deletion of unknown (upb_MessageUnknown*), including unknown
// upb_StringView and non-canonical extensions (upb_Extension*).
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter,
struct upb_Arena* arena);
#ifdef __cplusplus
} /* extern "C" */
#endif
#include "upb/port/undef.inc"
#endif /* UPB_MESSAGE_UNKNOWN_FIELDS_H_ */