-
Notifications
You must be signed in to change notification settings - Fork 0
Generated Cpp API
Every generated message is templated on a runtime configuration:
template <class Config = ::protocyte::DefaultConfig>
struct Message;Generated messages are move-only. Ordinary C++ copying is deleted because it cannot report allocation failure.
Construction binds a non-owning context and does not allocate:
protocyte::DefaultConfig::Context ctx {
protocyte::hosted_allocator(),
protocyte::Limits {},
};
auto message = demo::Sample<>::create(ctx);The context and allocator state must outlive the message.
Primitive scalar setters return void. Operations that can fail return [[nodiscard]] values:
-
protocyte::Status; -
protocyte::Result<T>; -
protocyte::Result<T&>for reference-valued operations.
Check a result before reading its value:
const auto parsed = demo::Sample<>::parse(ctx, bytes);
if (!parsed) {
const auto &error = parsed.error();
// error.code, error.offset, error.field_number
}
const auto &message = *parsed;Access .error() only after a false status check.
Generated messages expose:
-
create(ctx); -
parse(ctx, reader)andparse(ctx, input_bytes); -
parse(reader, output); -
merge_from(reader); -
serialize(writer)andserialize(output_bytes); -
encoded_size(); -
copy_from(source)andcopy_from(source, staging_message); -
clone()andclone(output); - protobuf-derived field accessors.
The exact accessor set depends on field kind and presence:
- immutable accessors such as
value(); -
set_*()for scalar values; -
has_*()for fields with presence; -
clear_*()where clearing is meaningful; -
mutable_*()for mutable strings, bytes, messages, and containers; -
ensure_*()for fallible nested-message creation.
Repeated fields expose their configured vector surface. Maps expose their configured map surface. Oneofs expose a case discriminator and only commit case changes after the incoming value is ready.
The current setter and mutation failure model is:
| Field or operation | Generated result | Why it can fail |
|---|---|---|
| Numeric and boolean scalar setter | void |
Direct assignment |
| Enum setter | protocyte::Status |
Closed-enum validation |
| String or bytes setter | protocyte::Status |
Allocation, configured limits, or fixed-size validation |
Nested-message ensure_*()
|
protocyte::Result<T&> |
Nested storage allocation |
| Repeated and map mutation | Container-specific Status or Result<T&>
|
Allocation, capacity, or configured limits |
clear_*() |
void |
Releases or resets existing state |
Fallible return types are [[nodiscard]]; check them even when the selected
hosted allocator normally succeeds.
parse(ctx, input) accepts protocyte::Span<const protocyte::u8>:
const auto parsed = demo::Sample<>::parse(ctx, encoded);Compatible lvalue ranges such as arrays, std::array, std::vector, and std::span convert to the dynamic span automatically.
The overload creates a SliceReader and delegates to the reader-based parser.
Avoid a complete outer-message temporary:
demo::Sample<> output {ctx};
protocyte::SliceReader reader {encoded.data(), encoded.size()};
const auto status = demo::Sample<>::parse(reader, output);
if (!status) {
// output is empty and remains bound to ctx
}On failure, the output is reset to an empty message with its original destination context.
merge_from(reader) follows protobuf merge semantics.
Successfully parsed field occurrences remain committed if a later occurrence fails. The failing occurrence itself does not change visible state:
- singular nested messages commit after the complete occurrence parses;
- oneofs switch cases only after successful parsing;
- repeated fields append only complete elements;
- malformed packed payloads append no decoded prefix;
- maps insert only complete entries.
See Errors, Limits, and Wire Behavior.
Compute the required size:
const auto size = message.encoded_size();
if (!size) {
return handle(size.error());
}Serialize to a mutable contiguous range:
std::vector<protocyte::u8> encoded(*size);
const auto written = message.serialize(encoded);This overload returns the number of bytes written. It preflights the encoded size, so an undersized contiguous buffer returns ErrorCode::size_limit without modifying the buffer.
serialize(writer) is incremental rather than transactional. A custom writer failure can leave bytes from earlier successful calls committed. Stage output when all-or-nothing publication is required.
Generated messages use explicit fallible deep copies:
const auto status = destination.copy_from(source);
const auto cloned = source.clone();Caller-controlled variants avoid an internal full-message temporary:
demo::Sample<> staging {ctx};
const auto copy_status = destination.copy_from(source, staging);
demo::Sample<> output {ctx};
const auto clone_status = source.clone(output);copy_from(source, staging) is transactional for the destination. On success, staging remains valid but moved-from and must not alias either operand.
clone() uses the source context. clone(output) retains the context already bound to output.
Generated immutable string accessors return protocyte::StringView.
By default:
using StringView = protocyte::Span<const char>;Hosted targets can enable std::string_view interoperability:
target_compile_definitions(
demo_proto
PUBLIC PROTOCYTE_ENABLE_STD_STRING_VIEW=1
)The definition changes public signatures, so all translation units in that target graph must use the same value.
Every generated enum has protobuf-like numeric helpers, even when reflection is disabled:
inline constexpr Mode Mode_MIN;
inline constexpr Mode Mode_MAX;
inline constexpr ::protocyte::i32 Mode_ARRAYSIZE;
[[nodiscard]] constexpr bool
Mode_is_valid(::protocyte::i32 value) noexcept;MIN and MAX directly alias the first declared enum members having the
smallest and largest numeric values, regardless of declaration order.
ARRAYSIZE retains protobuf's spelling and means MAX + 1; it is not the
number of declared values. It is omitted when MAX is INT32_MAX.
is_valid() accepts declared numbers only, deduplicating aliases.
Helpers for a nested enum are static members of the declaring message:
using Color = Paint<>::Color;
static_assert(Paint<>::Color_MIN == Color::COLOR_UNSPECIFIED);
static_assert(Paint<>::Color_is_valid(1));Proto2 enums are closed. Their generated field APIs reject undeclared numeric
values according to the documented closed-enum wire behavior. Proto3 enums are
open and preserve undeclared int32 values in their raw field surface, while
is_valid() still reports only declared values. Protocyte does not emit
protobuf's internal open-enum extrema sentinels.
Unknown-field preservation is disabled by default:
struct ForwardCompatibleConfig : protocyte::DefaultConfig {
static constexpr bool preserve_unknown_fields = true;
};Enabled messages expose:
-
unknown_fields(); -
unknown_field_count(); -
unknown_field_bytes(); -
clear_unknown_fields(); -
mutable_unknown_fields().
Unknown occurrences retain encounter order as canonical protobuf bytes. Parsing and reserialization do not promise byte-identical forwarding.
The disabled storage specialization adds no message object footprint.
Reflection tables are emitted only when PROTOCYTE_ENABLE_REFLECTION is nonzero:
target_compile_definitions(
demo_proto
PUBLIC PROTOCYTE_ENABLE_REFLECTION=1
)PUBLIC visibility is required so generated sources and consumers see the same declaration surface.
On Windows, protocyte_add_proto_library(TYPE SHARED) gives reflection data a target-unique import/export macro. Direct generator users that build a DLL must manage visibility themselves.
Each generated message receives an externally linked std::array<protocyte::ReflectionFieldInfo, N> in its package's protocyte_reflection namespace.
Reflection builds also add these enum helpers:
[[nodiscard]] ::protocyte::StringView Mode_name(Mode value) noexcept;
[[nodiscard]] bool Mode_parse(
::protocyte::StringView name,
Mode& value) noexcept;
[[nodiscard]] const ::protocyte::ReflectionEnumInfo*
Mode_descriptor() noexcept;name() returns the first declared name for an aliased number and an empty view
for an unknown value. parse() is case-sensitive, accepts every declared alias,
does not allocate, and leaves its output unchanged on failure. A generated
character-array overload accepts null-terminated names such as string literals
with the same behavior for fallback Span and hosted std::string_view builds.
The descriptor preserves declaration order and reports short and protobuf full
names, deprecation state, and whether the enum is closed.
Unlike protobuf LITE_RUNTIME, a reflection-disabled Protocyte build
intentionally has no generated enum name(), parse(), or descriptor() API
and contains no enum-name tables.
Legal schema declarations that collide with generated helper names or internal template parameter spellings are remapped deterministically. The protobuf-derived type remains usable without emitting invalid C++.
When comments are enabled, a remapped field emits a nearby comment naming its protobuf field and generated accessor stem. For example:
// Protocyte C++ name mapping: protobuf field "class" uses
// accessor stem "class_protocyte" to avoid a C++ collision.Use the generated declaration as the source of truth for collision-safe
spellings. comments=off suppresses these mapping comments together with
schema documentation.
Cross-file collisions that cannot be renamed consistently are rejected. See Plugin Parameters.
Repository · Releases · Issues · Apache License 2.0
Canonical source: docs/wiki/