From 3e0f4ffb4cbff68d225f77373793aced77dda4b3 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Fri, 29 May 2026 08:57:27 +0200 Subject: [PATCH 1/2] fix(abi): pin enum width and use uint64_t in the C ABI (future-proofing) Two layout-neutral hardening changes to the plugin C ABI, both protecting third-party plugins built on non-default toolchains. Genuinely irreversible once such plugins ship, so done before wide adoption. Enum width pinning: every by-value C-ABI enum (PJ_primitive_type_t, PJ_data_source_state_t, the message-level / message-box-type / message-box- buttons enums, PJ_toolbox_message_level_t) gains a `..._FORCE_INT32 = 0x7FFFFFFF` enumerator. The existing sizeof==4 static_asserts only protect this project's build; the enumerator is what forces a stable 4-byte width into a plugin compiled with -fshort-enums, where these enums (max value 0xFF) would otherwise shrink to 1 byte and silently misalign every struct/param that embeds them. Adds the missing PJ_message_box_buttons_t sentinel. Fixed-width sizes: replaces size_t with uint64_t in every C-ABI struct and function-pointer signature (plugin_data_api.h). size_t is what made the ABI implicitly 64-bit-only; uint64_t makes the width explicit and platform- independent. Both are layout-identical on the supported 64-bit target: enum sizeof stays 4, size_t and uint64_t are the same width, no vtable offset or size moves. All layout sentinels and 62/62 tests pass unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../include/pj_base/data_source_protocol.h | 15 ++++-- pj_base/include/pj_base/plugin_data_api.h | 47 ++++++++++--------- pj_base/include/pj_base/toolbox_protocol.h | 1 + pj_base/tests/abi_layout_sentinels_test.cpp | 7 ++- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/pj_base/include/pj_base/data_source_protocol.h b/pj_base/include/pj_base/data_source_protocol.h index 6d43496..f2c8bb4 100644 --- a/pj_base/include/pj_base/data_source_protocol.h +++ b/pj_base/include/pj_base/data_source_protocol.h @@ -80,6 +80,10 @@ typedef enum { PJ_DATA_SOURCE_STATE_STOPPING = 5, PJ_DATA_SOURCE_STATE_STOPPED = 6, /**< Terminal. */ PJ_DATA_SOURCE_STATE_FAILED = 7, /**< Terminal. */ + /* Forces a stable 4-byte width across compilers, so a plugin built with + * -fshort-enums cannot shrink this enum and misalign by-value uses. Not a + * real state; never returned or accepted. */ + PJ_DATA_SOURCE_STATE_FORCE_INT32 = 0x7FFFFFFF, } PJ_data_source_state_t; /** Severity level for plugin-to-host diagnostic messages. */ @@ -87,14 +91,16 @@ typedef enum { PJ_DATA_SOURCE_MESSAGE_INFO = 0, PJ_DATA_SOURCE_MESSAGE_WARNING = 1, PJ_DATA_SOURCE_MESSAGE_ERROR = 2, + PJ_DATA_SOURCE_MESSAGE_FORCE_INT32 = 0x7FFFFFFF, /* pin 4-byte width; not a real level */ } PJ_data_source_message_level_t; /** Type of message box to display. Determines the icon shown. */ typedef enum { - PJ_MESSAGE_BOX_INFO = 0, /**< Information icon (i). */ - PJ_MESSAGE_BOX_WARNING = 1, /**< Warning icon (!). */ - PJ_MESSAGE_BOX_ERROR = 2, /**< Error/critical icon (X). */ - PJ_MESSAGE_BOX_QUESTION = 3, /**< Question icon (?). */ + PJ_MESSAGE_BOX_INFO = 0, /**< Information icon (i). */ + PJ_MESSAGE_BOX_WARNING = 1, /**< Warning icon (!). */ + PJ_MESSAGE_BOX_ERROR = 2, /**< Error/critical icon (X). */ + PJ_MESSAGE_BOX_QUESTION = 3, /**< Question icon (?). */ + PJ_MESSAGE_BOX_TYPE_FORCE_INT32 = 0x7FFFFFFF, /* pin 4-byte width; not a real type */ } PJ_message_box_type_t; /** @@ -110,6 +116,7 @@ typedef enum { PJ_MSG_BTN_ABORT = 0x20, PJ_MSG_BTN_RETRY = 0x40, PJ_MSG_BTN_IGNORE = 0x80, + PJ_MSG_BTN_FORCE_INT32 = 0x7FFFFFFF, /* pin 4-byte width; not a real button */ } PJ_message_box_buttons_t; /** diff --git a/pj_base/include/pj_base/plugin_data_api.h b/pj_base/include/pj_base/plugin_data_api.h index 0940082..d48648d 100644 --- a/pj_base/include/pj_base/plugin_data_api.h +++ b/pj_base/include/pj_base/plugin_data_api.h @@ -93,18 +93,22 @@ typedef enum { /** Sentinel: null value with no type information. Used when is_null=true * and the plugin provides no type hint (untyped kNull). */ PJ_PRIMITIVE_TYPE_UNSPECIFIED = 0xFF, + /* Forces a stable 4-byte width across compilers, so a plugin built with + * -fshort-enums cannot shrink this enum and misalign the by-value uses in + * PJ_scalar_value_t / PJ_field_info_t / ensure_field. Not a real type. */ + PJ_PRIMITIVE_TYPE_FORCE_INT32 = 0x7FFFFFFF, } PJ_primitive_type_t; /* ABI-FROZEN: layout permanent; changes = ABI break. */ typedef struct { const char* data; - size_t size; + uint64_t size; } PJ_string_view_t; /* ABI-FROZEN: layout permanent; changes = ABI break. */ typedef struct { const uint8_t* data; - size_t size; + uint64_t size; } PJ_bytes_view_t; /* ========================================================================== @@ -317,11 +321,11 @@ typedef struct { typedef struct { const PJ_data_source_info_t* data_sources; - size_t data_source_count; + uint64_t data_source_count; const PJ_topic_info_t* topics; - size_t topic_count; + uint64_t topic_count; const PJ_field_info_t* fields; - size_t field_count; + uint64_t field_count; void* release_ctx; void (*release)(void* release_ctx); } PJ_catalog_snapshot_t; @@ -373,13 +377,13 @@ typedef struct PJ_source_write_host_vtable_t { /* [stream-thread] Append a record by field name. Convenience path for * simple plugins; resolves field handles on every call. */ bool (*append_record)( - void* ctx, PJ_topic_handle_t topic, int64_t timestamp, const PJ_named_field_value_t* fields, size_t field_count, + void* ctx, PJ_topic_handle_t topic, int64_t timestamp, const PJ_named_field_value_t* fields, uint64_t field_count, PJ_error_t* out_error) PJ_NOEXCEPT; /* [stream-thread] Append a record with pre-resolved field handles. Fast * path for streaming producers — skip the name lookup. */ bool (*append_bound_record)( - void* ctx, PJ_topic_handle_t topic, int64_t timestamp, const PJ_bound_field_value_t* fields, size_t field_count, + void* ctx, PJ_topic_handle_t topic, int64_t timestamp, const PJ_bound_field_value_t* fields, uint64_t field_count, PJ_error_t* out_error) PJ_NOEXCEPT; /* [stream-thread] PRIMARY BATCH PATH. Plugin hands ownership of an Arrow @@ -417,12 +421,12 @@ typedef struct PJ_parser_write_host_vtable_t { /* [stream-thread] Append a record by field name. */ bool (*append_record)( - void* ctx, int64_t timestamp, const PJ_named_field_value_t* fields, size_t field_count, + void* ctx, int64_t timestamp, const PJ_named_field_value_t* fields, uint64_t field_count, PJ_error_t* out_error) PJ_NOEXCEPT; /* [stream-thread] Append a record with pre-resolved field handles. */ bool (*append_bound_record)( - void* ctx, int64_t timestamp, const PJ_bound_field_value_t* fields, size_t field_count, + void* ctx, int64_t timestamp, const PJ_bound_field_value_t* fields, uint64_t field_count, PJ_error_t* out_error) PJ_NOEXCEPT; /* [stream-thread] Optional batch path. Plugin hands ownership of an Arrow @@ -474,12 +478,12 @@ typedef struct PJ_toolbox_host_vtable_t { /* [main-thread] Append a record by field name. */ bool (*append_record)( - void* ctx, PJ_topic_handle_t topic, int64_t timestamp, const PJ_named_field_value_t* fields, size_t field_count, + void* ctx, PJ_topic_handle_t topic, int64_t timestamp, const PJ_named_field_value_t* fields, uint64_t field_count, PJ_error_t* out_error) PJ_NOEXCEPT; /* [main-thread] Append a record with pre-resolved field handles. */ bool (*append_bound_record)( - void* ctx, PJ_topic_handle_t topic, int64_t timestamp, const PJ_bound_field_value_t* fields, size_t field_count, + void* ctx, PJ_topic_handle_t topic, int64_t timestamp, const PJ_bound_field_value_t* fields, uint64_t field_count, PJ_error_t* out_error) PJ_NOEXCEPT; /* [main-thread] Bulk-write via Arrow C Data Interface (same ownership rule @@ -516,7 +520,7 @@ typedef struct PJ_toolbox_host_vtable_t { * push is not offered on the toolbox surface (plugin holds the bytes * already by the time it calls). */ bool (*push_owned_object)( - void* ctx, PJ_object_topic_handle_t topic, int64_t timestamp_ns, const uint8_t* data, size_t size, + void* ctx, PJ_object_topic_handle_t topic, int64_t timestamp_ns, const uint8_t* data, uint64_t size, PJ_error_t* out_error) PJ_NOEXCEPT; } PJ_toolbox_host_vtable_t; @@ -549,7 +553,7 @@ typedef struct { * fetch context — valid at least until the NEXT call to the same fn or * until fetch_ctx_destroy runs. The host immediately copies the bytes; the * plugin may reuse or free the buffer on the following call. */ -typedef bool (*PJ_lazy_fetch_fn_t)(void* fetch_ctx, const uint8_t** out_data, size_t* out_size) PJ_NOEXCEPT; +typedef bool (*PJ_lazy_fetch_fn_t)(void* fetch_ctx, const uint8_t** out_data, uint64_t* out_size) PJ_NOEXCEPT; /* ABI-APPENDABLE: new slots may be added at the tail; struct_size gates read. * @@ -580,7 +584,7 @@ typedef struct PJ_object_write_host_vtable_t { * (markers, annotations, scene primitives) whose aggregate volume stays * comfortably in memory. */ bool (*push_owned)( - void* ctx, PJ_object_topic_handle_t topic, int64_t timestamp_ns, const uint8_t* data, size_t size, + void* ctx, PJ_object_topic_handle_t topic, int64_t timestamp_ns, const uint8_t* data, uint64_t size, PJ_error_t* out_error) PJ_NOEXCEPT; /* [stream-thread] Push a lazy entry — host stores the fetch closure, not @@ -598,7 +602,7 @@ typedef struct PJ_object_write_host_vtable_t { * Typical plugin author usage: do NOT call this. The application owns * the retention policy; DataSource plugins should leave budgets alone. */ void (*set_retention_budget)( - void* ctx, PJ_object_topic_handle_t topic, int64_t time_window_ns, size_t max_memory_bytes) PJ_NOEXCEPT; + void* ctx, PJ_object_topic_handle_t topic, int64_t time_window_ns, uint64_t max_memory_bytes) PJ_NOEXCEPT; } PJ_object_write_host_vtable_t; /* ABI-FROZEN: fat pointer layout permanent. */ @@ -634,7 +638,7 @@ typedef struct PJ_parser_object_write_host_vtable_t { /* [stream-thread] Eager push of serialized payload bytes into the bound * object topic. Store copies the bytes. */ - bool (*push_owned)(void* ctx, int64_t timestamp_ns, const uint8_t* data, size_t size, PJ_error_t* out_error) + bool (*push_owned)(void* ctx, int64_t timestamp_ns, const uint8_t* data, uint64_t size, PJ_error_t* out_error) PJ_NOEXCEPT; /* [stream-thread] Lazy push. Rarely used from parsers (a delegated parser @@ -689,7 +693,7 @@ typedef struct PJ_object_read_host_vtable_t { * up to that many handles and always sets *out_count to the TOTAL number * of topics (so the caller can detect truncation and resize). */ bool (*list_topics)( - void* ctx, PJ_object_topic_handle_t* out_buffer, size_t buffer_capacity, size_t* out_count, + void* ctx, PJ_object_topic_handle_t* out_buffer, uint64_t buffer_capacity, uint64_t* out_count, PJ_error_t* out_error) PJ_NOEXCEPT; /* [main-thread] Return the topic's metadata JSON — a pointer stable for @@ -706,13 +710,13 @@ typedef struct PJ_object_read_host_vtable_t { /* [thread-safe] Expose the bytes behind an owning handle. View is valid * until release_bytes(handle). Safe to call from decoder worker threads. */ - void (*get_bytes)(PJ_object_bytes_handle_t handle, const uint8_t** out_data, size_t* out_size) PJ_NOEXCEPT; + void (*get_bytes)(PJ_object_bytes_handle_t handle, const uint8_t** out_data, uint64_t* out_size) PJ_NOEXCEPT; /* [thread-safe] Release an owning handle. Idempotent on NULL. */ void (*release_bytes)(PJ_object_bytes_handle_t handle) PJ_NOEXCEPT; /* [main-thread] Entry count for a topic. 0 on bad handle. */ - size_t (*entry_count)(void* ctx, PJ_object_topic_handle_t topic) PJ_NOEXCEPT; + uint64_t (*entry_count)(void* ctx, PJ_object_topic_handle_t topic) PJ_NOEXCEPT; /* [main-thread] Time range [min, max] for a topic. Returns false if the * topic is unknown or empty. */ @@ -775,12 +779,13 @@ typedef struct PJ_settings_store_vtable_t { /* [main-thread] Read a string list. On found, *out_items points to an array * of *out_count entries, valid until the next call on this store. */ bool (*get_string_list)( - void* ctx, PJ_string_view_t key, const PJ_string_view_t** out_items, size_t* out_count, bool* out_found, + void* ctx, PJ_string_view_t key, const PJ_string_view_t** out_items, uint64_t* out_count, bool* out_found, PJ_error_t* out_error) PJ_NOEXCEPT; /* [main-thread] Write a string list (create or overwrite). */ bool (*set_string_list)( - void* ctx, PJ_string_view_t key, const PJ_string_view_t* items, size_t count, PJ_error_t* out_error) PJ_NOEXCEPT; + void* ctx, PJ_string_view_t key, const PJ_string_view_t* items, uint64_t count, + PJ_error_t* out_error) PJ_NOEXCEPT; /* [main-thread] Report whether a key exists, in *out_present. */ bool (*contains)(void* ctx, PJ_string_view_t key, bool* out_present, PJ_error_t* out_error) PJ_NOEXCEPT; diff --git a/pj_base/include/pj_base/toolbox_protocol.h b/pj_base/include/pj_base/toolbox_protocol.h index e515d48..e61bb93 100644 --- a/pj_base/include/pj_base/toolbox_protocol.h +++ b/pj_base/include/pj_base/toolbox_protocol.h @@ -53,6 +53,7 @@ typedef enum { PJ_TOOLBOX_MESSAGE_INFO = 0, PJ_TOOLBOX_MESSAGE_WARNING = 1, PJ_TOOLBOX_MESSAGE_ERROR = 2, + PJ_TOOLBOX_MESSAGE_FORCE_INT32 = 0x7FFFFFFF, /* pin 4-byte width; not a real level */ } PJ_toolbox_message_level_t; enum { diff --git a/pj_base/tests/abi_layout_sentinels_test.cpp b/pj_base/tests/abi_layout_sentinels_test.cpp index bf39f3c..1b8b885 100644 --- a/pj_base/tests/abi_layout_sentinels_test.cpp +++ b/pj_base/tests/abi_layout_sentinels_test.cpp @@ -40,12 +40,15 @@ static_assert(sizeof(void*) == 8, "v4 ABI pinned to 64-bit targets"); // --- Enum size guards -------------------------------------------------------- -// Defends against `-fshort-enums` and similar flags that silently shrink -// enums below the 32-bit wire assumption. +// Each ABI enum carries a `..._FORCE_INT32 = 0x7FFFFFFF` enumerator that pins +// its width to a stable 4 bytes even under `-fshort-enums` in a third-party +// plugin build — the enumerator is what travels into the plugin's compiler; +// these static_asserts only verify the pinning holds in this build too. static_assert(sizeof(PJ_primitive_type_t) == 4, "enum layout pinned"); static_assert(sizeof(PJ_data_source_state_t) == 4, "enum layout pinned"); static_assert(sizeof(PJ_data_source_message_level_t) == 4, "enum layout pinned"); static_assert(sizeof(PJ_message_box_type_t) == 4, "enum layout pinned"); +static_assert(sizeof(PJ_message_box_buttons_t) == 4, "enum layout pinned"); static_assert(sizeof(PJ_toolbox_message_level_t) == 4, "enum layout pinned"); // --- PJ_error_t (ABI-FROZEN) ------------------------------------------------- From f60c01cb01621ce970aa4cb65c31f70f101bb4f1 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Fri, 29 May 2026 12:15:22 +0200 Subject: [PATCH 2/2] fix(abi): match C++ host/SDK to the uint64_t C ABI (fixes macOS build) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prior commit widened the C ABI (plugin_data_api.h) from size_t to uint64_t, but the C++ host vtable implementations and SDK host-views that fill those slots still used size_t. On macOS uint64_t is `unsigned long long` while size_t is `unsigned long` — same width, distinct types — so the trampolines fail to bind to the slots and the out-param pointers mismatch (size_t* vs uint64_t*). Linux (glibc) and Windows (MSVC) alias both to one type, so only macOS CI caught it. Convert every ABI-boundary size_t to uint64_t, keeping size_t for purely internal in-memory indexing: - pj_datastore host trampolines: append_record/append_bound_record field_count, push_owned size, lazy-fetch out_size, set_retention_budget, list_topics capacity/out_count, get_bytes out_size, entry_count return. - SDK host-views (plugin_data_api.hpp): list_topics/get_string_list counts, entryCount return, setRetentionBudget param, both LazyBox trampolines; object_bytes.hpp get_bytes; settings_store_host slots. - testing helpers + 4 built test trampolines bound to the same slots. Value conversions size_t<->uint64_t are same-width and warning-free on 64-bit; only the pointer and function-pointer types required fixing. Internal storage (RetentionBudget.max_memory_bytes, encoding/buffer indexing) stays size_t. Build (Debug+ASAN, -Werror -Wconversion) + 62/62 tests pass; clang-format clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- pj_base/include/pj_base/sdk/object_bytes.hpp | 2 +- .../include/pj_base/sdk/plugin_data_api.hpp | 12 +++---- .../pj_base/sdk/settings_store_host.hpp | 4 +-- .../sdk/testing/parser_write_recorder.hpp | 4 +-- pj_base/tests/plugin_data_api_test.cpp | 4 +-- pj_datastore/src/plugin_data_host.cpp | 32 ++++++++++--------- .../tests/plugin_data_host_object_test.cpp | 2 +- .../pj_plugins/testing/toolbox_test_store.hpp | 4 +-- pj_plugins/tests/data_source_library_test.cpp | 4 +-- .../tests/file_source_integration_test.cpp | 4 +-- pj_plugins/tests/toolbox_plugin_test.cpp | 4 +-- 11 files changed, 39 insertions(+), 37 deletions(-) diff --git a/pj_base/include/pj_base/sdk/object_bytes.hpp b/pj_base/include/pj_base/sdk/object_bytes.hpp index db3236f..9422bb5 100644 --- a/pj_base/include/pj_base/sdk/object_bytes.hpp +++ b/pj_base/include/pj_base/sdk/object_bytes.hpp @@ -65,7 +65,7 @@ class ObjectBytes { return {}; } const uint8_t* data = nullptr; - std::size_t size = 0; + uint64_t size = 0; // matches PJ_object_read_host_vtable_t::get_bytes (uint64_t*) vtable_->get_bytes(handle_, &data, &size); return Span(data, size); } diff --git a/pj_base/include/pj_base/sdk/plugin_data_api.hpp b/pj_base/include/pj_base/sdk/plugin_data_api.hpp index 23329ec..9ac8844 100644 --- a/pj_base/include/pj_base/sdk/plugin_data_api.hpp +++ b/pj_base/include/pj_base/sdk/plugin_data_api.hpp @@ -609,7 +609,7 @@ class ToolboxObjectReadHostView { return unexpected("toolbox object read host is not bound"); } // First pass: ask for the count. - std::size_t count = 0; + uint64_t count = 0; // matches PJ_object_read_host_vtable_t::list_topics (uint64_t*) PJ_error_t err{}; if (!host_.vtable->list_topics(host_.ctx, nullptr, 0, &count, &err)) { return unexpected(errorToString(err)); @@ -655,7 +655,7 @@ class ToolboxObjectReadHostView { return ObjectBytes(handle, host_.vtable); } - [[nodiscard]] std::size_t entryCount(ObjectTopicHandle topic) const { + [[nodiscard]] uint64_t entryCount(ObjectTopicHandle topic) const { if (!valid() || host_.vtable->entry_count == nullptr) { return 0; } @@ -764,7 +764,7 @@ class SourceObjectWriteHostView { } /// Configure retention. Application-level concern — plugins rarely call this. - void setRetentionBudget(ObjectTopicHandle topic, int64_t time_window_ns, size_t max_memory_bytes) const { + void setRetentionBudget(ObjectTopicHandle topic, int64_t time_window_ns, uint64_t max_memory_bytes) const { if (!valid()) { return; } @@ -786,7 +786,7 @@ class SourceObjectWriteHostView { FetchFn fetch; std::vector last_bytes; - static bool trampoline(void* ctx, const uint8_t** out_data, size_t* out_size) noexcept { + static bool trampoline(void* ctx, const uint8_t** out_data, uint64_t* out_size) noexcept { if (ctx == nullptr || out_data == nullptr || out_size == nullptr) { return false; } @@ -866,7 +866,7 @@ class ParserObjectWriteHostView { FetchFn fetch; std::vector last_bytes; - static bool trampoline(void* ctx, const uint8_t** out_data, size_t* out_size) noexcept { + static bool trampoline(void* ctx, const uint8_t** out_data, uint64_t* out_size) noexcept { if (ctx == nullptr || out_data == nullptr || out_size == nullptr) { return false; } @@ -1442,7 +1442,7 @@ class SettingsView { return result; } const PJ_string_view_t* items = nullptr; - std::size_t count = 0; + uint64_t count = 0; // matches PJ_settings_store_vtable_t::get_string_list (uint64_t*) bool found = false; PJ_error_t err{}; if (!store_.vtable->get_string_list(store_.ctx, toAbiString(key), &items, &count, &found, &err)) { diff --git a/pj_base/include/pj_base/sdk/settings_store_host.hpp b/pj_base/include/pj_base/sdk/settings_store_host.hpp index f6d8ead..ca95f8d 100644 --- a/pj_base/include/pj_base/sdk/settings_store_host.hpp +++ b/pj_base/include/pj_base/sdk/settings_store_host.hpp @@ -105,7 +105,7 @@ class SettingsStoreHost { } static bool tGetStringList( - void* ctx, PJ_string_view_t key, const PJ_string_view_t** out_items, size_t* out_count, bool* out_found, + void* ctx, PJ_string_view_t key, const PJ_string_view_t** out_items, uint64_t* out_count, bool* out_found, PJ_error_t* out_error) noexcept { if (ctx == nullptr || out_items == nullptr || out_count == nullptr || out_found == nullptr) { fillError(out_error, 2, "settings", "null ctx or out-param"); @@ -140,7 +140,7 @@ class SettingsStoreHost { } static bool tSetStringList( - void* ctx, PJ_string_view_t key, const PJ_string_view_t* items, size_t count, PJ_error_t* out_error) noexcept { + void* ctx, PJ_string_view_t key, const PJ_string_view_t* items, uint64_t count, PJ_error_t* out_error) noexcept { if (ctx == nullptr || (items == nullptr && count != 0)) { fillError(out_error, 2, "settings", "null ctx or items"); return false; diff --git a/pj_base/include/pj_base/sdk/testing/parser_write_recorder.hpp b/pj_base/include/pj_base/sdk/testing/parser_write_recorder.hpp index 2e395f5..fa98687 100644 --- a/pj_base/include/pj_base/sdk/testing/parser_write_recorder.hpp +++ b/pj_base/include/pj_base/sdk/testing/parser_write_recorder.hpp @@ -179,7 +179,7 @@ class ParserWriteRecorder { } static bool trampolineAppendRecord( - void* ctx, int64_t timestamp, const PJ_named_field_value_t* fields, size_t field_count, PJ_error_t*) noexcept { + void* ctx, int64_t timestamp, const PJ_named_field_value_t* fields, uint64_t field_count, PJ_error_t*) noexcept { auto* self = static_cast(ctx); RecordedRow row; row.timestamp = timestamp; @@ -198,7 +198,7 @@ class ParserWriteRecorder { } static bool trampolineAppendBoundRecord( - void* ctx, int64_t timestamp, const PJ_bound_field_value_t* fields, size_t field_count, PJ_error_t*) noexcept { + void* ctx, int64_t timestamp, const PJ_bound_field_value_t* fields, uint64_t field_count, PJ_error_t*) noexcept { auto* self = static_cast(ctx); RecordedRow row; row.timestamp = timestamp; diff --git a/pj_base/tests/plugin_data_api_test.cpp b/pj_base/tests/plugin_data_api_test.cpp index ca1f575..155d4bc 100644 --- a/pj_base/tests/plugin_data_api_test.cpp +++ b/pj_base/tests/plugin_data_api_test.cpp @@ -49,11 +49,11 @@ bool parserEnsureField( return true; } -bool parserAppendRecord(void*, int64_t, const PJ_named_field_value_t*, std::size_t, PJ_error_t*) noexcept { +bool parserAppendRecord(void*, int64_t, const PJ_named_field_value_t*, uint64_t, PJ_error_t*) noexcept { return true; } -bool parserAppendBoundRecord(void* ctx, int64_t, const PJ_bound_field_value_t*, std::size_t, PJ_error_t*) noexcept { +bool parserAppendBoundRecord(void* ctx, int64_t, const PJ_bound_field_value_t*, uint64_t, PJ_error_t*) noexcept { static_cast(ctx)->called = true; return true; } diff --git a/pj_datastore/src/plugin_data_host.cpp b/pj_datastore/src/plugin_data_host.cpp index 8aa5f7c..6afb18f 100644 --- a/pj_datastore/src/plugin_data_host.cpp +++ b/pj_datastore/src/plugin_data_host.cpp @@ -1007,7 +1007,7 @@ bool sourceEnsureField( } bool sourceAppendRecord( - void* ctx, TopicHandle topic, int64_t timestamp, const PJ_named_field_value_t* fields, std::size_t field_count, + void* ctx, TopicHandle topic, int64_t timestamp, const PJ_named_field_value_t* fields, uint64_t field_count, PJ_error_t* out_error) noexcept { return guardHostCallback(out_error, [&] { auto* impl = static_cast(ctx); @@ -1020,7 +1020,7 @@ bool sourceAppendRecord( } bool sourceAppendBoundRecord( - void* ctx, TopicHandle topic, int64_t timestamp, const PJ_bound_field_value_t* fields, std::size_t field_count, + void* ctx, TopicHandle topic, int64_t timestamp, const PJ_bound_field_value_t* fields, uint64_t field_count, PJ_error_t* out_error) noexcept { return guardHostCallback(out_error, [&] { auto* impl = static_cast(ctx); @@ -1064,7 +1064,7 @@ bool parserEnsureField( } bool parserAppendRecord( - void* ctx, int64_t timestamp, const PJ_named_field_value_t* fields, std::size_t field_count, + void* ctx, int64_t timestamp, const PJ_named_field_value_t* fields, uint64_t field_count, PJ_error_t* out_error) noexcept { return guardHostCallback(out_error, [&] { auto* impl = static_cast(ctx); @@ -1077,7 +1077,7 @@ bool parserAppendRecord( } bool parserAppendBoundRecord( - void* ctx, int64_t timestamp, const PJ_bound_field_value_t* fields, std::size_t field_count, + void* ctx, int64_t timestamp, const PJ_bound_field_value_t* fields, uint64_t field_count, PJ_error_t* out_error) noexcept { return guardHostCallback(out_error, [&] { auto* impl = static_cast(ctx); @@ -1143,7 +1143,7 @@ bool toolboxEnsureField( } bool toolboxAppendRecord( - void* ctx, TopicHandle topic, int64_t timestamp, const PJ_named_field_value_t* fields, std::size_t field_count, + void* ctx, TopicHandle topic, int64_t timestamp, const PJ_named_field_value_t* fields, uint64_t field_count, PJ_error_t* out_error) noexcept { return guardHostCallback(out_error, [&] { auto* impl = static_cast(ctx); @@ -1156,7 +1156,7 @@ bool toolboxAppendRecord( } bool toolboxAppendBoundRecord( - void* ctx, TopicHandle topic, int64_t timestamp, const PJ_bound_field_value_t* fields, std::size_t field_count, + void* ctx, TopicHandle topic, int64_t timestamp, const PJ_bound_field_value_t* fields, uint64_t field_count, PJ_error_t* out_error) noexcept { return guardHostCallback(out_error, [&] { auto* impl = static_cast(ctx); @@ -1250,7 +1250,7 @@ bool toolboxRegisterObjectTopic( } bool toolboxPushOwnedObject( - void* ctx, PJ_object_topic_handle_t topic, int64_t timestamp_ns, const uint8_t* data, std::size_t size, + void* ctx, PJ_object_topic_handle_t topic, int64_t timestamp_ns, const uint8_t* data, uint64_t size, PJ_error_t* out_error) noexcept { auto* impl = static_cast(ctx); try { @@ -1302,7 +1302,7 @@ class PluginFetchCtx { return {}; } const uint8_t* data = nullptr; - std::size_t size = 0; + uint64_t size = 0; // matches PJ_lazy_fetch_fn_t out_size (uint64_t*) if (!fetch_fn_(ctx_, &data, &size) || data == nullptr) { return {}; } @@ -1349,7 +1349,7 @@ bool sourceObjectRegisterTopic( } bool sourceObjectPushOwned( - void* ctx, PJ_object_topic_handle_t topic, int64_t timestamp_ns, const uint8_t* data, std::size_t size, + void* ctx, PJ_object_topic_handle_t topic, int64_t timestamp_ns, const uint8_t* data, uint64_t size, PJ_error_t* out_error) noexcept { auto* impl = static_cast(ctx); try { @@ -1417,7 +1417,7 @@ bool sourceObjectPushLazy( } void sourceObjectSetRetentionBudget( - void* ctx, PJ_object_topic_handle_t topic, int64_t time_window_ns, std::size_t max_memory_bytes) noexcept { + void* ctx, PJ_object_topic_handle_t topic, int64_t time_window_ns, uint64_t max_memory_bytes) noexcept { auto* impl = static_cast(ctx); try { RetentionBudget budget{}; @@ -1455,7 +1455,7 @@ PJ_object_topic_handle_t toolboxObjectLookupTopic(void* ctx, PJ_string_view_t to } bool toolboxObjectListTopics( - void* ctx, PJ_object_topic_handle_t* out_buffer, std::size_t buffer_capacity, std::size_t* out_count, + void* ctx, PJ_object_topic_handle_t* out_buffer, uint64_t buffer_capacity, uint64_t* out_count, PJ_error_t* out_error) noexcept { auto* impl = static_cast(ctx); if (out_count == nullptr) { @@ -1466,7 +1466,9 @@ bool toolboxObjectListTopics( const auto ids = impl->store.listTopics(); *out_count = ids.size(); if (out_buffer != nullptr) { - const std::size_t n = std::min(buffer_capacity, ids.size()); + // buffer_capacity is uint64_t (ABI); ids.size() is size_t. Compare in + // uint64_t, then index with size_t (n <= ids.size(), so it fits). + const std::size_t n = static_cast(std::min(buffer_capacity, ids.size())); for (std::size_t i = 0; i < n; ++i) { out_buffer[i] = PJ_object_topic_handle_t{ids[i].id}; } @@ -1529,7 +1531,7 @@ bool toolboxObjectReadLatestAt( } } -void toolboxObjectGetBytes(PJ_object_bytes_handle_t handle, const uint8_t** out_data, std::size_t* out_size) noexcept { +void toolboxObjectGetBytes(PJ_object_bytes_handle_t handle, const uint8_t** out_data, uint64_t* out_size) noexcept { if (out_data != nullptr) { *out_data = nullptr; } @@ -1558,7 +1560,7 @@ void toolboxObjectReleaseBytes(PJ_object_bytes_handle_t handle) noexcept { delete reinterpret_cast(handle); } -std::size_t toolboxObjectEntryCount(void* ctx, PJ_object_topic_handle_t topic) noexcept { +uint64_t toolboxObjectEntryCount(void* ctx, PJ_object_topic_handle_t topic) noexcept { auto* impl = static_cast(ctx); try { return impl->store.entryCount(ObjectTopicId{topic.id}); @@ -1592,7 +1594,7 @@ bool toolboxObjectTimeRange( // --------------------------------------------------------------------------- bool parserObjectPushOwned( - void* ctx, int64_t timestamp_ns, const uint8_t* data, std::size_t size, PJ_error_t* out_error) noexcept { + void* ctx, int64_t timestamp_ns, const uint8_t* data, uint64_t size, PJ_error_t* out_error) noexcept { auto* impl = static_cast(ctx); try { std::vector bytes; diff --git a/pj_datastore/tests/plugin_data_host_object_test.cpp b/pj_datastore/tests/plugin_data_host_object_test.cpp index c23f324..e0292bb 100644 --- a/pj_datastore/tests/plugin_data_host_object_test.cpp +++ b/pj_datastore/tests/plugin_data_host_object_test.cpp @@ -133,7 +133,7 @@ TEST(PluginDataHostObjectTest, PushLazyDestroyCallbackRunsExactlyOnceOnEviction) }; auto* ctx = new Ctx(); - auto fetch_fn = [](void* c, const uint8_t** out_data, size_t* out_size) noexcept -> bool { + auto fetch_fn = [](void* c, const uint8_t** out_data, uint64_t* out_size) noexcept -> bool { auto* self = static_cast(c); self->last_bytes = self->payload; *out_data = self->last_bytes.data(); diff --git a/pj_plugins/include/pj_plugins/testing/toolbox_test_store.hpp b/pj_plugins/include/pj_plugins/testing/toolbox_test_store.hpp index 85c7f78..67d59a1 100644 --- a/pj_plugins/include/pj_plugins/testing/toolbox_test_store.hpp +++ b/pj_plugins/include/pj_plugins/testing/toolbox_test_store.hpp @@ -444,7 +444,7 @@ class ToolboxTestStore { } static bool trampolineAppendRecord( - void* ctx, PJ_topic_handle_t, int64_t timestamp, const PJ_named_field_value_t* fields, size_t field_count, + void* ctx, PJ_topic_handle_t, int64_t timestamp, const PJ_named_field_value_t* fields, uint64_t field_count, PJ_error_t*) noexcept { auto* self = static_cast(ctx); RecordedRow row; @@ -464,7 +464,7 @@ class ToolboxTestStore { } static bool trampolineAppendBoundRecord( - void*, PJ_topic_handle_t, int64_t, const PJ_bound_field_value_t*, size_t, PJ_error_t*) noexcept { + void*, PJ_topic_handle_t, int64_t, const PJ_bound_field_value_t*, uint64_t, PJ_error_t*) noexcept { // Bound writes are currently not captured — toolboxes that need them // can extend this later. Returning true keeps the write path happy. return true; diff --git a/pj_plugins/tests/data_source_library_test.cpp b/pj_plugins/tests/data_source_library_test.cpp index e13995d..667fa69 100644 --- a/pj_plugins/tests/data_source_library_test.cpp +++ b/pj_plugins/tests/data_source_library_test.cpp @@ -34,11 +34,11 @@ bool fwsEnsureField( *out = PJ_field_handle_t{topic, 1}; return true; } -bool fwsAppendRecord(void*, PJ_topic_handle_t, int64_t, const PJ_named_field_value_t*, size_t, PJ_error_t*) noexcept { +bool fwsAppendRecord(void*, PJ_topic_handle_t, int64_t, const PJ_named_field_value_t*, uint64_t, PJ_error_t*) noexcept { return true; } bool fwsAppendBoundRecord( - void*, PJ_topic_handle_t, int64_t, const PJ_bound_field_value_t*, size_t, PJ_error_t*) noexcept { + void*, PJ_topic_handle_t, int64_t, const PJ_bound_field_value_t*, uint64_t, PJ_error_t*) noexcept { return true; } bool fwsAppendArrowStream( diff --git a/pj_plugins/tests/file_source_integration_test.cpp b/pj_plugins/tests/file_source_integration_test.cpp index 2ecc5ca..5064a76 100644 --- a/pj_plugins/tests/file_source_integration_test.cpp +++ b/pj_plugins/tests/file_source_integration_test.cpp @@ -63,7 +63,7 @@ bool whEnsureField( return true; } bool whAppendRecord( - void* ctx, PJ_topic_handle_t, int64_t, const PJ_named_field_value_t*, size_t, PJ_error_t* err) noexcept { + void* ctx, PJ_topic_handle_t, int64_t, const PJ_named_field_value_t*, uint64_t, PJ_error_t* err) noexcept { auto* s = static_cast(ctx); if (s->fail_next_append) { s->last_error = "mock append failure"; @@ -73,7 +73,7 @@ bool whAppendRecord( return true; } bool whAppendBoundRecord( - void*, PJ_topic_handle_t, int64_t, const PJ_bound_field_value_t*, size_t, PJ_error_t*) noexcept { + void*, PJ_topic_handle_t, int64_t, const PJ_bound_field_value_t*, uint64_t, PJ_error_t*) noexcept { return true; } bool whAppendArrowStream( diff --git a/pj_plugins/tests/toolbox_plugin_test.cpp b/pj_plugins/tests/toolbox_plugin_test.cpp index 53960de..d3b7142 100644 --- a/pj_plugins/tests/toolbox_plugin_test.cpp +++ b/pj_plugins/tests/toolbox_plugin_test.cpp @@ -47,13 +47,13 @@ bool tbEnsureField( return true; } bool tbAppendRecord( - void* ctx, PJ_topic_handle_t, int64_t, const PJ_named_field_value_t*, size_t, PJ_error_t*) noexcept { + void* ctx, PJ_topic_handle_t, int64_t, const PJ_named_field_value_t*, uint64_t, PJ_error_t*) noexcept { auto* s = static_cast(ctx); ++s->append_record_calls; return true; } bool tbAppendBoundRecord( - void*, PJ_topic_handle_t, int64_t, const PJ_bound_field_value_t*, size_t, PJ_error_t*) noexcept { + void*, PJ_topic_handle_t, int64_t, const PJ_bound_field_value_t*, uint64_t, PJ_error_t*) noexcept { return true; } bool tbAppendArrowStream(