From d4538df01426c4d6dda3229b643d2478b50381eb Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Fri, 14 Aug 2026 11:51:11 +0200 Subject: [PATCH 1/4] Add compatibility with newer protobuf --- 3rdparty/stout/include/stout/protobuf.hpp | 34 +++++++++++------------ src/common/protobuf_utils.cpp | 6 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/3rdparty/stout/include/stout/protobuf.hpp b/3rdparty/stout/include/stout/protobuf.hpp index 9a82a304d47..e19f589575c 100644 --- a/3rdparty/stout/include/stout/protobuf.hpp +++ b/3rdparty/stout/include/stout/protobuf.hpp @@ -220,7 +220,7 @@ Try deserialize(const std::string& value) value.data(), static_cast(value.size())); if (!t.ParseFromZeroCopyStream(&stream)) { - return Error("Failed to deserialize " + t.GetDescriptor()->full_name()); + return Error("Failed to deserialize " + std::string(t.GetDescriptor()->full_name())); } return t; } @@ -233,7 +233,7 @@ Try serialize(const T& t) std::string value; if (!t.SerializeToString(&value)) { - return Error("Failed to serialize " + t.GetDescriptor()->full_name()); + return Error("Failed to serialize " + std::string(t.GetDescriptor()->full_name())); } return value; } @@ -483,7 +483,7 @@ struct Parser : boost::static_visitor> break; default: return Error("Not expecting a JSON object for field '" + - field->name() + "'"); + std::string(field->name()) + "'"); } return Nothing(); } @@ -502,7 +502,7 @@ struct Parser : boost::static_visitor> Try decode = base64::decode(string.value); if (decode.isError()) { return Error("Failed to base64 decode bytes field" - " '" + field->name() + "': " + decode.error()); + " '" + std::string(field->name()) + "': " + decode.error()); } if (field->is_repeated()) { @@ -552,7 +552,7 @@ struct Parser : boost::static_visitor> if (number.isError()) { return Error( "Failed to parse '" + string.value + "' as a JSON number " - "for field '" + field->name() + "': " + number.error()); + "for field '" + std::string(field->name()) + "': " + number.error()); } return operator()(number.get()); @@ -572,7 +572,7 @@ struct Parser : boost::static_visitor> if (number.isError()) { return Error( "Failed to parse '" + string.value + "' as a JSON number " - "for field '" + field->name() + "': " + number.error()); + "for field '" + std::string(field->name()) + "': " + number.error()); } return operator()(number.get()); @@ -582,14 +582,14 @@ struct Parser : boost::static_visitor> if (boolean.isError()) { return Error( "Failed to parse '" + string.value + "' as a JSON boolean " - "for field '" + field->name() + "': " + boolean.error()); + "for field '" + std::string(field->name()) + "': " + boolean.error()); } return operator()(boolean.get()); } default: return Error("Not expecting a JSON string for field '" + - field->name() + "'"); + std::string(field->name()) + "'"); } return Nothing(); } @@ -647,7 +647,7 @@ struct Parser : boost::static_visitor> break; default: return Error("Not expecting a JSON number for field '" + - field->name() + "'"); + std::string(field->name()) + "'"); } return Nothing(); } @@ -656,7 +656,7 @@ struct Parser : boost::static_visitor> { if (!field->is_repeated()) { return Error("Not expecting a JSON array for field '" + - field->name() + "'"); + std::string(field->name()) + "'"); } foreach (const JSON::Value& value, array.values) { @@ -683,7 +683,7 @@ struct Parser : boost::static_visitor> break; default: return Error("Not expecting a JSON boolean for field '" + - field->name() + "'"); + std::string(field->name()) + "'"); } return Nothing(); } @@ -864,7 +864,7 @@ inline void json(ObjectWriter* writer, const Protobuf& protobuf) foreach (const FieldDescriptor* field, fields) { if (field->is_repeated() && !field->is_map()) { writer->field( - field->name(), + std::string(field->name()), [&field, &reflection, &message](JSON::ArrayWriter* writer) { int fieldSize = reflection->FieldSize(message, field); for (int i = 0; i < fieldSize; ++i) { @@ -966,11 +966,11 @@ inline void json(ObjectWriter* writer, const Protobuf& protobuf) }; if (!field->is_repeated()) { // Singular field. - writeField(field->name(), reflection, message, field); + writeField(std::string(field->name()), reflection, message, field); } else { // Map field. CHECK(field->is_map()); writer->field( - field->name(), + std::string(field->name()), [&field, &reflection, &message, &writeField]( JSON::ObjectWriter* writer) { foreach ( @@ -1176,7 +1176,7 @@ inline Object protobuf(const google::protobuf::Message& message) map.values[name] = value_for_field(entry, value_field); } - object.values[field->name()] = map; + object.values[std::string(field->name())] = map; } else if (field->is_repeated()) { JSON::Array array; int fieldSize = reflection->FieldSize(message, field); @@ -1243,9 +1243,9 @@ inline Object protobuf(const google::protobuf::Message& message) stringify(field->type())); } } - object.values[field->name()] = array; + object.values[std::string(field->name())] = array; } else { - object.values[field->name()] = value_for_field(message, field); + object.values[std::string(field->name())] = value_for_field(message, field); } } diff --git a/src/common/protobuf_utils.cpp b/src/common/protobuf_utils.cpp index 723d85a8656..1e4848cd1cb 100644 --- a/src/common/protobuf_utils.cpp +++ b/src/common/protobuf_utils.cpp @@ -123,11 +123,11 @@ Option UnionValidator::validate( reflection->HasField(message, fieldDescriptor)) { const auto* descr = typeDescriptor_->FindValueByNumber(messageTypeNumber); return Error( - "Protobuf union `" + message.GetDescriptor()->full_name() + + "Protobuf union `" + string(message.GetDescriptor()->full_name()) + "` with `Type == " + - (descr == nullptr ? string("") : descr->name()) + + (descr == nullptr ? string("") : string(descr->name())) + "` should not have the field `" + - fieldDescriptor->name() + "` set."); + string(fieldDescriptor->name()) + "` set."); } } return None(); From 56edcb7adfbe1a6c34f7539bc5ea8a224dd30145 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:23:07 +0200 Subject: [PATCH 2/4] More Protobuf > 22 issue fixed --- .../libprocess/include/process/protobuf.hpp | 31 ++++++++++--------- 3rdparty/stout/include/stout/json.hpp | 2 ++ 3rdparty/stout/include/stout/jsonify.hpp | 5 +-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/3rdparty/libprocess/include/process/protobuf.hpp b/3rdparty/libprocess/include/process/protobuf.hpp index 87c40cdacd8..3fcd10b513e 100644 --- a/3rdparty/libprocess/include/process/protobuf.hpp +++ b/3rdparty/libprocess/include/process/protobuf.hpp @@ -40,7 +40,7 @@ inline void post(const process::UPID& to, { std::string data; if (message.SerializeToString(&data)) { - post(to, message.GetTypeName(), data.data(), data.size()); + post(to, std::string(message.GetTypeName()), data.data(), data.size()); } else { LOG(ERROR) << "Failed to post '" << message.GetTypeName() << "' to " << to << ": Failed to serialize"; @@ -54,7 +54,7 @@ inline void post(const process::UPID& from, { std::string data; if (message.SerializeToString(&data)) { - post(from, to, message.GetTypeName(), data.data(), data.size()); + post(from, to, std::string(message.GetTypeName()), data.data(), data.size()); } else { LOG(ERROR) << "Failed to post '" << message.GetTypeName() << "' to " << to << ": Failed to serialize"; @@ -128,7 +128,8 @@ class ProtobufProcess : public process::Process { std::string data; if (message.SerializeToString(&data)) { - process::Process::send(to, message.GetTypeName(), std::move(data)); + process::Process::send( + to, std::string(message.GetTypeName()), std::move(data)); } else { LOG(ERROR) << "Failed to send '" << message.GetTypeName() << "' to " << to << ": Failed to serialize"; @@ -149,7 +150,7 @@ class ProtobufProcess : public process::Process { google::protobuf::Message* m = new M(); T* t = static_cast(this); - protobufHandlers[m->GetTypeName()] = + protobufHandlers[std::string(m->GetTypeName())] = lambda::bind(&handlerM, t, method, lambda::_1, lambda::_2); @@ -161,7 +162,7 @@ class ProtobufProcess : public process::Process { google::protobuf::Message* m = new M(); T* t = static_cast(this); - protobufHandlers[m->GetTypeName()] = + protobufHandlers[std::string(m->GetTypeName())] = lambda::bind(&handlerMutM, t, method, lambda::_1, lambda::_2); @@ -176,7 +177,7 @@ class ProtobufProcess : public process::Process { google::protobuf::Message* m = new M(); T* t = static_cast(this); - protobufHandlers[m->GetTypeName()] = + protobufHandlers[std::string(m->GetTypeName())] = lambda::bind(&handler0, t, method, lambda::_1, lambda::_2); @@ -191,7 +192,7 @@ class ProtobufProcess : public process::Process { google::protobuf::Message* m = new M(); T* t = static_cast(this); - protobufHandlers[m->GetTypeName()] = + protobufHandlers[std::string(m->GetTypeName())] = lambda::bind(static_cast { google::protobuf::Message* m = new M(); T* t = static_cast(this); - protobufHandlers[m->GetTypeName()] = + protobufHandlers[std::string(m->GetTypeName())] = lambda::bind(&_handlerM, t, method, lambda::_1, lambda::_2); @@ -221,7 +222,7 @@ class ProtobufProcess : public process::Process { google::protobuf::Message* m = new M(); T* t = static_cast(this); - protobufHandlers[m->GetTypeName()] = + protobufHandlers[std::string(m->GetTypeName())] = lambda::bind(&_handlerMutM, t, method, lambda::_1, lambda::_2); @@ -233,7 +234,7 @@ class ProtobufProcess : public process::Process { google::protobuf::Message* m = new M(); T* t = static_cast(this); - protobufHandlers[m->GetTypeName()] = + protobufHandlers[std::string(m->GetTypeName())] = lambda::bind(&_handler0, t, method, lambda::_1, lambda::_2); @@ -248,7 +249,7 @@ class ProtobufProcess : public process::Process { google::protobuf::Message* m = new M(); T* t = static_cast(this); - protobufHandlers[m->GetTypeName()] = + protobufHandlers[std::string(m->GetTypeName())] = lambda::bind(static_cast const std::string& data) { google::protobuf::Arena arena; - M* m = CHECK_NOTNULL(google::protobuf::Arena::CreateMessage(&arena)); + M* m = CHECK_NOTNULL(google::protobuf::Arena::Create(&arena)); if (m->ParseFromString(data)) { (t->*method)(sender, *m); @@ -318,7 +319,7 @@ class ProtobufProcess : public process::Process MessageProperty... p) { google::protobuf::Arena arena; - M* m = CHECK_NOTNULL(google::protobuf::Arena::CreateMessage(&arena)); + M* m = CHECK_NOTNULL(google::protobuf::Arena::Create(&arena)); if (m->ParseFromString(data)) { (t->*method)(sender, google::protobuf::convert((m->*p)())...); @@ -337,7 +338,7 @@ class ProtobufProcess : public process::Process const std::string& data) { google::protobuf::Arena arena; - M* m = CHECK_NOTNULL(google::protobuf::Arena::CreateMessage(&arena)); + M* m = CHECK_NOTNULL(google::protobuf::Arena::Create(&arena)); if (m->ParseFromString(data)) { (t->*method)(*m); @@ -383,7 +384,7 @@ class ProtobufProcess : public process::Process MessageProperty... p) { google::protobuf::Arena arena; - M* m = CHECK_NOTNULL(google::protobuf::Arena::CreateMessage(&arena)); + M* m = CHECK_NOTNULL(google::protobuf::Arena::Create(&arena)); if (m->ParseFromString(data)) { (t->*method)(google::protobuf::convert((m->*p)())...); diff --git a/3rdparty/stout/include/stout/json.hpp b/3rdparty/stout/include/stout/json.hpp index 17bd02e5b22..b6fcc788366 100644 --- a/3rdparty/stout/include/stout/json.hpp +++ b/3rdparty/stout/include/stout/json.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -81,6 +82,7 @@ struct String String() {} String(const char* _value) : value(_value) {} String(const std::string& _value) : value(_value) {} + String(std::string_view _value) : value(_value) {} std::string value; }; diff --git a/3rdparty/stout/include/stout/jsonify.hpp b/3rdparty/stout/include/stout/jsonify.hpp index e18da8fb486..c56f27404ce 100644 --- a/3rdparty/stout/include/stout/jsonify.hpp +++ b/3rdparty/stout/include/stout/jsonify.hpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -344,7 +345,7 @@ class ObjectWriter ObjectWriter& operator=(ObjectWriter&&) = delete; template - void field(const std::string& key, const T& value) + void field(std::string_view key, const T& value) { // This check will fail we enable write validation in rapidjson; // we'll need to figure out a way to surface the error. @@ -352,7 +353,7 @@ class ObjectWriter // TODO(bmahler): The 1.1.0 release of rapidjson did not // yet have the std::string overload for `Key`, avoid calling // `c_str()` and `size()` when we upgrade beyond 1.1.0. - CHECK(writer_->Key(key.c_str(), key.size())); + CHECK(writer_->Key(key.data(), key.size())); jsonify(value).write(writer_); } From daac3fa9caa8781903b577545ed169e678935e73 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Fri, 21 Aug 2026 11:54:03 +0200 Subject: [PATCH 3/4] More Protobuf > 22 changes --- 3rdparty/stout/include/stout/jsonify.hpp | 39 ++++++++++++++++++++++-- src/common/http.cpp | 16 ++++++---- src/common/protobuf_utils.cpp | 3 +- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/3rdparty/stout/include/stout/jsonify.hpp b/3rdparty/stout/include/stout/jsonify.hpp index c56f27404ce..452179845db 100644 --- a/3rdparty/stout/include/stout/jsonify.hpp +++ b/3rdparty/stout/include/stout/jsonify.hpp @@ -286,6 +286,15 @@ class StringWriter CHECK(writer_->String(value)); } + void set(std::string_view value) + { + empty_ = false; + + // This check will fail if we enable write validation in rapidjson; + // we'll need to figure out a way to surface the error. + CHECK(writer_->String(value.data(), value.size())); + } + private: rapidjson::Writer* writer_; bool empty_; @@ -439,6 +448,26 @@ inline void json(StringWriter* writer, const std::string& value) writer->set(value); } + +// For the `absl::string_view` the protobuf descriptor accessors return since +// protobuf 22. Without this, such a value is written as an array of +// one-character strings: `std::string`'s converting constructor from +// `string_view` is explicit, so the overload above is not viable, and a +// `string_view` is iterable, so the one below is. +// +// Constrained to an exact `std::string_view` on purpose. A plain +// `json(StringWriter*, std::string_view)` overload would instead make +// `const char*` ambiguous against the overload above, both being +// user-defined conversions. +template < + typename T, + typename std::enable_if< + std::is_same::value, int>::type = 0> +void json(StringWriter* writer, T value) +{ + writer->set(value); +} + namespace internal { // TODO(mpark): Pull this out to something like . @@ -500,12 +529,18 @@ struct HasMappedType // `json` function for iterables (e.g., std::vector). // This function is only enabled if `Iterable` is iterable, is not a // `const char (&)[N]` (in order to avoid ambiguity with the string literal -// overload), and does not have a member typedef `mapped_type` (we take the -// existence of `mapped_type` as the indication of an associative container). +// overload), is not convertible to `std::string_view` (strings are iterable +// too, and would otherwise be written as an array of one-character strings +// -- the string overload above only wins for `std::string` because a +// non-template beats a template, which does not help a type that reaches it +// by conversion), and does not have a member typedef `mapped_type` (we take +// the existence of `mapped_type` as the indication of an associative +// container). template < typename Iterable, typename std::enable_if< internal::IsSequence::value && + !std::is_convertible::value && !(std::is_array::value && std::rank::value == 1 && std::is_same< diff --git a/src/common/http.cpp b/src/common/http.cpp index 093d837c1d1..67e6ba24d68 100644 --- a/src/common/http.cpp +++ b/src/common/http.cpp @@ -224,7 +224,7 @@ void json(JSON::ObjectWriter* writer, const asV1Protobuf& protobuf) foreach (const FieldDescriptor* field, fields) { if (field->is_repeated() && !field->is_map()) { writer->field( - lowerSlaveToAgent(field->name()), + lowerSlaveToAgent(string(field->name())), [&field, &reflection, &message](JSON::ArrayWriter* writer) { int fieldSize = reflection->FieldSize(message, field); for (int i = 0; i < fieldSize; ++i) { @@ -264,9 +264,9 @@ void json(JSON::ObjectWriter* writer, const asV1Protobuf& protobuf) break; case FieldDescriptor::CPPTYPE_ENUM: writer->element( - upperSlaveToAgent( + upperSlaveToAgent(string( reflection->GetRepeatedEnum(message, field, i) - ->name())); + ->name()))); break; case FieldDescriptor::CPPTYPE_STRING: const std::string& s = reflection->GetRepeatedStringReference( @@ -316,7 +316,8 @@ void json(JSON::ObjectWriter* writer, const asV1Protobuf& protobuf) case FieldDescriptor::CPPTYPE_ENUM: writer->field( fieldName, - upperSlaveToAgent(reflection->GetEnum(message, field)->name())); + upperSlaveToAgent( + string(reflection->GetEnum(message, field)->name()))); break; case FieldDescriptor::CPPTYPE_STRING: const std::string& s = @@ -332,11 +333,14 @@ void json(JSON::ObjectWriter* writer, const asV1Protobuf& protobuf) if (!field->is_repeated()) { // Singular field. writeField( - lowerSlaveToAgent(field->name()), reflection, message, field); + lowerSlaveToAgent(string(field->name())), + reflection, + message, + field); } else { // Map field. CHECK(field->is_map()); writer->field( - lowerSlaveToAgent(field->name()), + lowerSlaveToAgent(string(field->name())), [&field, &reflection, &message, &writeField]( JSON::ObjectWriter* writer) { foreach ( diff --git a/src/common/protobuf_utils.cpp b/src/common/protobuf_utils.cpp index 1e4848cd1cb..78241d8669c 100644 --- a/src/common/protobuf_utils.cpp +++ b/src/common/protobuf_utils.cpp @@ -102,7 +102,8 @@ UnionValidator::UnionValidator(const google::protobuf::Descriptor* descriptor) } const auto* fieldDescriptor = - descriptor->FindFieldByName(strings::lower(typeValueDescriptor->name())); + descriptor->FindFieldByName( + strings::lower(string(typeValueDescriptor->name()))); CHECK_NOTNULL(fieldDescriptor); unionFieldDescriptors_.emplace_back( From a69e7359bc0725f11796cce17379fb1c477c072e Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Fri, 21 Aug 2026 15:47:51 +0200 Subject: [PATCH 4/4] More protobuf >22 changes --- src/master/metrics.cpp | 11 ++++++----- src/python/native_common/common.hpp | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/master/metrics.cpp b/src/master/metrics.cpp index 79734851d69..7649286042f 100644 --- a/src/master/metrics.cpp +++ b/src/master/metrics.cpp @@ -400,7 +400,7 @@ Metrics::Metrics(const Master& master) } std::string prefix = - "master/operations/" + strings::lower(descriptor->name()) + "/"; + "master/operations/" + strings::lower(string(descriptor->name())) + "/"; operation_type_states.emplace(type, prefix); } @@ -750,7 +750,7 @@ FrameworkMetrics::FrameworkMetrics( } Counter counter = Counter( - metricPrefix + "calls/" + strings::lower(descriptor->name())); + metricPrefix + "calls/" + strings::lower(string(descriptor->name()))); call_types.put(type, counter); addMetric(counter); @@ -772,7 +772,7 @@ FrameworkMetrics::FrameworkMetrics( } Counter counter = Counter( - metricPrefix + "events/" + strings::lower(descriptor->name())); + metricPrefix + "events/" + strings::lower(string(descriptor->name()))); event_types.put(type, counter); addMetric(counter); @@ -788,7 +788,7 @@ FrameworkMetrics::FrameworkMetrics( if (protobuf::isTerminalState(state)) { Counter counter = Counter( metricPrefix + "tasks/terminal/" + - strings::lower(descriptor->name())); + strings::lower(string(descriptor->name()))); terminal_task_states.put(state, counter); addMetric(counter); @@ -818,7 +818,8 @@ FrameworkMetrics::FrameworkMetrics( } Counter counter = Counter( - metricPrefix + "operations/" + strings::lower(descriptor->name())); + metricPrefix + "operations/" + + strings::lower(string(descriptor->name()))); operation_types.put(type, counter); addMetric(counter); diff --git a/src/python/native_common/common.hpp b/src/python/native_common/common.hpp index fadec2778bf..26a369b488d 100644 --- a/src/python/native_common/common.hpp +++ b/src/python/native_common/common.hpp @@ -157,7 +157,7 @@ construct(PyObject* obj) PyErr_Format( PyExc_TypeError, "Failed to construct %s from a Python object", - result->GetDescriptor()->full_name().c_str()); + std::string(result->GetDescriptor()->full_name()).c_str()); return nullptr; }