mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
Internal change.
PiperOrigin-RevId: 947803839
This commit is contained in:
parent
3bc006d2c1
commit
0b1b3fa234
4 changed files with 496 additions and 137 deletions
|
|
@ -81,6 +81,8 @@ _message_target_compatible_with = {
|
|||
filegroup(
|
||||
name = "message_srcs",
|
||||
srcs = [
|
||||
"buffer_convert.c",
|
||||
"buffer_convert.h",
|
||||
"convert.c",
|
||||
"convert.h",
|
||||
"descriptor.c",
|
||||
|
|
|
|||
325
python/buffer_convert.c
Normal file
325
python/buffer_convert.c
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
// 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
|
||||
|
||||
// clang-format off
|
||||
#include "Python.h"
|
||||
// clang-format on
|
||||
|
||||
#include "python/buffer_convert.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "upb/base/descriptor_constants.h"
|
||||
#include "upb/reflection/def.h"
|
||||
|
||||
// Must be last.
|
||||
#include "upb/port/def.inc"
|
||||
|
||||
#define SOURCE_KINDS(M) \
|
||||
M(Bool, bool, UNSIGNED) \
|
||||
M(Int8, int8_t, SIGNED) \
|
||||
M(UInt8, uint8_t, UNSIGNED) \
|
||||
M(Int16, int16_t, SIGNED) \
|
||||
M(UInt16, uint16_t, UNSIGNED) \
|
||||
M(Int32, int32_t, SIGNED) \
|
||||
M(UInt32, uint32_t, UNSIGNED) \
|
||||
M(Int64, int64_t, SIGNED) \
|
||||
M(UInt64, uint64_t, UNSIGNED)
|
||||
|
||||
#define TARGET_KINDS(M, Source, SourceT, SourceSign) \
|
||||
M(Source, SourceT, SourceSign, Int32, int32_t, SIGNED, INT32_MIN, INT32_MAX) \
|
||||
M(Source, SourceT, SourceSign, UInt32, uint32_t, UNSIGNED, 0, UINT32_MAX) \
|
||||
M(Source, SourceT, SourceSign, Int64, int64_t, SIGNED, INT64_MIN, INT64_MAX) \
|
||||
M(Source, SourceT, SourceSign, UInt64, uint64_t, UNSIGNED, 0, UINT64_MAX)
|
||||
|
||||
#define K(Source, SourceT, SourceSign, Target, TargetT, TargetSign, Min, Max) \
|
||||
kPyUpb_TargetKind_##Target,
|
||||
typedef enum {
|
||||
kPyUpb_TargetKind_None = 0,
|
||||
kPyUpb_TargetKind_Float,
|
||||
kPyUpb_TargetKind_Double,
|
||||
kPyUpb_TargetKind_Bool,
|
||||
TARGET_KINDS(K, X, X, X)
|
||||
} PyUpb_TargetKind;
|
||||
#undef K
|
||||
|
||||
#define K(Source, SourceT, SourceSign, Target, TargetT, TargetSign, Min, Max) \
|
||||
sizeof(TargetT),
|
||||
|
||||
static const size_t kPyUpb_TargetSize[] = {
|
||||
0, // kPyUpb_TargetKind_None
|
||||
sizeof(float), // kPyUpb_TargetKind_Float
|
||||
sizeof(double), // kPyUpb_TargetKind_Double
|
||||
sizeof(bool), // kPyUpb_TargetKind_Bool
|
||||
TARGET_KINDS(K, X, X, X)};
|
||||
|
||||
#undef K
|
||||
|
||||
// --- Range Check Helpers ---
|
||||
// Uses token pasting (SourceSign_TargetSign) to select safe casting bounds.
|
||||
// We cast to intmax_t/uintmax_t to safely bridge widths before comparing.
|
||||
|
||||
// Source is SIGNED, Target is SIGNED
|
||||
#define IN_RANGE_SIGNED_SIGNED(val, min, max) \
|
||||
((intmax_t)(val) >= (intmax_t)(min) && (intmax_t)(val) <= (intmax_t)(max))
|
||||
|
||||
// Source is SIGNED, Target is UNSIGNED
|
||||
#define IN_RANGE_SIGNED_UNSIGNED(val, min, max) \
|
||||
((val) >= 0 && (uintmax_t)(val) <= (uintmax_t)(max))
|
||||
|
||||
// Source is UNSIGNED, Target is SIGNED
|
||||
#define IN_RANGE_UNSIGNED_SIGNED(val, min, max) \
|
||||
((uintmax_t)(val) <= (uintmax_t)(max))
|
||||
|
||||
// Source is UNSIGNED, Target is UNSIGNED
|
||||
#define IN_RANGE_UNSIGNED_UNSIGNED(val, min, max) \
|
||||
((uintmax_t)(val) <= (uintmax_t)(max))
|
||||
|
||||
// Dispatcher macro
|
||||
#define IN_RANGE(val, SourceSign, TargetSign, min, max) \
|
||||
IN_RANGE_##SourceSign##_##TargetSign(val, min, max)
|
||||
// ---------------------------
|
||||
|
||||
#define TARGET_CASE(Source, SourceT, SourceSign, Target, TargetT, TargetSign, \
|
||||
Min, Max) \
|
||||
case kPyUpb_TargetKind_##Target: { \
|
||||
TargetT* t = (TargetT*)target; \
|
||||
for (size_t i = 0; i < count; ++i) { \
|
||||
if (!IN_RANGE(s[i], SourceSign, TargetSign, Min, Max)) { \
|
||||
return kPyUpb_TryResult_Failure; \
|
||||
} \
|
||||
t[i] = (TargetT)s[i]; \
|
||||
} \
|
||||
return kPyUpb_TryResult_Success; \
|
||||
}
|
||||
|
||||
#define SOURCES_CASE(Source, SourceT, SourceSign) \
|
||||
case kPyUpb_SourceKind_##Source: { \
|
||||
const SourceT* s = (const SourceT*)source; \
|
||||
switch (target_kind) { \
|
||||
case kPyUpb_TargetKind_Bool: { \
|
||||
bool* t = (bool*)target; \
|
||||
for (size_t i = 0; i < count; ++i) { \
|
||||
t[i] = s[i] != (SourceT)0; \
|
||||
} \
|
||||
return kPyUpb_TryResult_Success; \
|
||||
} \
|
||||
TARGET_KINDS(TARGET_CASE, Source, SourceT, SourceSign) \
|
||||
default: \
|
||||
return kPyUpb_TryResult_NotSupported; \
|
||||
} \
|
||||
} break;
|
||||
|
||||
static PyUpb_TryResult PyUpb_IntegralCast(PyUpb_TargetKind target_kind,
|
||||
void* target, //
|
||||
PyUpb_SourceKind source_kind,
|
||||
const void* source, size_t count) {
|
||||
switch (source_kind) {
|
||||
SOURCE_KINDS(SOURCES_CASE)
|
||||
default:
|
||||
return kPyUpb_TryResult_NotSupported;
|
||||
}
|
||||
}
|
||||
|
||||
static void PyUpb_FloatCast(PyUpb_TargetKind target_kind, void* target, //
|
||||
PyUpb_SourceKind source_kind, const void* source,
|
||||
size_t count) {
|
||||
if (target_kind == kPyUpb_TargetKind_Float) {
|
||||
assert(source_kind == kPyUpb_SourceKind_Double);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
((float*)target)[i] = ((double*)source)[i];
|
||||
}
|
||||
} else {
|
||||
assert(source_kind == kPyUpb_SourceKind_Float);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
((double*)target)[i] = ((float*)source)[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef IN_RANGE_SIGNED_SIGNED
|
||||
#undef IN_RANGE_SIGNED_UNSIGNED
|
||||
#undef IN_RANGE_UNSIGNED_SIGNED
|
||||
#undef IN_RANGE_UNSIGNED_UNSIGNED
|
||||
#undef IN_RANGE
|
||||
#undef TARGET_CASE
|
||||
#undef TARGET_KINDS
|
||||
#undef SOURCES_CASE
|
||||
#undef SOURCE_KINDS
|
||||
|
||||
PyUpb_SourceKind PyUpb_SourceKindFromCType(upb_CType ctype) {
|
||||
switch (ctype) {
|
||||
case kUpb_CType_Bool:
|
||||
return kPyUpb_SourceKind_Bool;
|
||||
case kUpb_CType_Enum:
|
||||
case kUpb_CType_Int32:
|
||||
return kPyUpb_SourceKind_Int32;
|
||||
case kUpb_CType_UInt32:
|
||||
return kPyUpb_SourceKind_UInt32;
|
||||
case kUpb_CType_Int64:
|
||||
return kPyUpb_SourceKind_Int64;
|
||||
case kUpb_CType_UInt64:
|
||||
return kPyUpb_SourceKind_UInt64;
|
||||
case kUpb_CType_Float:
|
||||
return kPyUpb_SourceKind_Float;
|
||||
case kUpb_CType_Double:
|
||||
return kPyUpb_SourceKind_Double;
|
||||
default:
|
||||
return kPyUpb_SourceKind_None;
|
||||
}
|
||||
}
|
||||
|
||||
static PyUpb_TargetKind PyUpb_TargetKindFromCType(upb_CType ctype) {
|
||||
switch (ctype) {
|
||||
case kUpb_CType_Bool:
|
||||
return kPyUpb_TargetKind_Bool;
|
||||
case kUpb_CType_Enum:
|
||||
case kUpb_CType_Int32:
|
||||
return kPyUpb_TargetKind_Int32;
|
||||
case kUpb_CType_UInt32:
|
||||
return kPyUpb_TargetKind_UInt32;
|
||||
case kUpb_CType_Int64:
|
||||
return kPyUpb_TargetKind_Int64;
|
||||
case kUpb_CType_UInt64:
|
||||
return kPyUpb_TargetKind_UInt64;
|
||||
case kUpb_CType_Float:
|
||||
return kPyUpb_TargetKind_Float;
|
||||
case kUpb_CType_Double:
|
||||
return kPyUpb_TargetKind_Double;
|
||||
default:
|
||||
return kPyUpb_TargetKind_None;
|
||||
}
|
||||
}
|
||||
|
||||
size_t PyUpb_GetTargetItemSize(upb_CType ctype) {
|
||||
return kPyUpb_TargetSize[PyUpb_TargetKindFromCType(ctype)];
|
||||
}
|
||||
|
||||
PyUpb_SourceKind PyUpb_SourceKindFromFormat(int itemsize, char format) {
|
||||
switch (itemsize) {
|
||||
case 1:
|
||||
switch (format) {
|
||||
case '?':
|
||||
return kPyUpb_SourceKind_Bool;
|
||||
case '\0':
|
||||
case 'B':
|
||||
return kPyUpb_SourceKind_UInt8;
|
||||
case 'b':
|
||||
return kPyUpb_SourceKind_Int8;
|
||||
default:
|
||||
return kPyUpb_SourceKind_None;
|
||||
}
|
||||
case 2:
|
||||
switch (format) {
|
||||
case 'H':
|
||||
return kPyUpb_SourceKind_UInt16;
|
||||
case 'h':
|
||||
return kPyUpb_SourceKind_Int16;
|
||||
default:
|
||||
return kPyUpb_SourceKind_None;
|
||||
}
|
||||
case 4:
|
||||
switch (format) {
|
||||
case 'I':
|
||||
return kPyUpb_SourceKind_UInt32;
|
||||
case 'l':
|
||||
case 'i':
|
||||
return kPyUpb_SourceKind_Int32;
|
||||
case 'f':
|
||||
return kPyUpb_SourceKind_Float;
|
||||
default:
|
||||
return kPyUpb_SourceKind_None;
|
||||
}
|
||||
case 8:
|
||||
switch (format) {
|
||||
case 'Q':
|
||||
return kPyUpb_SourceKind_UInt64;
|
||||
case 'l':
|
||||
case 'q':
|
||||
return kPyUpb_SourceKind_Int64;
|
||||
case 'd':
|
||||
return kPyUpb_SourceKind_Double;
|
||||
default:
|
||||
return kPyUpb_SourceKind_None;
|
||||
}
|
||||
default:
|
||||
return kPyUpb_SourceKind_None;
|
||||
}
|
||||
}
|
||||
|
||||
static bool PyUpb_ValidateClosedEnum(const upb_FieldDef* field,
|
||||
const void* data, Py_ssize_t count) {
|
||||
if (upb_FieldDef_CType(field) != kUpb_CType_Enum) return true;
|
||||
const upb_EnumDef* e = upb_FieldDef_EnumSubDef(field);
|
||||
if (!upb_EnumDef_IsClosed(e)) return true;
|
||||
const int32_t* i32 = (const int32_t*)data;
|
||||
for (Py_ssize_t i = 0; i < count; i++) {
|
||||
if (!upb_EnumDef_CheckNumber(e, i32[i])) {
|
||||
PyErr_Format(PyExc_ValueError, "invalid enumerator %d", (int)i32[i]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PyUpb_TryResult PyUpb_TryConvertBuffer(const upb_FieldDef* field,
|
||||
PyUpb_SourceKind src_kind,
|
||||
const void** buffer, size_t count,
|
||||
void** temp_buffer) {
|
||||
upb_CType ctype = upb_FieldDef_CType(field);
|
||||
const PyUpb_TargetKind tgt_kind = PyUpb_TargetKindFromCType(ctype);
|
||||
if (tgt_kind == kPyUpb_TargetKind_None ||
|
||||
src_kind == kPyUpb_SourceKind_None) {
|
||||
return kPyUpb_TryResult_NotSupported;
|
||||
}
|
||||
const bool src_is_float = src_kind == kPyUpb_SourceKind_Float ||
|
||||
src_kind == kPyUpb_SourceKind_Double;
|
||||
const bool dst_is_float = tgt_kind == kPyUpb_TargetKind_Float ||
|
||||
tgt_kind == kPyUpb_TargetKind_Double;
|
||||
if (src_is_float != dst_is_float) {
|
||||
return kPyUpb_TryResult_NotSupported;
|
||||
}
|
||||
if (PyUpb_SourceKindFromCType(ctype) != src_kind) {
|
||||
*temp_buffer = PyMem_Malloc(count * kPyUpb_TargetSize[tgt_kind]);
|
||||
if (!*temp_buffer) {
|
||||
PyErr_NoMemory();
|
||||
return kPyUpb_TryResult_Failure;
|
||||
}
|
||||
if (!src_is_float) {
|
||||
switch (PyUpb_IntegralCast(tgt_kind, *temp_buffer, src_kind, *buffer,
|
||||
count)) {
|
||||
case kPyUpb_TryResult_Success:
|
||||
break;
|
||||
case kPyUpb_TryResult_Failure:
|
||||
PyMem_Free(*temp_buffer);
|
||||
*temp_buffer = NULL;
|
||||
PyErr_SetString(PyExc_OverflowError, "Integer value out of range");
|
||||
return kPyUpb_TryResult_Failure;
|
||||
case kPyUpb_TryResult_NotSupported:
|
||||
PyMem_Free(*temp_buffer);
|
||||
*temp_buffer = NULL;
|
||||
return kPyUpb_TryResult_NotSupported;
|
||||
}
|
||||
} else {
|
||||
PyUpb_FloatCast(tgt_kind, *temp_buffer, src_kind, *buffer, count);
|
||||
}
|
||||
*buffer = *temp_buffer;
|
||||
}
|
||||
if (!PyUpb_ValidateClosedEnum(field, *buffer, count)) {
|
||||
if (*temp_buffer) {
|
||||
PyMem_Free(*temp_buffer);
|
||||
*temp_buffer = NULL;
|
||||
}
|
||||
return kPyUpb_TryResult_Failure;
|
||||
}
|
||||
return kPyUpb_TryResult_Success;
|
||||
}
|
||||
|
||||
#include "upb/port/undef.inc"
|
||||
68
python/buffer_convert.h
Normal file
68
python/buffer_convert.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// 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_PYTHON_BUFFER_CONVERT_H__
|
||||
#define UPB_PYTHON_BUFFER_CONVERT_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "upb/base/descriptor_constants.h"
|
||||
#include "upb/reflection/def.h"
|
||||
|
||||
// The result of an attempted buffer conversion.
|
||||
typedef enum {
|
||||
kPyUpb_TryResult_Success,
|
||||
// Operation failed. Python error is set.
|
||||
kPyUpb_TryResult_Failure,
|
||||
// Operation is not supported. Python error is not set.
|
||||
kPyUpb_TryResult_NotSupported,
|
||||
} PyUpb_TryResult;
|
||||
|
||||
// Represents the incoming buffer's underlying element type.
|
||||
typedef enum {
|
||||
kPyUpb_SourceKind_None = 0,
|
||||
kPyUpb_SourceKind_Float,
|
||||
kPyUpb_SourceKind_Double,
|
||||
kPyUpb_SourceKind_Bool,
|
||||
kPyUpb_SourceKind_Int8,
|
||||
kPyUpb_SourceKind_UInt8,
|
||||
kPyUpb_SourceKind_Int16,
|
||||
kPyUpb_SourceKind_UInt16,
|
||||
kPyUpb_SourceKind_Int32,
|
||||
kPyUpb_SourceKind_UInt32,
|
||||
kPyUpb_SourceKind_Int64,
|
||||
kPyUpb_SourceKind_UInt64
|
||||
} PyUpb_SourceKind;
|
||||
|
||||
// Helper to determine the source kind from a field's upb_CType.
|
||||
PyUpb_SourceKind PyUpb_SourceKindFromCType(upb_CType ctype);
|
||||
PyUpb_SourceKind PyUpb_SourceKindFromFormat(int itemsize, char format);
|
||||
|
||||
// Returns the byte size of the target CType for buffer assignment.
|
||||
size_t PyUpb_GetTargetItemSize(upb_CType ctype);
|
||||
|
||||
// Attempts to convert an array of `count` elements of `src_kind` from `*buffer`
|
||||
// into the type expected by `field`.
|
||||
//
|
||||
// If successful, returns kPyUpb_TryResult_Success. If conversion requires a new
|
||||
// allocation (e.g. types differ but are compatible), `*temp_buffer` is
|
||||
// allocated and `*buffer` is updated to point to it. The caller is responsible
|
||||
// for freeing
|
||||
// `*temp_buffer` if it is not NULL.
|
||||
//
|
||||
// If conversion is not supported, returns kPyUpb_TryResult_NotSupported.
|
||||
//
|
||||
// If conversion fails, returns kPyUpb_TryResult_Failure.
|
||||
// If SourceKind is the same as the target CType, conversion is a no-op however
|
||||
// enum values are still validated.
|
||||
PyUpb_TryResult PyUpb_TryConvertBuffer(const upb_FieldDef* field,
|
||||
PyUpb_SourceKind src_kind,
|
||||
const void** buffer, size_t count,
|
||||
void** temp_buffer);
|
||||
|
||||
#endif // UPB_PYTHON_BUFFER_CONVERT_H__
|
||||
|
|
@ -7,7 +7,14 @@
|
|||
|
||||
#include "python/repeated.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "google/protobuf/breaking_changes.h"
|
||||
#include "python/buffer_convert.h"
|
||||
#include "python/convert.h"
|
||||
#include "python/message.h"
|
||||
#include "python/protobuf.h"
|
||||
|
|
@ -21,23 +28,6 @@ static PyObject* PyUpb_RepeatedCompositeContainer_Append(PyObject* _self,
|
|||
PyObject* value);
|
||||
static PyObject* PyUpb_RepeatedScalarContainer_Append(PyObject* _self,
|
||||
PyObject* value);
|
||||
static Py_ssize_t GetDefaultDTypeSize(upb_CType cpp_type) {
|
||||
switch (cpp_type) {
|
||||
case kUpb_CType_Bool:
|
||||
return 1;
|
||||
case kUpb_CType_UInt32:
|
||||
case kUpb_CType_Int32:
|
||||
case kUpb_CType_Enum:
|
||||
case kUpb_CType_Float:
|
||||
return 4;
|
||||
case kUpb_CType_Int64:
|
||||
case kUpb_CType_UInt64:
|
||||
case kUpb_CType_Double:
|
||||
return 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper for a repeated field.
|
||||
typedef struct {
|
||||
|
|
@ -218,39 +208,9 @@ PyObject* PyUpb_RepeatedContainer_DeepCopy(PyObject* _self, PyObject* value) {
|
|||
}
|
||||
|
||||
#if PyUpb_SUPPORT_BUFFER_VIEW
|
||||
static bool IsContiguous1DAndMatchesFieldType(const Py_buffer* view,
|
||||
const upb_FieldDef* field) {
|
||||
const char* format = view->format;
|
||||
if (format == NULL || view->ndim != 1 ||
|
||||
(view->strides != NULL && view->itemsize != view->strides[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char fmt = format[0];
|
||||
// Always allow objects.
|
||||
if (fmt == 'O') {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (upb_FieldDef_CType(field)) {
|
||||
case kUpb_CType_Int32:
|
||||
case kUpb_CType_Enum:
|
||||
return view->itemsize == 4 && (fmt == 'i' || fmt == 'l');
|
||||
case kUpb_CType_Int64:
|
||||
return view->itemsize == 8 && (fmt == 'q' || fmt == 'l');
|
||||
case kUpb_CType_UInt32:
|
||||
return view->itemsize == 4 && (fmt == 'I');
|
||||
case kUpb_CType_UInt64:
|
||||
return view->itemsize == 8 && (fmt == 'Q');
|
||||
case kUpb_CType_Float:
|
||||
return view->itemsize == 4 && (fmt == 'f');
|
||||
case kUpb_CType_Double:
|
||||
return view->itemsize == 8 && (fmt == 'd');
|
||||
case kUpb_CType_Bool:
|
||||
return view->itemsize == 1 && (fmt == '?' || fmt == 'B');
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
static bool IsContiguous1D(const Py_buffer* view) {
|
||||
return view->ndim == 1 &&
|
||||
(view->strides == NULL || view->itemsize == view->strides[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -270,117 +230,121 @@ typedef bool (*PyUpb_ElemCb)(upb_MessageValue val, void* ctx);
|
|||
typedef bool (*PyUpb_BulkCb)(const void* data, Py_ssize_t count,
|
||||
Py_ssize_t itemsize, void* ctx);
|
||||
|
||||
typedef enum {
|
||||
kTryResult_Success,
|
||||
kTryResult_Failure,
|
||||
kTryResult_NotSupported,
|
||||
} TryResult;
|
||||
|
||||
static TryResult PyUpb_IterInputTryRepeatedContainer(PyObject* value,
|
||||
const upb_FieldDef* field,
|
||||
upb_Arena* arena,
|
||||
PyUpb_BulkCb bulk_cb,
|
||||
void* ctx) {
|
||||
// Detect if value is a repeated scalar container of the same field type.
|
||||
static PyUpb_TryResult PyUpb_IterInputTryRepeatedContainer(
|
||||
PyObject* value, const upb_FieldDef* field, upb_Arena* arena,
|
||||
PyUpb_BulkCb bulk_cb, void* ctx) {
|
||||
// Detect if value is a repeated scalar container of a compatible field type.
|
||||
PyUpb_ModuleState* state = PyUpb_ModuleState_MaybeGet();
|
||||
if (state == NULL ||
|
||||
Py_TYPE(value) != state->repeated_scalar_container_type) {
|
||||
return kTryResult_NotSupported;
|
||||
return kPyUpb_TryResult_NotSupported;
|
||||
}
|
||||
PyUpb_RepeatedContainer* other = (PyUpb_RepeatedContainer*)value;
|
||||
const upb_FieldDef* other_f = PyUpb_RepeatedContainer_GetField(other);
|
||||
if (upb_FieldDef_CType(other_f) != upb_FieldDef_CType(field)) {
|
||||
return kTryResult_NotSupported;
|
||||
}
|
||||
Py_ssize_t itemsize = GetDefaultDTypeSize(upb_FieldDef_CType(field));
|
||||
if (itemsize == 0) {
|
||||
return kTryResult_NotSupported;
|
||||
}
|
||||
upb_Array* arr = PyUpb_RepeatedContainer_GetIfReified(other);
|
||||
size_t count = arr ? upb_Array_Size(arr) : 0;
|
||||
PyUpb_RepeatedContainer* src = (PyUpb_RepeatedContainer*)value;
|
||||
const upb_FieldDef* src_f = PyUpb_RepeatedContainer_GetField(src);
|
||||
const upb_CType src_type = upb_FieldDef_CType(src_f);
|
||||
const PyUpb_SourceKind src_kind = PyUpb_SourceKindFromCType(src_type);
|
||||
|
||||
upb_Array* src_arr = PyUpb_RepeatedContainer_GetIfReified(src);
|
||||
size_t count = src_arr ? upb_Array_Size(src_arr) : 0;
|
||||
if (count == 0) {
|
||||
return bulk_cb(NULL, 0, 0, ctx) ? kTryResult_Success : kTryResult_Failure;
|
||||
return bulk_cb(NULL, 0, 0, ctx) ? kPyUpb_TryResult_Success
|
||||
: kPyUpb_TryResult_Failure;
|
||||
}
|
||||
const void* data = upb_Array_DataPtr(arr);
|
||||
if (upb_FieldDef_CType(field) == kUpb_CType_Enum &&
|
||||
upb_FieldDef_EnumSubDef(other_f) != upb_FieldDef_EnumSubDef(field)) {
|
||||
const upb_EnumDef* e = upb_FieldDef_EnumSubDef(field);
|
||||
if (upb_EnumDef_IsClosed(e)) {
|
||||
const int32_t* i32 = (const int32_t*)data;
|
||||
for (Py_ssize_t i = 0; i < (Py_ssize_t)count; i++) {
|
||||
if (!upb_EnumDef_CheckNumber(e, i32[i])) {
|
||||
PyErr_Format(PyExc_ValueError, "invalid enumerator %d", (int)i32[i]);
|
||||
return kTryResult_Failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
const void* src_data = upb_Array_DataPtr(src_arr);
|
||||
void* cast_data = NULL;
|
||||
PyUpb_TryResult res =
|
||||
PyUpb_TryConvertBuffer(field, src_kind, &src_data, count, &cast_data);
|
||||
if (res != kPyUpb_TryResult_Success) {
|
||||
return res;
|
||||
}
|
||||
return bulk_cb(data, count, itemsize, ctx) ? kTryResult_Success
|
||||
: kTryResult_Failure;
|
||||
|
||||
const size_t target_item_size =
|
||||
PyUpb_GetTargetItemSize(upb_FieldDef_CType(field));
|
||||
bool ok = bulk_cb(src_data, count, target_item_size, ctx);
|
||||
|
||||
if (cast_data != NULL) {
|
||||
PyMem_Free(cast_data);
|
||||
}
|
||||
|
||||
return ok ? kPyUpb_TryResult_Success : kPyUpb_TryResult_Failure;
|
||||
}
|
||||
|
||||
#if PyUpb_SUPPORT_BUFFER_VIEW
|
||||
static TryResult PyUpb_IterInputTryBufferView(PyObject* value,
|
||||
const upb_FieldDef* field,
|
||||
upb_Arena* arena,
|
||||
PyUpb_SizeCb size_cb,
|
||||
PyUpb_ElemCb elem_cb,
|
||||
PyUpb_BulkCb bulk_cb, void* ctx) {
|
||||
static PyUpb_TryResult PyUpb_IterInputTryBufferView(
|
||||
PyObject* value, const upb_FieldDef* field, upb_Arena* arena,
|
||||
PyUpb_SizeCb size_cb, PyUpb_ElemCb elem_cb, PyUpb_BulkCb bulk_cb,
|
||||
void* ctx) {
|
||||
Py_buffer view;
|
||||
if (PyObject_GetBuffer(value, &view, PyBUF_RECORDS_RO) != 0) {
|
||||
PyErr_Clear();
|
||||
return kTryResult_NotSupported;
|
||||
return kPyUpb_TryResult_NotSupported;
|
||||
}
|
||||
if (!IsContiguous1DAndMatchesFieldType(&view, field)) {
|
||||
if (!IsContiguous1D(&view)) {
|
||||
PyBuffer_Release(&view);
|
||||
return kTryResult_NotSupported;
|
||||
return kPyUpb_TryResult_NotSupported;
|
||||
}
|
||||
const void* src_buf = view.buf;
|
||||
void* temp_buf = NULL;
|
||||
const char format = view.format == NULL ? 'B' : view.format[0];
|
||||
Py_ssize_t count = view.len / view.itemsize;
|
||||
if (count == 0) {
|
||||
PyBuffer_Release(&view);
|
||||
return bulk_cb(NULL, 0, 0, ctx) ? kTryResult_Success : kTryResult_Failure;
|
||||
return bulk_cb(NULL, 0, 0, ctx) ? kPyUpb_TryResult_Success
|
||||
: kPyUpb_TryResult_Failure;
|
||||
}
|
||||
if (view.format[0] != 'O') {
|
||||
if (upb_FieldDef_CType(field) == kUpb_CType_Enum) {
|
||||
const upb_EnumDef* e = upb_FieldDef_EnumSubDef(field);
|
||||
if (upb_EnumDef_IsClosed(e)) {
|
||||
const int32_t* i32 = (const int32_t*)view.buf;
|
||||
for (Py_ssize_t i = 0; i < count; i++) {
|
||||
if (!upb_EnumDef_CheckNumber(e, i32[i])) {
|
||||
PyErr_Format(PyExc_ValueError, "invalid enumerator %d",
|
||||
(int)i32[i]);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (format == 'O') {
|
||||
PyObject** objs = (PyObject**)src_buf;
|
||||
if (!size_cb(count, ctx)) {
|
||||
goto error;
|
||||
}
|
||||
for (Py_ssize_t i = 0; i < count; i++) {
|
||||
PyObject* item = objs[i] ? objs[i] : Py_None;
|
||||
upb_MessageValue msgval;
|
||||
if (!PyUpb_PyToUpb(item, field, &msgval, arena)) {
|
||||
goto error;
|
||||
}
|
||||
if (!elem_cb(msgval, ctx)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (bulk_cb(view.buf, count, view.itemsize, ctx)) {
|
||||
goto done;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
PyObject** objs = (PyObject**)view.buf;
|
||||
if (!size_cb(count, ctx)) {
|
||||
const PyUpb_SourceKind src_kind =
|
||||
PyUpb_SourceKindFromFormat(view.itemsize, format);
|
||||
switch (PyUpb_TryConvertBuffer(field, src_kind, &src_buf, count, &temp_buf)) {
|
||||
case kPyUpb_TryResult_Success:
|
||||
break;
|
||||
case kPyUpb_TryResult_Failure:
|
||||
goto error;
|
||||
case kPyUpb_TryResult_NotSupported:
|
||||
goto not_supported;
|
||||
}
|
||||
const size_t target_item_size =
|
||||
PyUpb_GetTargetItemSize(upb_FieldDef_CType(field));
|
||||
if (bulk_cb(src_buf, count, target_item_size, ctx)) {
|
||||
goto done;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
for (Py_ssize_t i = 0; i < count; i++) {
|
||||
PyObject* item = objs[i] ? objs[i] : Py_None;
|
||||
upb_MessageValue msgval;
|
||||
if (!PyUpb_PyToUpb(item, field, &msgval, arena)) {
|
||||
goto error;
|
||||
}
|
||||
if (!elem_cb(msgval, ctx)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (temp_buf) {
|
||||
PyMem_Free(temp_buf);
|
||||
}
|
||||
PyBuffer_Release(&view);
|
||||
return kTryResult_Success;
|
||||
return kPyUpb_TryResult_Success;
|
||||
error:
|
||||
if (temp_buf) {
|
||||
PyMem_Free(temp_buf);
|
||||
}
|
||||
PyBuffer_Release(&view);
|
||||
return kTryResult_Failure;
|
||||
return kPyUpb_TryResult_Failure;
|
||||
not_supported:
|
||||
if (temp_buf) {
|
||||
PyMem_Free(temp_buf);
|
||||
}
|
||||
PyBuffer_Release(&view);
|
||||
return kPyUpb_TryResult_NotSupported;
|
||||
}
|
||||
#endif // PyUpb_SUPPORT_BUFFER_VIEW
|
||||
|
||||
|
|
@ -400,22 +364,22 @@ static bool PyUpb_IterInput(PyObject* value, const upb_FieldDef* field,
|
|||
void* ctx) {
|
||||
switch (
|
||||
PyUpb_IterInputTryRepeatedContainer(value, field, arena, bulk_cb, ctx)) {
|
||||
case kTryResult_Success:
|
||||
case kPyUpb_TryResult_Success:
|
||||
return true;
|
||||
case kTryResult_Failure:
|
||||
case kPyUpb_TryResult_Failure:
|
||||
return false;
|
||||
case kTryResult_NotSupported:
|
||||
case kPyUpb_TryResult_NotSupported:
|
||||
break;
|
||||
}
|
||||
|
||||
#if PyUpb_SUPPORT_BUFFER_VIEW
|
||||
switch (PyUpb_IterInputTryBufferView(value, field, arena, size_cb, elem_cb,
|
||||
bulk_cb, ctx)) {
|
||||
case kTryResult_Success:
|
||||
case kPyUpb_TryResult_Success:
|
||||
return true;
|
||||
case kTryResult_Failure:
|
||||
case kPyUpb_TryResult_Failure:
|
||||
return false;
|
||||
case kTryResult_NotSupported:
|
||||
case kPyUpb_TryResult_NotSupported:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue