Project import generated by Copybara.
GitOrigin-RevId: 6e5aa035cd1f6a9333962df5d3ab97a05bd5744e
This commit is contained in:
committed by
Sebastian Schmidt
parent
4a20e9909d
commit
c688862570
@@ -198,6 +198,7 @@ cc_library(
|
||||
":name_util",
|
||||
":options_registry",
|
||||
":proto_util_lite",
|
||||
":type_util",
|
||||
"//mediapipe/framework:calculator_cc_proto",
|
||||
"//mediapipe/framework:packet",
|
||||
"//mediapipe/framework:packet_type",
|
||||
@@ -277,9 +278,12 @@ cc_library(
|
||||
hdrs = ["options_registry.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":field_data_cc_proto",
|
||||
":proto_util_lite",
|
||||
"//mediapipe/framework/deps:registration",
|
||||
"//mediapipe/framework/port:advanced_proto",
|
||||
"//mediapipe/framework/port:logging",
|
||||
"//mediapipe/framework/port:ret_check",
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/synchronization",
|
||||
],
|
||||
@@ -334,6 +338,7 @@ cc_library(
|
||||
hdrs = ["proto_util_lite.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":field_data_cc_proto",
|
||||
"//mediapipe/framework:type_map",
|
||||
"//mediapipe/framework/port:advanced_proto_lite",
|
||||
"//mediapipe/framework/port:integral_types",
|
||||
@@ -518,9 +523,11 @@ cc_library(
|
||||
cc_library(
|
||||
name = "type_util",
|
||||
hdrs = ["type_util.h"],
|
||||
visibility = ["//mediapipe/framework:mediapipe_internal"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//mediapipe/framework:demangle",
|
||||
"//mediapipe/framework:port",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ syntax = "proto2";
|
||||
package mediapipe;
|
||||
|
||||
import "mediapipe/framework/calculator.proto";
|
||||
import "mediapipe/framework/calculator_options.proto";
|
||||
import "mediapipe/framework/deps/proto_descriptor.proto";
|
||||
|
||||
option java_package = "com.google.mediapipe.proto";
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "mediapipe/framework/packet.h"
|
||||
@@ -18,6 +19,7 @@
|
||||
#include "mediapipe/framework/port/status.h"
|
||||
#include "mediapipe/framework/tool/name_util.h"
|
||||
#include "mediapipe/framework/tool/proto_util_lite.h"
|
||||
#include "mediapipe/framework/tool/type_util.h"
|
||||
|
||||
namespace mediapipe {
|
||||
namespace tool {
|
||||
@@ -41,165 +43,39 @@ FieldType AsFieldType(proto_ns::FieldDescriptorProto::Type type) {
|
||||
return static_cast<FieldType>(type);
|
||||
}
|
||||
|
||||
absl::Status WriteValue(const FieldData& value, FieldType field_type,
|
||||
std::string* field_bytes) {
|
||||
StringOutputStream sos(field_bytes);
|
||||
CodedOutputStream out(&sos);
|
||||
switch (field_type) {
|
||||
case WireFormatLite::TYPE_INT32:
|
||||
WireFormatLite::WriteInt32NoTag(value.int32_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_SINT32:
|
||||
WireFormatLite::WriteSInt32NoTag(value.int32_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_INT64:
|
||||
WireFormatLite::WriteInt64NoTag(value.int64_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_SINT64:
|
||||
WireFormatLite::WriteSInt64NoTag(value.int64_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_UINT32:
|
||||
WireFormatLite::WriteUInt32NoTag(value.uint32_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_UINT64:
|
||||
WireFormatLite::WriteUInt64NoTag(value.uint64_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_DOUBLE:
|
||||
WireFormatLite::WriteDoubleNoTag(value.uint64_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_FLOAT:
|
||||
WireFormatLite::WriteFloatNoTag(value.float_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_BOOL:
|
||||
WireFormatLite::WriteBoolNoTag(value.bool_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_ENUM:
|
||||
WireFormatLite::WriteEnumNoTag(value.enum_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_STRING:
|
||||
out.WriteString(value.string_value());
|
||||
break;
|
||||
case WireFormatLite::TYPE_MESSAGE:
|
||||
out.WriteString(value.message_value().value());
|
||||
break;
|
||||
default:
|
||||
return absl::UnimplementedError(
|
||||
absl::StrCat("Cannot write type: ", field_type));
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Serializes a packet value.
|
||||
absl::Status WriteField(const FieldData& packet, const FieldDescriptor* field,
|
||||
std::string* result) {
|
||||
FieldType field_type = AsFieldType(field->type());
|
||||
return WriteValue(packet, field_type, result);
|
||||
}
|
||||
|
||||
template <typename ValueT, FieldType kFieldType>
|
||||
static ValueT ReadValue(absl::string_view field_bytes, absl::Status* status) {
|
||||
ArrayInputStream ais(field_bytes.data(), field_bytes.size());
|
||||
CodedInputStream input(&ais);
|
||||
ValueT result;
|
||||
if (!WireFormatLite::ReadPrimitive<ValueT, kFieldType>(&input, &result)) {
|
||||
status->Update(mediapipe::InvalidArgumentError(absl::StrCat(
|
||||
"Bad serialized value: ", MediaPipeTypeStringOrDemangled<ValueT>(),
|
||||
".")));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
absl::Status ReadValue(absl::string_view field_bytes, FieldType field_type,
|
||||
absl::string_view message_type, FieldData* result) {
|
||||
absl::Status status;
|
||||
result->Clear();
|
||||
switch (field_type) {
|
||||
case WireFormatLite::TYPE_INT32:
|
||||
result->set_int32_value(
|
||||
ReadValue<int32, WireFormatLite::TYPE_INT32>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_SINT32:
|
||||
result->set_int32_value(
|
||||
ReadValue<int32, WireFormatLite::TYPE_SINT32>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_INT64:
|
||||
result->set_int64_value(
|
||||
ReadValue<int64, WireFormatLite::TYPE_INT64>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_SINT64:
|
||||
result->set_int64_value(
|
||||
ReadValue<int64, WireFormatLite::TYPE_SINT64>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_UINT32:
|
||||
result->set_uint32_value(
|
||||
ReadValue<uint32, WireFormatLite::TYPE_UINT32>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_UINT64:
|
||||
result->set_uint64_value(
|
||||
ReadValue<uint32, WireFormatLite::TYPE_UINT32>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_DOUBLE:
|
||||
result->set_double_value(
|
||||
ReadValue<double, WireFormatLite::TYPE_DOUBLE>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_FLOAT:
|
||||
result->set_float_value(
|
||||
ReadValue<float, WireFormatLite::TYPE_FLOAT>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_BOOL:
|
||||
result->set_bool_value(
|
||||
ReadValue<bool, WireFormatLite::TYPE_BOOL>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_ENUM:
|
||||
result->set_enum_value(
|
||||
ReadValue<int32, WireFormatLite::TYPE_ENUM>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_STRING:
|
||||
result->set_string_value(std::string(field_bytes));
|
||||
break;
|
||||
case WireFormatLite::TYPE_MESSAGE:
|
||||
result->mutable_message_value()->set_value(std::string(field_bytes));
|
||||
result->mutable_message_value()->set_type_url(TypeUrl(message_type));
|
||||
break;
|
||||
default:
|
||||
status = absl::UnimplementedError(
|
||||
absl::StrCat("Cannot read type: ", field_type));
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
return ProtoUtilLite::WriteValue(packet, field->type(), result);
|
||||
}
|
||||
|
||||
// Deserializes a packet from a protobuf field.
|
||||
absl::Status ReadField(absl::string_view bytes, const FieldDescriptor* field,
|
||||
absl::Status ReadField(absl::string_view bytes, const FieldDescriptor& field,
|
||||
FieldData* result) {
|
||||
RET_CHECK_NE(field, nullptr);
|
||||
FieldType field_type = AsFieldType(field->type());
|
||||
std::string message_type = (field_type == WireFormatLite::TYPE_MESSAGE)
|
||||
? field->message_type()->full_name()
|
||||
std::string message_type = (field.type() == WireFormatLite::TYPE_MESSAGE)
|
||||
? field.message_type()->full_name()
|
||||
: "";
|
||||
return ReadValue(bytes, field_type, message_type, result);
|
||||
return ProtoUtilLite::ReadValue(bytes, field.type(), message_type, result);
|
||||
}
|
||||
|
||||
// Reads all values from a repeated field.
|
||||
absl::Status GetFieldValues(const FieldData& message_data,
|
||||
const FieldDescriptor& field,
|
||||
std::vector<FieldData>* result) {
|
||||
absl::StatusOr<std::vector<FieldData>> GetFieldValues(
|
||||
const FieldData& message_data, const FieldDescriptor& field) {
|
||||
std::vector<FieldData> result;
|
||||
const std::string& message_bytes = message_data.message_value().value();
|
||||
FieldType field_type = AsFieldType(field.type());
|
||||
ProtoUtilLite proto_util;
|
||||
ProtoUtilLite::ProtoPath proto_path = {{field.number(), 0}};
|
||||
int count;
|
||||
MP_RETURN_IF_ERROR(
|
||||
proto_util.GetFieldCount(message_bytes, proto_path, field_type, &count));
|
||||
MP_RETURN_IF_ERROR(ProtoUtilLite::GetFieldCount(message_bytes, proto_path,
|
||||
field.type(), &count));
|
||||
std::vector<std::string> field_values;
|
||||
MP_RETURN_IF_ERROR(proto_util.GetFieldRange(message_bytes, proto_path, count,
|
||||
field_type, &field_values));
|
||||
for (int i = 0; i < count; ++i) {
|
||||
MP_RETURN_IF_ERROR(ProtoUtilLite::GetFieldRange(
|
||||
message_bytes, proto_path, count, field.type(), &field_values));
|
||||
for (int i = 0; i < field_values.size(); ++i) {
|
||||
FieldData r;
|
||||
MP_RETURN_IF_ERROR(ReadField(field_values[i], &field, &r));
|
||||
result->push_back(std::move(r));
|
||||
MP_RETURN_IF_ERROR(ReadField(field_values[i], field, &r));
|
||||
result.push_back(std::move(r));
|
||||
}
|
||||
return absl::OkStatus();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Reads one value from a field.
|
||||
@@ -207,42 +83,70 @@ absl::Status GetFieldValue(const FieldData& message_data,
|
||||
const FieldPathEntry& entry, FieldData* result) {
|
||||
RET_CHECK_NE(entry.field, nullptr);
|
||||
const std::string& message_bytes = message_data.message_value().value();
|
||||
FieldType field_type = AsFieldType(entry.field->type());
|
||||
ProtoUtilLite proto_util;
|
||||
ProtoUtilLite::ProtoPath proto_path = {{entry.field->number(), entry.index}};
|
||||
FieldType field_type = entry.field->type();
|
||||
int index = std::max(0, entry.index);
|
||||
ProtoUtilLite::ProtoPath proto_path = {{entry.field->number(), index}};
|
||||
std::vector<std::string> field_values;
|
||||
MP_RETURN_IF_ERROR(proto_util.GetFieldRange(message_bytes, proto_path, 1,
|
||||
field_type, &field_values));
|
||||
MP_RETURN_IF_ERROR(ReadField(field_values[0], entry.field, result));
|
||||
MP_RETURN_IF_ERROR(ProtoUtilLite::GetFieldRange(message_bytes, proto_path, 1,
|
||||
field_type, &field_values));
|
||||
MP_RETURN_IF_ERROR(ReadField(field_values[0], *entry.field, result));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Writes one value to a field.
|
||||
absl::Status SetFieldValue(const FieldPathEntry& entry, const FieldData& value,
|
||||
FieldData* result) {
|
||||
std::vector<FieldData> field_values;
|
||||
ProtoUtilLite proto_util;
|
||||
FieldType field_type = AsFieldType(entry.field->type());
|
||||
ProtoUtilLite::ProtoPath proto_path = {{entry.field->number(), entry.index}};
|
||||
std::string* message_bytes = result->mutable_message_value()->mutable_value();
|
||||
absl::Status SetFieldValue(FieldData& result, const FieldPathEntry& entry,
|
||||
const FieldData& value) {
|
||||
int index = std::max(0, entry.index);
|
||||
ProtoUtilLite::ProtoPath proto_path = {{entry.field->number(), index}};
|
||||
std::string* message_bytes = result.mutable_message_value()->mutable_value();
|
||||
int field_count;
|
||||
MP_RETURN_IF_ERROR(proto_util.GetFieldCount(*message_bytes, proto_path,
|
||||
field_type, &field_count));
|
||||
if (entry.index > field_count) {
|
||||
MP_RETURN_IF_ERROR(ProtoUtilLite::GetFieldCount(
|
||||
*message_bytes, proto_path, entry.field->type(), &field_count));
|
||||
if (index > field_count) {
|
||||
return absl::OutOfRangeError(
|
||||
absl::StrCat("Option field index out of range: ", entry.index));
|
||||
absl::StrCat("Option field index out of range: ", index));
|
||||
}
|
||||
int replace_length = entry.index < field_count ? 1 : 0;
|
||||
int replace_length = index < field_count ? 1 : 0;
|
||||
std::string field_value;
|
||||
MP_RETURN_IF_ERROR(WriteField(value, entry.field, &field_value));
|
||||
MP_RETURN_IF_ERROR(proto_util.ReplaceFieldRange(
|
||||
message_bytes, proto_path, replace_length, field_type, {field_value}));
|
||||
MP_RETURN_IF_ERROR(ProtoUtilLite::ReplaceFieldRange(
|
||||
message_bytes, proto_path, replace_length, entry.field->type(),
|
||||
{field_value}));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Writes several values to a repeated field.
|
||||
// The specified |values| replace the specified |entry| index,
|
||||
// or if no index is specified all field values are replaced.
|
||||
absl::Status SetFieldValues(FieldData& result, const FieldPathEntry& entry,
|
||||
const std::vector<FieldData>& values) {
|
||||
if (entry.field == nullptr) {
|
||||
return absl::InvalidArgumentError("Field not found.");
|
||||
}
|
||||
FieldType field_type = entry.field->type();
|
||||
ProtoUtilLite::ProtoPath proto_path = {{entry.field->number(), 0}};
|
||||
std::string* message_bytes = result.mutable_message_value()->mutable_value();
|
||||
int field_count;
|
||||
MP_RETURN_IF_ERROR(ProtoUtilLite::GetFieldCount(*message_bytes, proto_path,
|
||||
field_type, &field_count));
|
||||
int replace_start = 0, replace_length = field_count;
|
||||
if (entry.index > -1) {
|
||||
replace_start = entry.index;
|
||||
replace_length = 1;
|
||||
}
|
||||
std::vector<std::string> field_values(values.size());
|
||||
for (int i = 0; i < values.size(); ++i) {
|
||||
MP_RETURN_IF_ERROR(WriteField(values[i], entry.field, &field_values[i]));
|
||||
}
|
||||
proto_path = {{entry.field->number(), replace_start}};
|
||||
MP_RETURN_IF_ERROR(ProtoUtilLite::ReplaceFieldRange(
|
||||
message_bytes, proto_path, replace_length, field_type, field_values));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Returns true for a field of type "google.protobuf.Any".
|
||||
bool IsProtobufAny(const FieldDescriptor* field) {
|
||||
return AsFieldType(field->type()) == FieldType::TYPE_MESSAGE &&
|
||||
return field->type() == FieldType::TYPE_MESSAGE &&
|
||||
field->message_type()->full_name() == kGoogleProtobufAny;
|
||||
}
|
||||
|
||||
@@ -275,9 +179,7 @@ StatusOr<int> FindExtensionIndex(const FieldData& message_data,
|
||||
}
|
||||
std::string& extension_type = entry->extension_type;
|
||||
std::vector<FieldData> field_values;
|
||||
RET_CHECK_NE(entry->field, nullptr);
|
||||
MP_RETURN_IF_ERROR(
|
||||
GetFieldValues(message_data, *entry->field, &field_values));
|
||||
ASSIGN_OR_RETURN(field_values, GetFieldValues(message_data, *entry->field));
|
||||
for (int i = 0; i < field_values.size(); ++i) {
|
||||
FieldData extension = ParseProtobufAny(field_values[i]);
|
||||
if (extension_type == "*" ||
|
||||
@@ -290,9 +192,9 @@ StatusOr<int> FindExtensionIndex(const FieldData& message_data,
|
||||
|
||||
// Returns true if the value of a field is available.
|
||||
bool HasField(const FieldPath& field_path, const FieldData& message_data) {
|
||||
FieldData value;
|
||||
return GetField(field_path, message_data, &value).ok() &&
|
||||
value.value_case() != mediapipe::FieldData::VALUE_NOT_SET;
|
||||
auto value = GetField(message_data, field_path);
|
||||
return value.ok() &&
|
||||
value->value_case() != mediapipe::FieldData::VALUE_NOT_SET;
|
||||
}
|
||||
|
||||
// Returns the extension field containing the specified extension-type.
|
||||
@@ -330,43 +232,24 @@ void SetOptionsMessage(
|
||||
*options_any->mutable_value() = node_options.message_value().value();
|
||||
}
|
||||
|
||||
// Returns the count of values in a repeated field.
|
||||
int FieldCount(const FieldData& message_data, const FieldDescriptor* field) {
|
||||
const std::string& message_bytes = message_data.message_value().value();
|
||||
FieldType field_type = AsFieldType(field->type());
|
||||
ProtoUtilLite proto_util;
|
||||
ProtoUtilLite::ProtoPath proto_path = {{field->number(), 0}};
|
||||
int count;
|
||||
if (proto_util.GetFieldCount(message_bytes, proto_path, field_type, &count)
|
||||
.ok()) {
|
||||
return count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// Deserializes a packet containing a MessageLite value.
|
||||
absl::Status ReadMessage(const std::string& value, const std::string& type_name,
|
||||
Packet* result) {
|
||||
auto packet = packet_internal::PacketFromDynamicProto(type_name, value);
|
||||
if (packet.ok()) {
|
||||
*result = *packet;
|
||||
}
|
||||
return packet.status();
|
||||
absl::StatusOr<Packet> ReadMessage(const std::string& value,
|
||||
const std::string& type_name) {
|
||||
return packet_internal::PacketFromDynamicProto(type_name, value);
|
||||
}
|
||||
|
||||
// Merge two options FieldData values.
|
||||
absl::Status MergeMessages(const FieldData& base, const FieldData& over,
|
||||
FieldData* result) {
|
||||
absl::StatusOr<FieldData> MergeMessages(const FieldData& base,
|
||||
const FieldData& over) {
|
||||
FieldData result;
|
||||
absl::Status status;
|
||||
if (over.value_case() == FieldData::VALUE_NOT_SET) {
|
||||
*result = base;
|
||||
return status;
|
||||
return base;
|
||||
}
|
||||
if (base.value_case() == FieldData::VALUE_NOT_SET) {
|
||||
*result = over;
|
||||
return status;
|
||||
return over;
|
||||
}
|
||||
if (over.value_case() != base.value_case()) {
|
||||
return absl::InvalidArgumentError(absl::StrCat(
|
||||
@@ -382,10 +265,9 @@ absl::Status MergeMessages(const FieldData& base, const FieldData& over,
|
||||
absl::Cord merged_value;
|
||||
merged_value.Append(base.message_value().value());
|
||||
merged_value.Append(over.message_value().value());
|
||||
result->mutable_message_value()->set_type_url(
|
||||
base.message_value().type_url());
|
||||
result->mutable_message_value()->set_value(std::string(merged_value));
|
||||
return status;
|
||||
result.mutable_message_value()->set_type_url(base.message_value().type_url());
|
||||
result.mutable_message_value()->set_value(std::string(merged_value));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns either the extension field or the repeated protobuf.Any field index
|
||||
@@ -439,51 +321,48 @@ FieldPath GetExtensionPath(const std::string& parent_type,
|
||||
}
|
||||
|
||||
// Returns the requested options protobuf for a graph node.
|
||||
absl::Status GetNodeOptions(const FieldData& message_data,
|
||||
const std::string& extension_type,
|
||||
FieldData* result) {
|
||||
absl::StatusOr<FieldData> GetNodeOptions(const FieldData& message_data,
|
||||
const std::string& extension_type) {
|
||||
constexpr char kOptionsName[] = "options";
|
||||
constexpr char kNodeOptionsName[] = "node_options";
|
||||
std::string parent_type = options_field_util::ParseTypeUrl(
|
||||
std::string(message_data.message_value().type_url()));
|
||||
FieldPath path;
|
||||
Status status;
|
||||
absl::Status status;
|
||||
path = GetExtensionPath(parent_type, extension_type, kOptionsName, false);
|
||||
status = GetField(path, message_data, result);
|
||||
if (status.ok()) {
|
||||
return status;
|
||||
auto result = GetField(message_data, path);
|
||||
if (result.ok()) {
|
||||
return result;
|
||||
}
|
||||
path = GetExtensionPath(parent_type, extension_type, kNodeOptionsName, true);
|
||||
status = GetField(path, message_data, result);
|
||||
return status;
|
||||
return GetField(message_data, path);
|
||||
}
|
||||
|
||||
// Returns the requested options protobuf for a graph.
|
||||
absl::Status GetGraphOptions(const FieldData& message_data,
|
||||
const std::string& extension_type,
|
||||
FieldData* result) {
|
||||
absl::StatusOr<FieldData> GetGraphOptions(const FieldData& message_data,
|
||||
const std::string& extension_type) {
|
||||
constexpr char kOptionsName[] = "options";
|
||||
constexpr char kGraphOptionsName[] = "graph_options";
|
||||
std::string parent_type = options_field_util::ParseTypeUrl(
|
||||
std::string(message_data.message_value().type_url()));
|
||||
FieldPath path;
|
||||
Status status;
|
||||
absl::Status status;
|
||||
path = GetExtensionPath(parent_type, extension_type, kOptionsName, false);
|
||||
status = GetField(path, message_data, result);
|
||||
if (status.ok()) {
|
||||
return status;
|
||||
auto result = GetField(message_data, path);
|
||||
if (result.ok()) {
|
||||
return result;
|
||||
}
|
||||
path = GetExtensionPath(parent_type, extension_type, kGraphOptionsName, true);
|
||||
status = GetField(path, message_data, result);
|
||||
return status;
|
||||
return GetField(message_data, path);
|
||||
}
|
||||
|
||||
// Reads a FieldData value from a protobuf field.
|
||||
absl::Status GetField(const FieldPath& field_path,
|
||||
const FieldData& message_data, FieldData* result) {
|
||||
// Reads the FieldData values from a protobuf field.
|
||||
absl::StatusOr<std::vector<FieldData>> GetFieldValues(
|
||||
const FieldData& message_data, const FieldPath& field_path) {
|
||||
std::vector<FieldData> results;
|
||||
if (field_path.empty()) {
|
||||
*result->mutable_message_value() = message_data.message_value();
|
||||
return absl::OkStatus();
|
||||
results.push_back(message_data);
|
||||
return results;
|
||||
}
|
||||
FieldPathEntry head = field_path.front();
|
||||
FieldPath tail = field_path;
|
||||
@@ -491,65 +370,101 @@ absl::Status GetField(const FieldPath& field_path,
|
||||
if (!head.extension_type.empty()) {
|
||||
MP_RETURN_IF_ERROR(FindExtension(message_data, &head));
|
||||
}
|
||||
if (tail.empty() && FieldCount(message_data, head.field) == 0) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
MP_RETURN_IF_ERROR(GetFieldValue(message_data, head, result));
|
||||
RET_CHECK_NE(head.field, nullptr);
|
||||
ASSIGN_OR_RETURN(results, GetFieldValues(message_data, *head.field));
|
||||
if (IsProtobufAny(head.field)) {
|
||||
*result = ParseProtobufAny(*result);
|
||||
for (int i = 0; i < results.size(); ++i) {
|
||||
results[i] = ParseProtobufAny(results[i]);
|
||||
}
|
||||
}
|
||||
int index = tail.empty() ? head.index : std::max(0, head.index);
|
||||
if ((int)results.size() <= index) {
|
||||
return absl::OutOfRangeError(absl::StrCat(
|
||||
"Missing feild value: ", head.field ? head.field->name() : "#",
|
||||
" at index: ", index));
|
||||
}
|
||||
if (!tail.empty()) {
|
||||
FieldData child = *result;
|
||||
MP_RETURN_IF_ERROR(GetField(tail, child, result));
|
||||
FieldData child = results.at(index);
|
||||
ASSIGN_OR_RETURN(results, GetFieldValues(child, tail));
|
||||
} else if (index > -1) {
|
||||
FieldData child = results.at(index);
|
||||
results.clear();
|
||||
results.push_back(child);
|
||||
}
|
||||
return absl::OkStatus();
|
||||
return results;
|
||||
}
|
||||
|
||||
// Writes a FieldData value into protobuf field.
|
||||
absl::Status SetField(const FieldPath& field_path, const FieldData& value,
|
||||
FieldData* message_data) {
|
||||
// Reads a FieldData value from a protobuf field.
|
||||
absl::StatusOr<FieldData> GetField(const FieldData& message_data,
|
||||
const FieldPath& field_path) {
|
||||
std::vector<FieldData> results;
|
||||
ASSIGN_OR_RETURN(results, GetFieldValues(message_data, field_path));
|
||||
if (results.empty()) {
|
||||
FieldPathEntry tail = field_path.back();
|
||||
return absl::OutOfRangeError(absl::StrCat(
|
||||
"Missing feild value: ", tail.field ? tail.field->name() : "##",
|
||||
" at index: ", tail.index));
|
||||
}
|
||||
return results[0];
|
||||
}
|
||||
|
||||
// Writes FieldData values into protobuf field.
|
||||
absl::Status SetFieldValues(FieldData& message_data,
|
||||
const FieldPath& field_path,
|
||||
const std::vector<FieldData>& values) {
|
||||
if (field_path.empty()) {
|
||||
*message_data->mutable_message_value() = value.message_value();
|
||||
if (values.empty()) {
|
||||
return absl::InvalidArgumentError("Missing feild value.");
|
||||
}
|
||||
message_data = values[0];
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
FieldPathEntry head = field_path.front();
|
||||
FieldPath tail = field_path;
|
||||
tail.erase(tail.begin());
|
||||
if (!head.extension_type.empty()) {
|
||||
MP_RETURN_IF_ERROR(FindExtension(*message_data, &head));
|
||||
MP_RETURN_IF_ERROR(FindExtension(message_data, &head));
|
||||
}
|
||||
if (tail.empty()) {
|
||||
MP_RETURN_IF_ERROR(SetFieldValue(head, value, message_data));
|
||||
} else {
|
||||
FieldData child;
|
||||
MP_RETURN_IF_ERROR(GetFieldValue(*message_data, head, &child));
|
||||
MP_RETURN_IF_ERROR(SetField(tail, value, &child));
|
||||
if (IsProtobufAny(head.field)) {
|
||||
child = SerializeProtobufAny(child);
|
||||
}
|
||||
MP_RETURN_IF_ERROR(SetFieldValue(head, child, message_data));
|
||||
MP_RETURN_IF_ERROR(SetFieldValues(message_data, head, values));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
FieldData child;
|
||||
MP_RETURN_IF_ERROR(GetFieldValue(message_data, head, &child));
|
||||
MP_RETURN_IF_ERROR(SetFieldValues(child, tail, values));
|
||||
if (IsProtobufAny(head.field)) {
|
||||
child = SerializeProtobufAny(child);
|
||||
}
|
||||
MP_RETURN_IF_ERROR(SetFieldValue(message_data, head, child));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Merges a packet value into nested protobuf Message.
|
||||
absl::Status MergeField(const FieldPath& field_path, const FieldData& value,
|
||||
FieldData* message_data) {
|
||||
// Writes a FieldData value into protobuf field.
|
||||
absl::Status SetField(FieldData& message_data, const FieldPath& field_path,
|
||||
const FieldData& value) {
|
||||
return SetFieldValues(message_data, field_path, {value});
|
||||
}
|
||||
|
||||
// Merges FieldData values into nested protobuf Message.
|
||||
// For each new field index, any previous value is merged with the new value.
|
||||
absl::Status MergeFieldValues(FieldData& message_data,
|
||||
const FieldPath& field_path,
|
||||
const std::vector<FieldData>& values) {
|
||||
absl::Status status;
|
||||
FieldType field_type = field_path.empty()
|
||||
? FieldType::TYPE_MESSAGE
|
||||
: AsFieldType(field_path.back().field->type());
|
||||
std::string message_type =
|
||||
(value.has_message_value())
|
||||
? ParseTypeUrl(std::string(value.message_value().type_url()))
|
||||
: "";
|
||||
FieldData v = value;
|
||||
FieldType field_type = field_path.empty() ? FieldType::TYPE_MESSAGE
|
||||
: field_path.back().field->type();
|
||||
std::vector<FieldData> results = values;
|
||||
std::vector<FieldData> prevs;
|
||||
ASSIGN_OR_RETURN(prevs, GetFieldValues(message_data, field_path));
|
||||
if (field_type == FieldType::TYPE_MESSAGE) {
|
||||
FieldData b;
|
||||
status.Update(GetField(field_path, *message_data, &b));
|
||||
status.Update(MergeMessages(b, v, &v));
|
||||
for (int i = 0; i < std::min(values.size(), prevs.size()); ++i) {
|
||||
FieldData& v = results[i];
|
||||
FieldData& b = prevs[i];
|
||||
ASSIGN_OR_RETURN(v, MergeMessages(b, v));
|
||||
}
|
||||
}
|
||||
status.Update(SetField(field_path, v, message_data));
|
||||
status.Update(SetFieldValues(message_data, field_path, results));
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -576,34 +491,35 @@ struct ProtoEnum {
|
||||
int32 value;
|
||||
};
|
||||
|
||||
absl::Status AsPacket(const FieldData& data, Packet* result) {
|
||||
absl::StatusOr<Packet> AsPacket(const FieldData& data) {
|
||||
Packet result;
|
||||
switch (data.value_case()) {
|
||||
case FieldData::ValueCase::kInt32Value:
|
||||
*result = MakePacket<int32>(data.int32_value());
|
||||
result = MakePacket<int32>(data.int32_value());
|
||||
break;
|
||||
case FieldData::ValueCase::kInt64Value:
|
||||
*result = MakePacket<int64>(data.int64_value());
|
||||
result = MakePacket<int64>(data.int64_value());
|
||||
break;
|
||||
case FieldData::ValueCase::kUint32Value:
|
||||
*result = MakePacket<uint32>(data.uint32_value());
|
||||
result = MakePacket<uint32>(data.uint32_value());
|
||||
break;
|
||||
case FieldData::ValueCase::kUint64Value:
|
||||
*result = MakePacket<uint64>(data.uint64_value());
|
||||
result = MakePacket<uint64>(data.uint64_value());
|
||||
break;
|
||||
case FieldData::ValueCase::kDoubleValue:
|
||||
*result = MakePacket<double>(data.double_value());
|
||||
result = MakePacket<double>(data.double_value());
|
||||
break;
|
||||
case FieldData::ValueCase::kFloatValue:
|
||||
*result = MakePacket<float>(data.float_value());
|
||||
result = MakePacket<float>(data.float_value());
|
||||
break;
|
||||
case FieldData::ValueCase::kBoolValue:
|
||||
*result = MakePacket<bool>(data.bool_value());
|
||||
result = MakePacket<bool>(data.bool_value());
|
||||
break;
|
||||
case FieldData::ValueCase::kEnumValue:
|
||||
*result = MakePacket<ProtoEnum>(data.enum_value());
|
||||
result = MakePacket<ProtoEnum>(data.enum_value());
|
||||
break;
|
||||
case FieldData::ValueCase::kStringValue:
|
||||
*result = MakePacket<std::string>(data.string_value());
|
||||
result = MakePacket<std::string>(data.string_value());
|
||||
break;
|
||||
case FieldData::ValueCase::kMessageValue: {
|
||||
auto r = packet_internal::PacketFromDynamicProto(
|
||||
@@ -612,32 +528,33 @@ absl::Status AsPacket(const FieldData& data, Packet* result) {
|
||||
if (!r.ok()) {
|
||||
return r.status();
|
||||
}
|
||||
*result = r.value();
|
||||
result = r.value();
|
||||
break;
|
||||
}
|
||||
case FieldData::VALUE_NOT_SET:
|
||||
*result = Packet();
|
||||
result = Packet();
|
||||
}
|
||||
return absl::OkStatus();
|
||||
return result;
|
||||
}
|
||||
|
||||
absl::Status AsFieldData(Packet packet, FieldData* result) {
|
||||
static const auto* kTypeIds = new std::map<size_t, int32>{
|
||||
{tool::GetTypeHash<int32>(), WireFormatLite::CPPTYPE_INT32},
|
||||
{tool::GetTypeHash<int64>(), WireFormatLite::CPPTYPE_INT64},
|
||||
{tool::GetTypeHash<uint32>(), WireFormatLite::CPPTYPE_UINT32},
|
||||
{tool::GetTypeHash<uint64>(), WireFormatLite::CPPTYPE_UINT64},
|
||||
{tool::GetTypeHash<double>(), WireFormatLite::CPPTYPE_DOUBLE},
|
||||
{tool::GetTypeHash<float>(), WireFormatLite::CPPTYPE_FLOAT},
|
||||
{tool::GetTypeHash<bool>(), WireFormatLite::CPPTYPE_BOOL},
|
||||
{tool::GetTypeHash<ProtoEnum>(), WireFormatLite::CPPTYPE_ENUM},
|
||||
{tool::GetTypeHash<std::string>(), WireFormatLite::CPPTYPE_STRING},
|
||||
absl::StatusOr<FieldData> AsFieldData(Packet packet) {
|
||||
static const auto* kTypeIds = new std::map<TypeId, int32>{
|
||||
{kTypeId<int32>, WireFormatLite::CPPTYPE_INT32},
|
||||
{kTypeId<int64>, WireFormatLite::CPPTYPE_INT64},
|
||||
{kTypeId<uint32>, WireFormatLite::CPPTYPE_UINT32},
|
||||
{kTypeId<uint64>, WireFormatLite::CPPTYPE_UINT64},
|
||||
{kTypeId<double>, WireFormatLite::CPPTYPE_DOUBLE},
|
||||
{kTypeId<float>, WireFormatLite::CPPTYPE_FLOAT},
|
||||
{kTypeId<bool>, WireFormatLite::CPPTYPE_BOOL},
|
||||
{kTypeId<ProtoEnum>, WireFormatLite::CPPTYPE_ENUM},
|
||||
{kTypeId<std::string>, WireFormatLite::CPPTYPE_STRING},
|
||||
};
|
||||
|
||||
FieldData result;
|
||||
if (packet.ValidateAsProtoMessageLite().ok()) {
|
||||
result->mutable_message_value()->set_value(
|
||||
result.mutable_message_value()->set_value(
|
||||
packet.GetProtoMessageLite().SerializeAsString());
|
||||
result->mutable_message_value()->set_type_url(
|
||||
result.mutable_message_value()->set_type_url(
|
||||
TypeUrl(packet.GetProtoMessageLite().GetTypeName()));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
@@ -649,48 +566,42 @@ absl::Status AsFieldData(Packet packet, FieldData* result) {
|
||||
|
||||
switch (kTypeIds->at(packet.GetTypeId())) {
|
||||
case WireFormatLite::CPPTYPE_INT32:
|
||||
result->set_int32_value(packet.Get<int32>());
|
||||
result.set_int32_value(packet.Get<int32>());
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_INT64:
|
||||
result->set_int64_value(packet.Get<int64>());
|
||||
result.set_int64_value(packet.Get<int64>());
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_UINT32:
|
||||
result->set_uint32_value(packet.Get<uint32>());
|
||||
result.set_uint32_value(packet.Get<uint32>());
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_UINT64:
|
||||
result->set_uint64_value(packet.Get<uint64>());
|
||||
result.set_uint64_value(packet.Get<uint64>());
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_DOUBLE:
|
||||
result->set_double_value(packet.Get<double>());
|
||||
result.set_double_value(packet.Get<double>());
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_FLOAT:
|
||||
result->set_float_value(packet.Get<float>());
|
||||
result.set_float_value(packet.Get<float>());
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_BOOL:
|
||||
result->set_bool_value(packet.Get<bool>());
|
||||
result.set_bool_value(packet.Get<bool>());
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_ENUM:
|
||||
result->set_enum_value(packet.Get<ProtoEnum>().value);
|
||||
result.set_enum_value(packet.Get<ProtoEnum>().value);
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_STRING:
|
||||
result->set_string_value(packet.Get<std::string>());
|
||||
result.set_string_value(packet.Get<std::string>());
|
||||
break;
|
||||
}
|
||||
return absl::OkStatus();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string TypeUrl(absl::string_view type_name) {
|
||||
constexpr std::string_view kTypeUrlPrefix = "type.googleapis.com/";
|
||||
return absl::StrCat(std::string(kTypeUrlPrefix), std::string(type_name));
|
||||
return ProtoUtilLite::TypeUrl(type_name);
|
||||
}
|
||||
|
||||
std::string ParseTypeUrl(absl::string_view type_url) {
|
||||
constexpr std::string_view kTypeUrlPrefix = "type.googleapis.com/";
|
||||
if (std::string(type_url).rfind(kTypeUrlPrefix, 0) == 0) {
|
||||
return std::string(
|
||||
type_url.substr(kTypeUrlPrefix.length(), std::string::npos));
|
||||
}
|
||||
return std::string(type_url);
|
||||
return ProtoUtilLite::ParseTypeUrl(type_url);
|
||||
}
|
||||
|
||||
} // namespace options_field_util
|
||||
|
||||
@@ -34,30 +34,38 @@ absl::Status SetField(const FieldPath& field_path, const FieldData& value,
|
||||
FieldData* message_data);
|
||||
|
||||
// Reads a field value from a protobuf field.
|
||||
absl::Status GetField(const FieldPath& field_path,
|
||||
const FieldData& message_data, FieldData* result);
|
||||
absl::StatusOr<FieldData> GetField(const FieldData& message_data,
|
||||
const FieldPath& field_path);
|
||||
|
||||
// Merges a field value into nested protobuf Message.
|
||||
absl::Status MergeField(const FieldPath& field_path, const FieldData& value,
|
||||
FieldData* message_data);
|
||||
// Reads one or all FieldData values from a protobuf field.
|
||||
absl::StatusOr<std::vector<FieldData>> GetFieldValues(
|
||||
const FieldData& message_data, const FieldPath& field_path);
|
||||
|
||||
// Writes FieldData values into a protobuf field.
|
||||
absl::Status SetFieldValues(FieldData& message_data,
|
||||
const FieldPath& field_path,
|
||||
const std::vector<FieldData>& values);
|
||||
|
||||
// Merges FieldData values into a protobuf field.
|
||||
absl::Status MergeFieldValues(FieldData& message_data,
|
||||
const FieldPath& field_path,
|
||||
const std::vector<FieldData>& values);
|
||||
|
||||
// Deserializes a packet containing a MessageLite value.
|
||||
absl::Status ReadMessage(const std::string& value, const std::string& type_name,
|
||||
Packet* result);
|
||||
absl::StatusOr<Packet> ReadMessage(const std::string& value,
|
||||
const std::string& type_name);
|
||||
|
||||
// Merge two options protobuf field values.
|
||||
absl::Status MergeMessages(const FieldData& base, const FieldData& over,
|
||||
FieldData* result);
|
||||
absl::StatusOr<FieldData> MergeMessages(const FieldData& base,
|
||||
const FieldData& over);
|
||||
|
||||
// Returns the requested options protobuf for a graph.
|
||||
absl::Status GetNodeOptions(const FieldData& message_data,
|
||||
const std::string& extension_type,
|
||||
FieldData* result);
|
||||
absl::StatusOr<FieldData> GetNodeOptions(const FieldData& message_data,
|
||||
const std::string& extension_type);
|
||||
|
||||
// Returns the requested options protobuf for a graph node.
|
||||
absl::Status GetGraphOptions(const FieldData& message_data,
|
||||
const std::string& extension_type,
|
||||
FieldData* result);
|
||||
absl::StatusOr<FieldData> GetGraphOptions(const FieldData& message_data,
|
||||
const std::string& extension_type);
|
||||
|
||||
// Sets the node_options field in a Node, and clears the options field.
|
||||
void SetOptionsMessage(const FieldData& node_options,
|
||||
@@ -67,10 +75,10 @@ void SetOptionsMessage(const FieldData& node_options,
|
||||
FieldData AsFieldData(const proto_ns::MessageLite& message);
|
||||
|
||||
// Constructs a Packet for a FieldData proto.
|
||||
absl::Status AsPacket(const FieldData& data, Packet* result);
|
||||
absl::StatusOr<Packet> AsPacket(const FieldData& data);
|
||||
|
||||
// Constructs a FieldData proto for a Packet.
|
||||
absl::Status AsFieldData(Packet packet, FieldData* result);
|
||||
absl::StatusOr<FieldData> AsFieldData(Packet packet);
|
||||
|
||||
// Returns the protobuf type-url for a protobuf type-name.
|
||||
std::string TypeUrl(absl::string_view type_name);
|
||||
|
||||
@@ -25,11 +25,12 @@ constexpr char kDescriptorContents[] =
|
||||
#include "{{DESCRIPTOR_INC_FILE_PATH}}"
|
||||
; // NOLINT(whitespace/semicolon)
|
||||
|
||||
mediapipe::proto_ns::FileDescriptorSet ParseFileDescriptorSet(
|
||||
const std::string& pb) {
|
||||
mediapipe::proto_ns::FileDescriptorSet files;
|
||||
files.ParseFromString(pb);
|
||||
return files;
|
||||
mediapipe::FieldData ReadFileDescriptorSet(const std::string& pb) {
|
||||
mediapipe::FieldData result;
|
||||
*result.mutable_message_value()->mutable_type_url() =
|
||||
"proto2.FileDescriptorSet";
|
||||
*result.mutable_message_value()->mutable_value() = pb;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -39,6 +40,6 @@ namespace mediapipe {
|
||||
template <>
|
||||
const RegistrationToken tool::OptionsRegistry::registration_token<
|
||||
MP_OPTION_TYPE_NS::MP_OPTION_TYPE_NAME> =
|
||||
tool::OptionsRegistry::Register(ParseFileDescriptorSet(
|
||||
tool::OptionsRegistry::Register(ReadFileDescriptorSet(
|
||||
std::string(kDescriptorContents, sizeof(kDescriptorContents) - 1)));
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -30,15 +30,26 @@ struct IsExtension {
|
||||
|
||||
template <class T,
|
||||
typename std::enable_if<IsExtension<T>::value, int>::type = 0>
|
||||
void GetExtension(const CalculatorOptions& options, T* result) {
|
||||
T* GetExtension(CalculatorOptions& options) {
|
||||
if (options.HasExtension(T::ext)) {
|
||||
*result = options.GetExtension(T::ext);
|
||||
return options.MutableExtension(T::ext);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T,
|
||||
typename std::enable_if<!IsExtension<T>::value, int>::type = 0>
|
||||
void GetExtension(const CalculatorOptions& options, T* result) {}
|
||||
T* GetExtension(const CalculatorOptions& options) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void GetExtension(const CalculatorOptions& options, T* result) {
|
||||
T* r = GetExtension<T>(*const_cast<CalculatorOptions*>(&options));
|
||||
if (r) {
|
||||
*result = *r;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void GetNodeOptions(const CalculatorGraphConfig::Node& node_config, T* result) {
|
||||
@@ -53,23 +64,39 @@ void GetNodeOptions(const CalculatorGraphConfig::Node& node_config, T* result) {
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void SetNodeOptions(CalculatorGraphConfig::Node& node_config, const T& value) {
|
||||
#if defined(MEDIAPIPE_PROTO_LITE) && defined(MEDIAPIPE_PROTO_THIRD_PARTY)
|
||||
// protobuf::Any is unavailable with third_party/protobuf:protobuf-lite.
|
||||
#else
|
||||
for (mediapipe::protobuf::Any& options :
|
||||
*node_config.mutable_node_options()) {
|
||||
if (options.Is<T>()) {
|
||||
options.PackFrom(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
node_config.add_node_options()->PackFrom(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
// A map from object type to object.
|
||||
class TypeMap {
|
||||
public:
|
||||
template <class T>
|
||||
bool Has() const {
|
||||
return content_.count(TypeInfo::Get<T>()) > 0;
|
||||
return content_.count(kTypeId<T>) > 0;
|
||||
}
|
||||
template <class T>
|
||||
T* Get() const {
|
||||
if (!Has<T>()) {
|
||||
content_[TypeInfo::Get<T>()] = std::make_shared<T>();
|
||||
content_[kTypeId<T>] = std::make_shared<T>();
|
||||
}
|
||||
return static_cast<T*>(content_[TypeInfo::Get<T>()].get());
|
||||
return static_cast<T*>(content_[kTypeId<T>].get());
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::map<TypeIndex, std::shared_ptr<void>> content_;
|
||||
mutable std::map<TypeId, std::shared_ptr<void>> content_;
|
||||
};
|
||||
|
||||
// Extracts the options message of a specified type from a
|
||||
@@ -77,7 +104,7 @@ class TypeMap {
|
||||
class OptionsMap {
|
||||
public:
|
||||
OptionsMap& Initialize(const CalculatorGraphConfig::Node& node_config) {
|
||||
node_config_ = &node_config;
|
||||
node_config_ = const_cast<CalculatorGraphConfig::Node*>(&node_config);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -97,10 +124,40 @@ class OptionsMap {
|
||||
return *result;
|
||||
}
|
||||
|
||||
const CalculatorGraphConfig::Node* node_config_;
|
||||
CalculatorGraphConfig::Node* node_config_;
|
||||
TypeMap options_;
|
||||
};
|
||||
|
||||
class MutableOptionsMap : public OptionsMap {
|
||||
public:
|
||||
MutableOptionsMap& Initialize(CalculatorGraphConfig::Node& node_config) {
|
||||
node_config_ = &node_config;
|
||||
return *this;
|
||||
}
|
||||
template <class T>
|
||||
void Set(const T& value) const {
|
||||
*options_.Get<T>() = value;
|
||||
if (node_config_->has_options()) {
|
||||
*GetExtension<T>(*node_config_->mutable_options()) = value;
|
||||
} else {
|
||||
SetNodeOptions(*node_config_, value);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T* GetMutable() const {
|
||||
if (options_.Has<T>()) {
|
||||
return options_.Get<T>();
|
||||
}
|
||||
if (node_config_->has_options()) {
|
||||
return GetExtension<T>(*node_config_->mutable_options());
|
||||
}
|
||||
T* result = options_.Get<T>();
|
||||
GetNodeOptions(*node_config_, result);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tool
|
||||
} // namespace mediapipe
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#include "mediapipe/framework/tool/options_registry.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "mediapipe/framework/port/ret_check.h"
|
||||
#include "mediapipe/framework/tool/proto_util_lite.h"
|
||||
|
||||
namespace mediapipe {
|
||||
namespace tool {
|
||||
@@ -9,37 +14,135 @@ namespace {
|
||||
|
||||
// Returns a canonical message type name, with any leading "." removed.
|
||||
std::string CanonicalTypeName(const std::string& type_name) {
|
||||
return (type_name.rfind('.', 0) == 0) ? type_name.substr(1) : type_name;
|
||||
return (absl::StartsWith(type_name, ".")) ? type_name.substr(1) : type_name;
|
||||
}
|
||||
|
||||
// Returns the values from a protobuf field as typed FieldData.
|
||||
absl::StatusOr<std::vector<FieldData>> GetFieldValues(
|
||||
const FieldData& message_data, std::string field_name) {
|
||||
std::string type_name =
|
||||
ProtoUtilLite::ParseTypeUrl(message_data.message_value().type_url());
|
||||
const Descriptor* descriptor =
|
||||
OptionsRegistry::GetProtobufDescriptor(type_name);
|
||||
RET_CHECK_NE(descriptor, nullptr);
|
||||
const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
|
||||
if (field == nullptr) {
|
||||
return std::vector<FieldData>();
|
||||
}
|
||||
ProtoUtilLite::ProtoPath proto_path = {{field->number(), 0}};
|
||||
ProtoUtilLite::FieldValue mesage_bytes = message_data.message_value().value();
|
||||
int count;
|
||||
MP_RETURN_IF_ERROR(ProtoUtilLite::GetFieldCount(mesage_bytes, proto_path,
|
||||
field->type(), &count));
|
||||
std::vector<std::string> field_values;
|
||||
MP_RETURN_IF_ERROR(ProtoUtilLite::GetFieldRange(
|
||||
mesage_bytes, proto_path, count, field->type(), &field_values));
|
||||
std::vector<FieldData> result;
|
||||
for (int i = 0; i < field_values.size(); ++i) {
|
||||
FieldData r;
|
||||
std::string message_type =
|
||||
field->message_type() ? field->message_type()->full_name() : "";
|
||||
MP_RETURN_IF_ERROR(ProtoUtilLite::ReadValue(field_values[i], field->type(),
|
||||
message_type, &r));
|
||||
result.push_back(std::move(r));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns a single value from a protobuf string field.
|
||||
std::string GetFieldString(const FieldData& message_data,
|
||||
std::string field_name) {
|
||||
auto values = GetFieldValues(message_data, field_name);
|
||||
if (!values->empty()) {
|
||||
return values->front().string_value();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// Registers the descriptors for the descriptor protobufs. These four
|
||||
// descriptors are required to deserialize descriptors for other protobufs.
|
||||
// This implementation avoids a code size problem introduced by
|
||||
// proto_ns::DescriptorProto.
|
||||
void RegisterDescriptorProtos(
|
||||
absl::flat_hash_map<std::string, Descriptor>& result) {
|
||||
std::vector<Descriptor> descriptors = {
|
||||
{"proto2.FileDescriptorSet",
|
||||
{
|
||||
{"file", 1, FieldType::TYPE_MESSAGE, "proto2.FileDescriptorProto"},
|
||||
}},
|
||||
{"proto2.FileDescriptorProto",
|
||||
{
|
||||
{"package", 2, FieldType::TYPE_STRING, ""},
|
||||
{"message_type", 4, FieldType::TYPE_MESSAGE,
|
||||
"proto2.DescriptorProto"},
|
||||
}},
|
||||
{"proto2.DescriptorProto",
|
||||
{
|
||||
{"name", 1, FieldType::TYPE_STRING, ""},
|
||||
{"field", 2, FieldType::TYPE_MESSAGE, "proto2.FieldDescriptorProto"},
|
||||
{"extension", 6, FieldType::TYPE_MESSAGE,
|
||||
"proto2.FieldDescriptorProto"},
|
||||
{"nested_type", 3, FieldType::TYPE_MESSAGE,
|
||||
"proto2.DescriptorProto"},
|
||||
}},
|
||||
{"proto2.FieldDescriptorProto",
|
||||
{
|
||||
{"name", 1, FieldType::TYPE_STRING, ""},
|
||||
{"number", 3, FieldType::TYPE_INT32, ""},
|
||||
{"type", 5, FieldType::TYPE_ENUM, ""},
|
||||
{"type_name", 6, FieldType::TYPE_STRING, ""},
|
||||
{"extendee", 2, FieldType::TYPE_STRING, ""},
|
||||
}},
|
||||
};
|
||||
for (const auto& descriptor : descriptors) {
|
||||
result[descriptor.full_name()] = descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RegistrationToken OptionsRegistry::Register(
|
||||
const proto_ns::FileDescriptorSet& files) {
|
||||
absl::MutexLock lock(&mutex());
|
||||
for (auto& file : files.file()) {
|
||||
for (auto& message_type : file.message_type()) {
|
||||
Register(message_type, file.package());
|
||||
const FieldData& file_descriptor_set) {
|
||||
auto files = GetFieldValues(file_descriptor_set, "file");
|
||||
for (auto& file : *files) {
|
||||
std::string package_name = GetFieldString(file, "package");
|
||||
auto message_types = GetFieldValues(file, "message_type");
|
||||
for (auto& message_type : *message_types) {
|
||||
Register(message_type, package_name);
|
||||
}
|
||||
}
|
||||
return RegistrationToken([]() {});
|
||||
}
|
||||
|
||||
void OptionsRegistry::Register(const proto_ns::DescriptorProto& message_type,
|
||||
void OptionsRegistry::Register(const FieldData& message_type,
|
||||
const std::string& parent_name) {
|
||||
auto full_name = absl::StrCat(parent_name, ".", message_type.name());
|
||||
descriptors()[full_name] = Descriptor(message_type, full_name);
|
||||
for (auto& nested : message_type.nested_type()) {
|
||||
std::string name = GetFieldString(message_type, "name");
|
||||
std::string full_name = absl::StrCat(parent_name, ".", name);
|
||||
Descriptor descriptor(full_name, message_type);
|
||||
{
|
||||
absl::MutexLock lock(&mutex());
|
||||
descriptors()[full_name] = descriptor;
|
||||
}
|
||||
auto nested_types = GetFieldValues(message_type, "nested_type");
|
||||
for (auto& nested : *nested_types) {
|
||||
Register(nested, full_name);
|
||||
}
|
||||
for (auto& extension : message_type.extension()) {
|
||||
extensions()[CanonicalTypeName(extension.extendee())].push_back(
|
||||
FieldDescriptor(extension));
|
||||
auto exts = GetFieldValues(message_type, "extension");
|
||||
for (auto& extension : *exts) {
|
||||
FieldDescriptor field(extension);
|
||||
std::string extendee = GetFieldString(extension, "extendee");
|
||||
{
|
||||
absl::MutexLock lock(&mutex());
|
||||
extensions()[CanonicalTypeName(extendee)].push_back(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Descriptor* OptionsRegistry::GetProtobufDescriptor(
|
||||
const std::string& type_name) {
|
||||
if (descriptors().count("proto2.DescriptorProto") == 0) {
|
||||
RegisterDescriptorProtos(descriptors());
|
||||
}
|
||||
absl::ReaderMutexLock lock(&mutex());
|
||||
auto it = descriptors().find(CanonicalTypeName(type_name));
|
||||
return (it == descriptors().end()) ? nullptr : &it->second;
|
||||
@@ -73,11 +176,21 @@ absl::Mutex& OptionsRegistry::mutex() {
|
||||
return *mutex;
|
||||
}
|
||||
|
||||
Descriptor::Descriptor(const proto_ns::DescriptorProto& proto,
|
||||
const std::string& full_name)
|
||||
Descriptor::Descriptor(const std::string& full_name,
|
||||
const FieldData& descriptor_proto)
|
||||
: full_name_(full_name) {
|
||||
for (auto& field : proto.field()) {
|
||||
fields_[field.name()] = FieldDescriptor(field);
|
||||
auto fields = GetFieldValues(descriptor_proto, "field");
|
||||
for (const auto& field : *fields) {
|
||||
FieldDescriptor f(field);
|
||||
fields_[f.name()] = f;
|
||||
}
|
||||
}
|
||||
|
||||
Descriptor::Descriptor(const std::string& full_name,
|
||||
const std::vector<FieldDescriptor>& fields)
|
||||
: full_name_(full_name) {
|
||||
for (const auto& field : fields) {
|
||||
fields_[field.name()] = field;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,20 +202,22 @@ const FieldDescriptor* Descriptor::FindFieldByName(
|
||||
return (it != fields_.end()) ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
FieldDescriptor::FieldDescriptor(const proto_ns::FieldDescriptorProto& proto) {
|
||||
name_ = proto.name();
|
||||
message_type_ = CanonicalTypeName(proto.type_name());
|
||||
type_ = proto.type();
|
||||
number_ = proto.number();
|
||||
FieldDescriptor::FieldDescriptor(const FieldData& field_proto) {
|
||||
name_ = GetFieldString(field_proto, "name");
|
||||
number_ = GetFieldValues(field_proto, "number")->front().int32_value();
|
||||
type_ = (FieldType)GetFieldValues(field_proto, "type")->front().enum_value();
|
||||
message_type_ = CanonicalTypeName(GetFieldString(field_proto, "type_name"));
|
||||
}
|
||||
|
||||
FieldDescriptor::FieldDescriptor(std::string name, int number, FieldType type,
|
||||
std::string message_type)
|
||||
: name_(name), number_(number), type_(type), message_type_(message_type) {}
|
||||
|
||||
const std::string& FieldDescriptor::name() const { return name_; }
|
||||
|
||||
int FieldDescriptor::number() const { return number_; }
|
||||
|
||||
proto_ns::FieldDescriptorProto::Type FieldDescriptor::type() const {
|
||||
return type_;
|
||||
}
|
||||
FieldType FieldDescriptor::type() const { return type_; }
|
||||
|
||||
const Descriptor* FieldDescriptor::message_type() const {
|
||||
return OptionsRegistry::GetProtobufDescriptor(message_type_);
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
#ifndef MEDIAPIPE_FRAMEWORK_TOOL_OPTIONS_REGISTRY_H_
|
||||
#define MEDIAPIPE_FRAMEWORK_TOOL_OPTIONS_REGISTRY_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "mediapipe/framework/deps/registration.h"
|
||||
#include "mediapipe/framework/port/advanced_proto_inc.h"
|
||||
#include "mediapipe/framework/tool/field_data.pb.h"
|
||||
|
||||
namespace mediapipe {
|
||||
namespace tool {
|
||||
|
||||
class Descriptor;
|
||||
class FieldDescriptor;
|
||||
using FieldType = mediapipe::proto_ns::internal::WireFormatLite::FieldType;
|
||||
using mediapipe::FieldData;
|
||||
|
||||
// A static registry that stores descriptors for protobufs used in MediaPipe
|
||||
// calculator options. Lite-proto builds do not normally include descriptors.
|
||||
@@ -17,8 +22,8 @@ class FieldDescriptor;
|
||||
// referenced and specified separately within CalculatorGraphConfigs.
|
||||
class OptionsRegistry {
|
||||
public:
|
||||
// Registers the protobuf descriptors for a MessageLite.
|
||||
static RegistrationToken Register(const proto_ns::FileDescriptorSet& files);
|
||||
// Registers the protobuf descriptors for a FileDescriptorSet.
|
||||
static RegistrationToken Register(const FieldData& file_descriptor_set);
|
||||
|
||||
// Finds the descriptor for a protobuf.
|
||||
static const Descriptor* GetProtobufDescriptor(const std::string& type_name);
|
||||
@@ -28,8 +33,8 @@ class OptionsRegistry {
|
||||
std::vector<const FieldDescriptor*>* result);
|
||||
|
||||
private:
|
||||
// Registers protobuf descriptors a MessageLite and nested types.
|
||||
static void Register(const proto_ns::DescriptorProto& message_type,
|
||||
// Registers protobuf descriptors for a message type and nested types.
|
||||
static void Register(const FieldData& message_type,
|
||||
const std::string& parent_name);
|
||||
|
||||
static absl::flat_hash_map<std::string, Descriptor>& descriptors();
|
||||
@@ -46,9 +51,10 @@ class OptionsRegistry {
|
||||
// avoids a code size problem introduced by proto_ns::FieldDescriptor.
|
||||
class Descriptor {
|
||||
public:
|
||||
Descriptor() {}
|
||||
Descriptor(const proto_ns::DescriptorProto& proto,
|
||||
const std::string& full_name);
|
||||
Descriptor() = default;
|
||||
Descriptor(const std::string& full_name, const FieldData& descriptor_proto);
|
||||
Descriptor(const std::string& full_name,
|
||||
const std::vector<FieldDescriptor>& fields);
|
||||
const std::string& full_name() const;
|
||||
const FieldDescriptor* FindFieldByName(const std::string& name) const;
|
||||
|
||||
@@ -61,18 +67,20 @@ class Descriptor {
|
||||
// avoids a code size problem introduced by proto_ns::FieldDescriptor.
|
||||
class FieldDescriptor {
|
||||
public:
|
||||
FieldDescriptor() {}
|
||||
FieldDescriptor(const proto_ns::FieldDescriptorProto& proto);
|
||||
FieldDescriptor() = default;
|
||||
FieldDescriptor(const FieldData& field_proto);
|
||||
FieldDescriptor(std::string name, int number, FieldType type,
|
||||
std::string message_type);
|
||||
const std::string& name() const;
|
||||
int number() const;
|
||||
proto_ns::FieldDescriptorProto::Type type() const;
|
||||
FieldType type() const;
|
||||
const Descriptor* message_type() const;
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::string message_type_;
|
||||
proto_ns::FieldDescriptorProto::Type type_;
|
||||
int number_;
|
||||
FieldType type_;
|
||||
std::string message_type_;
|
||||
};
|
||||
|
||||
} // namespace tool
|
||||
|
||||
@@ -91,8 +91,7 @@ class OptionsSyntaxUtil::OptionsSyntaxHelper {
|
||||
int index;
|
||||
if (absl::SimpleAtoi(option_name, &index)) {
|
||||
result.back().index = index;
|
||||
}
|
||||
if (!ExtensionType(option_name).empty()) {
|
||||
} else if (!ExtensionType(option_name).empty()) {
|
||||
std::string extension_type = std::string(ExtensionType(option_name));
|
||||
result.push_back({nullptr, 0, extension_type});
|
||||
descriptor = OptionsRegistry::GetProtobufDescriptor(extension_type);
|
||||
@@ -102,7 +101,7 @@ class OptionsSyntaxUtil::OptionsSyntaxHelper {
|
||||
}
|
||||
auto field = descriptor->FindFieldByName(std::string(option_name));
|
||||
descriptor = field ? field->message_type() : nullptr;
|
||||
result.push_back({std::move(field), 0});
|
||||
result.push_back({std::move(field), -1});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -26,10 +26,9 @@ namespace mediapipe {
|
||||
namespace tool {
|
||||
|
||||
using options_field_util::FieldPath;
|
||||
using options_field_util::GetField;
|
||||
using options_field_util::GetGraphOptions;
|
||||
using options_field_util::GetNodeOptions;
|
||||
using options_field_util::MergeField;
|
||||
using options_field_util::MergeFieldValues;
|
||||
using options_field_util::MergeMessages;
|
||||
|
||||
// Returns the type for the root options message if specified.
|
||||
@@ -56,10 +55,19 @@ std::string MessageType(FieldData message) {
|
||||
std::string(message.message_value().type_url()));
|
||||
}
|
||||
|
||||
// Assigns the value from a StatusOr if avialable.
|
||||
#define ASSIGN_IF_OK(lhs, rexpr) \
|
||||
{ \
|
||||
auto statusor = (rexpr); \
|
||||
if (statusor.ok()) { \
|
||||
lhs = statusor.value(); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Copy literal options from graph_options to node_options.
|
||||
absl::Status CopyLiteralOptions(CalculatorGraphConfig::Node parent_node,
|
||||
CalculatorGraphConfig* config) {
|
||||
Status status;
|
||||
absl::Status status;
|
||||
FieldData graph_data = options_field_util::AsFieldData(*config);
|
||||
FieldData parent_data = options_field_util::AsFieldData(parent_node);
|
||||
|
||||
@@ -75,25 +83,26 @@ absl::Status CopyLiteralOptions(CalculatorGraphConfig::Node parent_node,
|
||||
std::string node_tag = syntax_util.OptionFieldsTag(tag_and_name[0]);
|
||||
std::string node_extension_type = ExtensionType(node_tag);
|
||||
FieldData graph_options;
|
||||
GetGraphOptions(graph_data, graph_extension_type, &graph_options)
|
||||
.IgnoreError();
|
||||
ASSIGN_IF_OK(graph_options,
|
||||
GetGraphOptions(graph_data, graph_extension_type));
|
||||
FieldData parent_options;
|
||||
GetNodeOptions(parent_data, graph_extension_type, &parent_options)
|
||||
.IgnoreError();
|
||||
status.Update(
|
||||
MergeMessages(graph_options, parent_options, &graph_options));
|
||||
ASSIGN_IF_OK(parent_options,
|
||||
GetNodeOptions(parent_data, graph_extension_type));
|
||||
ASSIGN_OR_RETURN(graph_options,
|
||||
MergeMessages(graph_options, parent_options));
|
||||
FieldData node_options;
|
||||
status.Update(
|
||||
GetNodeOptions(node_data, node_extension_type, &node_options));
|
||||
ASSIGN_OR_RETURN(node_options,
|
||||
GetNodeOptions(node_data, node_extension_type));
|
||||
if (!node_options.has_message_value() ||
|
||||
!graph_options.has_message_value()) {
|
||||
continue;
|
||||
}
|
||||
FieldPath graph_path = GetPath(graph_tag, MessageType(graph_options));
|
||||
FieldPath node_path = GetPath(node_tag, MessageType(node_options));
|
||||
FieldData packet_data;
|
||||
status.Update(GetField(graph_path, graph_options, &packet_data));
|
||||
status.Update(MergeField(node_path, packet_data, &node_options));
|
||||
std::vector<FieldData> packet_data;
|
||||
ASSIGN_OR_RETURN(packet_data, GetFieldValues(graph_options, graph_path));
|
||||
MP_RETURN_IF_ERROR(
|
||||
MergeFieldValues(node_options, node_path, packet_data));
|
||||
options_field_util::SetOptionsMessage(node_options, &node);
|
||||
}
|
||||
node.clear_option_value();
|
||||
@@ -105,7 +114,7 @@ absl::Status CopyLiteralOptions(CalculatorGraphConfig::Node parent_node,
|
||||
absl::Status DefineGraphOptions(const CalculatorGraphConfig::Node& parent_node,
|
||||
CalculatorGraphConfig* config) {
|
||||
MP_RETURN_IF_ERROR(CopyLiteralOptions(parent_node, config));
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace tool
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "mediapipe/framework/calculator_framework.h"
|
||||
#include "mediapipe/framework/port/gmock.h"
|
||||
@@ -30,23 +32,27 @@
|
||||
namespace mediapipe {
|
||||
namespace {
|
||||
|
||||
using ::mediapipe::proto_ns::FieldDescriptorProto;
|
||||
using FieldType = ::mediapipe::proto_ns::FieldDescriptorProto::Type;
|
||||
using ::testing::HasSubstr;
|
||||
|
||||
// Assigns the value from a StatusOr if avialable.
|
||||
#define ASSERT_AND_ASSIGN(lhs, rexpr) \
|
||||
{ \
|
||||
auto statusor = (rexpr); \
|
||||
MP_ASSERT_OK(statusor); \
|
||||
lhs = statusor.value(); \
|
||||
}
|
||||
|
||||
// A test Calculator using DeclareOptions and DefineOptions.
|
||||
class NightLightCalculator : public CalculatorBase {
|
||||
public:
|
||||
static absl::Status GetContract(CalculatorContract* cc) {
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Open(CalculatorContext* cc) final {
|
||||
return mediapipe::OkStatus();
|
||||
}
|
||||
absl::Status Open(CalculatorContext* cc) final { return absl::OkStatus(); }
|
||||
|
||||
absl::Status Process(CalculatorContext* cc) final {
|
||||
return mediapipe::OkStatus();
|
||||
}
|
||||
absl::Status Process(CalculatorContext* cc) final { return absl::OkStatus(); }
|
||||
|
||||
private:
|
||||
NightLightCalculatorOptions options_;
|
||||
@@ -124,7 +130,7 @@ TEST_F(OptionsUtilTest, CopyLiteralOptions) {
|
||||
|
||||
CalculatorGraph graph;
|
||||
graph_config.set_num_threads(4);
|
||||
MP_EXPECT_OK(graph.Initialize({subgraph_config, graph_config}, {}, {}));
|
||||
MP_ASSERT_OK(graph.Initialize({subgraph_config, graph_config}, {}, {}));
|
||||
|
||||
CalculatorGraphConfig expanded_config = graph.Config();
|
||||
expanded_config.clear_executor();
|
||||
@@ -236,8 +242,8 @@ TEST_F(OptionsUtilTest, FindOptionsMessage) {
|
||||
tool::options_field_util::FieldPath field_path =
|
||||
syntax_util.OptionFieldPath(split[1], descriptor);
|
||||
EXPECT_EQ(field_path.size(), 2);
|
||||
EXPECT_TRUE(Equals(field_path[0], "sub_options", 0, ""));
|
||||
EXPECT_TRUE(Equals(field_path[1], "num_lights", 0, ""));
|
||||
EXPECT_TRUE(Equals(field_path[0], "sub_options", -1, ""));
|
||||
EXPECT_TRUE(Equals(field_path[1], "num_lights", -1, ""));
|
||||
|
||||
{
|
||||
// NightLightCalculatorOptions in Node.options.
|
||||
@@ -252,11 +258,11 @@ TEST_F(OptionsUtilTest, FindOptionsMessage) {
|
||||
auto path = field_path;
|
||||
std::string node_extension_type = ExtensionType(std::string(split[1]));
|
||||
FieldData node_options;
|
||||
MP_EXPECT_OK(tool::options_field_util::GetNodeOptions(
|
||||
node_data, node_extension_type, &node_options));
|
||||
ASSERT_AND_ASSIGN(node_options, tool::options_field_util::GetNodeOptions(
|
||||
node_data, node_extension_type));
|
||||
FieldData packet_data;
|
||||
MP_EXPECT_OK(tool::options_field_util::GetField(field_path, node_options,
|
||||
&packet_data));
|
||||
ASSERT_AND_ASSIGN(packet_data, tool::options_field_util::GetField(
|
||||
node_options, field_path));
|
||||
EXPECT_EQ(packet_data.value_case(), FieldData::kInt32Value);
|
||||
EXPECT_EQ(packet_data.int32_value(), 33);
|
||||
}
|
||||
@@ -273,11 +279,11 @@ TEST_F(OptionsUtilTest, FindOptionsMessage) {
|
||||
auto path = field_path;
|
||||
std::string node_extension_type = ExtensionType(std::string(split[1]));
|
||||
FieldData node_options;
|
||||
MP_EXPECT_OK(tool::options_field_util::GetNodeOptions(
|
||||
node_data, node_extension_type, &node_options));
|
||||
ASSERT_AND_ASSIGN(node_options, tool::options_field_util::GetNodeOptions(
|
||||
node_data, node_extension_type));
|
||||
FieldData packet_data;
|
||||
MP_EXPECT_OK(tool::options_field_util::GetField(field_path, node_options,
|
||||
&packet_data));
|
||||
ASSERT_AND_ASSIGN(packet_data, tool::options_field_util::GetField(
|
||||
node_options, field_path));
|
||||
EXPECT_EQ(packet_data.value_case(), FieldData::kInt32Value);
|
||||
EXPECT_EQ(packet_data.int32_value(), 33);
|
||||
}
|
||||
@@ -285,5 +291,333 @@ TEST_F(OptionsUtilTest, FindOptionsMessage) {
|
||||
// TODO: Test with specified extension_type.
|
||||
}
|
||||
|
||||
// Constructs the field path for a string of field names.
|
||||
FieldPath MakeFieldPath(std::string tag, FieldData message_data) {
|
||||
tool::OptionsSyntaxUtil syntax_util;
|
||||
const tool::Descriptor* descriptor =
|
||||
tool::OptionsRegistry::GetProtobufDescriptor(
|
||||
tool::options_field_util::ParseTypeUrl(
|
||||
message_data.message_value().type_url()));
|
||||
return syntax_util.OptionFieldPath(tag, descriptor);
|
||||
}
|
||||
|
||||
// Returns the field path addressing the entire specified field.
|
||||
FieldPath EntireField(FieldPath field_path) {
|
||||
field_path.back().index = -1;
|
||||
return field_path;
|
||||
}
|
||||
|
||||
// Converts an int to a FieldData record.
|
||||
FieldData AsFieldData(int v) {
|
||||
return tool::options_field_util::AsFieldData(MakePacket<int>(v)).value();
|
||||
}
|
||||
|
||||
// Equality comparison for field contents.
|
||||
template <typename T>
|
||||
absl::Status Equals(const T& v1, const T& v2) {
|
||||
RET_CHECK_EQ(v1, v2);
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Equality comparison for protobuf field contents.
|
||||
// The generic Equals() fails because MessageLite lacks operator==().
|
||||
// The protobuf comparison is performed using testing::EqualsProto.
|
||||
using LightBundle = NightLightCalculatorOptions::LightBundle;
|
||||
template <>
|
||||
absl::Status Equals<LightBundle>(const LightBundle& v1, const LightBundle& v2) {
|
||||
std::string s_1, s_2;
|
||||
v1.SerializeToString(&s_1);
|
||||
v2.SerializeToString(&s_2);
|
||||
RET_CHECK(s_1 == s_2);
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Equality comparison for FieldData vectors.
|
||||
template <typename FieldType>
|
||||
absl::Status Equals(std::vector<FieldData> b1, std::vector<FieldData> b2) {
|
||||
using tool::options_field_util::AsPacket;
|
||||
RET_CHECK_EQ(b1.size(), b2.size());
|
||||
for (int i = 0; i < b1.size(); ++i) {
|
||||
ASSIGN_OR_RETURN(Packet p1, AsPacket(b1.at(i)));
|
||||
ASSIGN_OR_RETURN(Packet p2, AsPacket(b2.at(i)));
|
||||
MP_RETURN_IF_ERROR(Equals(p1.Get<FieldType>(), p2.Get<FieldType>()));
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Unit-tests for graph options feild accessors from options_field_util.
|
||||
class OptionsFieldUtilTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {}
|
||||
void TearDown() override {}
|
||||
};
|
||||
|
||||
// Tests empty FieldPaths applied to empty options.
|
||||
TEST_F(OptionsFieldUtilTest, EmptyFieldPaths) {
|
||||
FieldData graph_options;
|
||||
FieldData node_options;
|
||||
FieldPath graph_path;
|
||||
FieldPath node_path;
|
||||
std::vector<FieldData> packet_data;
|
||||
ASSERT_AND_ASSIGN(packet_data, GetFieldValues(graph_options, graph_path));
|
||||
MP_EXPECT_OK(MergeFieldValues(node_options, node_path, packet_data));
|
||||
}
|
||||
|
||||
// Tests GetFieldValues applied to an int field.
|
||||
TEST_F(OptionsFieldUtilTest, GetFieldValuesInt) {
|
||||
NightLightCalculatorOptions node_proto;
|
||||
node_proto.mutable_sub_options();
|
||||
node_proto.mutable_sub_options()->add_num_lights(33);
|
||||
node_proto.mutable_sub_options()->add_num_lights(44);
|
||||
FieldData node_data = tool::options_field_util::AsFieldData(node_proto);
|
||||
|
||||
// Read an entire populated repeated field.
|
||||
FieldPath path = MakeFieldPath("OPTIONS/sub_options/num_lights", node_data);
|
||||
MP_EXPECT_OK(Equals<int>(GetFieldValues(node_data, path).value(),
|
||||
{AsFieldData(33), AsFieldData(44)}));
|
||||
|
||||
// Read a specific populated repeated field index.
|
||||
path = MakeFieldPath("OPTIONS/sub_options/num_lights/1", node_data);
|
||||
MP_EXPECT_OK(
|
||||
Equals<int>(GetFieldValues(node_data, path).value(), {AsFieldData(44)}));
|
||||
}
|
||||
|
||||
// Tests GetFieldValues applied to a protobuf field.
|
||||
TEST_F(OptionsFieldUtilTest, GetFieldValuesProtobuf) {
|
||||
using tool::options_field_util::AsFieldData;
|
||||
using LightBundle = NightLightCalculatorOptions::LightBundle;
|
||||
NightLightCalculatorOptions node_proto;
|
||||
node_proto.mutable_sub_options();
|
||||
node_proto.mutable_sub_options()->add_bundle();
|
||||
*node_proto.mutable_sub_options()->mutable_bundle(0)->mutable_room_id() =
|
||||
"111";
|
||||
node_proto.mutable_sub_options()
|
||||
->mutable_bundle(0)
|
||||
->add_room_lights()
|
||||
->set_frame_rate(11.1);
|
||||
node_proto.mutable_sub_options()
|
||||
->mutable_bundle(0)
|
||||
->add_room_lights()
|
||||
->set_frame_rate(22.1);
|
||||
FieldData node_data = AsFieldData(node_proto);
|
||||
|
||||
// Read all values from a repeated protobuf field.
|
||||
LightBundle expected_proto;
|
||||
*expected_proto.mutable_room_id() = "111";
|
||||
expected_proto.add_room_lights()->set_frame_rate(11.1);
|
||||
expected_proto.add_room_lights()->set_frame_rate(22.1);
|
||||
FieldData expected_data = AsFieldData(expected_proto);
|
||||
FieldPath path = MakeFieldPath("OPTIONS/sub_options/bundle", node_data);
|
||||
MP_EXPECT_OK(Equals<LightBundle>(GetFieldValues(node_data, path).value(),
|
||||
{expected_data}));
|
||||
|
||||
// Read a specific index from a repeated protobuf field.
|
||||
path = MakeFieldPath("OPTIONS/sub_options/bundle/0", node_data);
|
||||
MP_EXPECT_OK(Equals<LightBundle>(GetFieldValues(node_data, path).value(),
|
||||
{expected_data}));
|
||||
}
|
||||
|
||||
// Tests SetFieldValues applied to an int field.
|
||||
TEST_F(OptionsFieldUtilTest, SetFieldValuesInt) {
|
||||
NightLightCalculatorOptions node_proto;
|
||||
node_proto.mutable_sub_options();
|
||||
FieldData node_data = tool::options_field_util::AsFieldData(node_proto);
|
||||
|
||||
// Replace an entire empty repeated field.
|
||||
FieldPath path = MakeFieldPath("OPTIONS/sub_options/num_lights", node_data);
|
||||
MP_ASSERT_OK(SetFieldValues(node_data, path, {AsFieldData(33)}));
|
||||
MP_EXPECT_OK(
|
||||
Equals<int>(GetFieldValues(node_data, path).value(), {AsFieldData(33)}));
|
||||
|
||||
// Replace an entire populated repeated field.
|
||||
MP_ASSERT_OK(SetFieldValues(node_data, path, {AsFieldData(44)}));
|
||||
MP_EXPECT_OK(
|
||||
Equals<int>(GetFieldValues(node_data, path).value(), {AsFieldData(44)}));
|
||||
|
||||
// Replace an entire repeated field with a new list of values.
|
||||
MP_ASSERT_OK(
|
||||
SetFieldValues(node_data, path, {AsFieldData(33), AsFieldData(44)}));
|
||||
MP_EXPECT_OK(Equals<int>(GetFieldValues(node_data, path).value(),
|
||||
{AsFieldData(33), AsFieldData(44)}));
|
||||
|
||||
// Replace a single field index with a new list of values.
|
||||
path = MakeFieldPath("OPTIONS/sub_options/num_lights/1", node_data);
|
||||
MP_ASSERT_OK(
|
||||
SetFieldValues(node_data, path, {AsFieldData(55), AsFieldData(66)}));
|
||||
MP_EXPECT_OK(
|
||||
Equals<int>(GetFieldValues(node_data, EntireField(path)).value(),
|
||||
{AsFieldData(33), AsFieldData(55), AsFieldData(66)}));
|
||||
|
||||
// Replace a single field middle index with a new list of values.
|
||||
path = MakeFieldPath("OPTIONS/sub_options/num_lights/1", node_data);
|
||||
MP_ASSERT_OK(
|
||||
SetFieldValues(node_data, path, {AsFieldData(11), AsFieldData(12)}));
|
||||
MP_EXPECT_OK(Equals<int>(
|
||||
GetFieldValues(node_data, EntireField(path)).value(),
|
||||
{AsFieldData(33), AsFieldData(11), AsFieldData(12), AsFieldData(66)}));
|
||||
|
||||
// Replace field index 0 with a new value.
|
||||
path = MakeFieldPath("OPTIONS/sub_options/num_lights/0", node_data);
|
||||
MP_ASSERT_OK(SetFieldValues(node_data, path, {AsFieldData(77)}));
|
||||
MP_EXPECT_OK(Equals<int>(
|
||||
GetFieldValues(node_data, EntireField(path)).value(),
|
||||
{AsFieldData(77), AsFieldData(11), AsFieldData(12), AsFieldData(66)}));
|
||||
|
||||
// Replace field index 0 with an empty list of values.
|
||||
MP_ASSERT_OK(SetFieldValues(node_data, path, {}));
|
||||
MP_EXPECT_OK(
|
||||
Equals<int>(GetFieldValues(node_data, EntireField(path)).value(),
|
||||
{AsFieldData(11), AsFieldData(12), AsFieldData(66)}));
|
||||
|
||||
// Replace an entire populated field with an empty list of values.
|
||||
path = MakeFieldPath("OPTIONS/sub_options/num_lights", node_data);
|
||||
MP_ASSERT_OK(SetFieldValues(node_data, path, {}));
|
||||
MP_ASSERT_OK(
|
||||
Equals<int>(GetFieldValues(node_data, EntireField(path)).value(), {}));
|
||||
|
||||
// Replace a missing field index with new values.
|
||||
path = MakeFieldPath("OPTIONS/sub_options/num_lights/1", node_data);
|
||||
absl::Status status =
|
||||
SetFieldValues(node_data, path, {AsFieldData(55), AsFieldData(66)});
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInternal);
|
||||
// TODO: status.message() appears empty on KokoroGCPDocker.
|
||||
// EXPECT_THAT(status.message(),
|
||||
// HasSubstr("index >= 0 && index <= v.size()"));
|
||||
}
|
||||
|
||||
// Tests SetFieldValues applied to a protobuf field.
|
||||
TEST_F(OptionsFieldUtilTest, SetFieldValuesProtobuf) {
|
||||
using tool::options_field_util::AsFieldData;
|
||||
using LightBundle = NightLightCalculatorOptions::LightBundle;
|
||||
NightLightCalculatorOptions node_proto;
|
||||
node_proto.mutable_sub_options();
|
||||
FieldData node_data = AsFieldData(node_proto);
|
||||
|
||||
// Replace an empty repeated protobuf field.
|
||||
LightBundle bundle_proto;
|
||||
*bundle_proto.mutable_room_id() = "222";
|
||||
bundle_proto.add_room_lights()->set_frame_rate(22.1);
|
||||
FieldData bundle_data = AsFieldData(bundle_proto);
|
||||
FieldData expected_data = bundle_data;
|
||||
FieldPath path = MakeFieldPath("OPTIONS/sub_options/bundle", node_data);
|
||||
MP_ASSERT_OK(SetFieldValues(node_data, path, {bundle_data}));
|
||||
MP_EXPECT_OK(Equals<LightBundle>(
|
||||
GetFieldValues(node_data, EntireField(path)).value(), {expected_data}));
|
||||
|
||||
// Replace a populated repeated protobuf field.
|
||||
*bundle_proto.mutable_room_id() = "333";
|
||||
bundle_proto.mutable_room_lights(0)->set_frame_rate(33.1);
|
||||
bundle_data = AsFieldData(bundle_proto);
|
||||
LightBundle expected_proto;
|
||||
*expected_proto.mutable_room_id() = "333";
|
||||
expected_proto.add_room_lights()->set_frame_rate(33.1);
|
||||
expected_data = AsFieldData(expected_proto);
|
||||
MP_ASSERT_OK(SetFieldValues(node_data, path, {bundle_data}));
|
||||
MP_EXPECT_OK(Equals<LightBundle>(
|
||||
GetFieldValues(node_data, EntireField(path)).value(), {expected_data}));
|
||||
}
|
||||
|
||||
// Tests MergeFieldValues applied to an int field.
|
||||
TEST_F(OptionsFieldUtilTest, MergeFieldValuesInt) {
|
||||
NightLightCalculatorOptions node_proto;
|
||||
node_proto.mutable_sub_options();
|
||||
FieldData node_data = tool::options_field_util::AsFieldData(node_proto);
|
||||
|
||||
// Replace an entire empty repeated field.
|
||||
FieldPath path = MakeFieldPath("OPTIONS/sub_options/num_lights", node_data);
|
||||
MP_ASSERT_OK(MergeFieldValues(node_data, path, {AsFieldData(33)}));
|
||||
MP_EXPECT_OK(
|
||||
Equals<int>(GetFieldValues(node_data, path).value(), {AsFieldData(33)}));
|
||||
|
||||
// Replace an entire populated repeated field.
|
||||
MP_ASSERT_OK(MergeFieldValues(node_data, path, {AsFieldData(44)}));
|
||||
MP_EXPECT_OK(
|
||||
Equals<int>(GetFieldValues(node_data, path).value(), {AsFieldData(44)}));
|
||||
|
||||
// Replace an entire repeated field with a new list of values.
|
||||
MP_ASSERT_OK(
|
||||
MergeFieldValues(node_data, path, {AsFieldData(33), AsFieldData(44)}));
|
||||
MP_EXPECT_OK(Equals<int>(GetFieldValues(node_data, path).value(),
|
||||
{AsFieldData(33), AsFieldData(44)}));
|
||||
|
||||
// Replace a singe field index with a new list of values.
|
||||
path = MakeFieldPath("OPTIONS/sub_options/num_lights/1", node_data);
|
||||
MP_ASSERT_OK(
|
||||
MergeFieldValues(node_data, path, {AsFieldData(55), AsFieldData(66)}));
|
||||
MP_EXPECT_OK(
|
||||
Equals<int>(GetFieldValues(node_data, EntireField(path)).value(),
|
||||
{AsFieldData(33), AsFieldData(55), AsFieldData(66)}));
|
||||
|
||||
// Replace a single field middle index with a new list of values.
|
||||
path = MakeFieldPath("OPTIONS/sub_options/num_lights/1", node_data);
|
||||
MP_ASSERT_OK(
|
||||
MergeFieldValues(node_data, path, {AsFieldData(11), AsFieldData(12)}));
|
||||
MP_EXPECT_OK(Equals<int>(
|
||||
GetFieldValues(node_data, EntireField(path)).value(),
|
||||
{AsFieldData(33), AsFieldData(11), AsFieldData(12), AsFieldData(66)}));
|
||||
|
||||
// Replace field index 0 with a new value.
|
||||
path = MakeFieldPath("OPTIONS/sub_options/num_lights/0", node_data);
|
||||
MP_ASSERT_OK(MergeFieldValues(node_data, path, {AsFieldData(77)}));
|
||||
MP_EXPECT_OK(Equals<int>(
|
||||
GetFieldValues(node_data, EntireField(path)).value(),
|
||||
{AsFieldData(77), AsFieldData(11), AsFieldData(12), AsFieldData(66)}));
|
||||
|
||||
// Replace field index 0 with an empty list of values.
|
||||
MP_ASSERT_OK(MergeFieldValues(node_data, path, {}));
|
||||
MP_EXPECT_OK(
|
||||
Equals<int>(GetFieldValues(node_data, EntireField(path)).value(),
|
||||
{AsFieldData(11), AsFieldData(12), AsFieldData(66)}));
|
||||
|
||||
// Replace an entire populated field with an empty list of values.
|
||||
path = MakeFieldPath("OPTIONS/sub_options/num_lights", node_data);
|
||||
MP_ASSERT_OK(MergeFieldValues(node_data, path, {}));
|
||||
MP_EXPECT_OK(
|
||||
Equals<int>(GetFieldValues(node_data, EntireField(path)).value(), {}));
|
||||
|
||||
// Replace a missing field index with new values.
|
||||
path = MakeFieldPath("OPTIONS/sub_options/num_lights/1", node_data);
|
||||
absl::Status status =
|
||||
MergeFieldValues(node_data, path, {AsFieldData(55), AsFieldData(66)});
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kOutOfRange);
|
||||
EXPECT_THAT(status.message(),
|
||||
HasSubstr("Missing feild value: num_lights at index: 1"));
|
||||
}
|
||||
|
||||
// Tests MergeFieldValues applied to a protobuf field.
|
||||
TEST_F(OptionsFieldUtilTest, MergeFieldValuesProtobuf) {
|
||||
using tool::options_field_util::AsFieldData;
|
||||
using LightBundle = NightLightCalculatorOptions::LightBundle;
|
||||
NightLightCalculatorOptions node_proto;
|
||||
node_proto.mutable_sub_options();
|
||||
FieldData node_data = AsFieldData(node_proto);
|
||||
|
||||
// Merge an empty repeated protobuf field.
|
||||
LightBundle bundle_proto;
|
||||
*bundle_proto.mutable_room_id() = "222";
|
||||
bundle_proto.add_room_lights()->set_frame_rate(22.1);
|
||||
FieldData bundle_data = AsFieldData(bundle_proto);
|
||||
FieldData expected_data = bundle_data;
|
||||
FieldPath path = MakeFieldPath("OPTIONS/sub_options/bundle", node_data);
|
||||
MP_ASSERT_OK(MergeFieldValues(node_data, path, {bundle_data}));
|
||||
MP_EXPECT_OK(Equals<LightBundle>(
|
||||
GetFieldValues(node_data, EntireField(path)).value(), {expected_data}));
|
||||
|
||||
// Merge a populated repeated protobuf field.
|
||||
// "LightBundle.room_id" merges to "333".
|
||||
// "LightBundle.room_lights" merges to {{22.1}, {33.1}}.
|
||||
*bundle_proto.mutable_room_id() = "333";
|
||||
bundle_proto.mutable_room_lights(0)->set_frame_rate(33.1);
|
||||
bundle_data = AsFieldData(bundle_proto);
|
||||
LightBundle expected_proto;
|
||||
*expected_proto.mutable_room_id() = "333";
|
||||
expected_proto.add_room_lights()->set_frame_rate(22.1);
|
||||
expected_proto.add_room_lights()->set_frame_rate(33.1);
|
||||
expected_data = AsFieldData(expected_proto);
|
||||
MP_ASSERT_OK(MergeFieldValues(node_data, path, {bundle_data}));
|
||||
MP_EXPECT_OK(Equals<LightBundle>(
|
||||
GetFieldValues(node_data, EntireField(path)).value(), {expected_data}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/strings/numbers.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "mediapipe/framework/port/canonical_errors.h"
|
||||
#include "mediapipe/framework/port/logging.h"
|
||||
#include "mediapipe/framework/port/ret_check.h"
|
||||
#include "mediapipe/framework/tool/field_data.pb.h"
|
||||
#include "mediapipe/framework/type_map.h"
|
||||
|
||||
#define RET_CHECK_NO_LOG(cond) RET_CHECK(cond).SetNoLogging()
|
||||
@@ -37,6 +39,7 @@ using FieldAccess = ProtoUtilLite::FieldAccess;
|
||||
using FieldValue = ProtoUtilLite::FieldValue;
|
||||
using ProtoPath = ProtoUtilLite::ProtoPath;
|
||||
using FieldType = ProtoUtilLite::FieldType;
|
||||
using mediapipe::FieldData;
|
||||
|
||||
// Returns true if a wire type includes a length indicator.
|
||||
bool IsLengthDelimited(WireFormatLite::WireType wire_type) {
|
||||
@@ -408,5 +411,149 @@ absl::Status ProtoUtilLite::Deserialize(
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status ProtoUtilLite::WriteValue(const FieldData& value,
|
||||
FieldType field_type,
|
||||
std::string* field_bytes) {
|
||||
StringOutputStream sos(field_bytes);
|
||||
CodedOutputStream out(&sos);
|
||||
switch (field_type) {
|
||||
case WireFormatLite::TYPE_INT32:
|
||||
WireFormatLite::WriteInt32NoTag(value.int32_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_SINT32:
|
||||
WireFormatLite::WriteSInt32NoTag(value.int32_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_INT64:
|
||||
WireFormatLite::WriteInt64NoTag(value.int64_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_SINT64:
|
||||
WireFormatLite::WriteSInt64NoTag(value.int64_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_UINT32:
|
||||
WireFormatLite::WriteUInt32NoTag(value.uint32_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_UINT64:
|
||||
WireFormatLite::WriteUInt64NoTag(value.uint64_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_DOUBLE:
|
||||
WireFormatLite::WriteDoubleNoTag(value.uint64_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_FLOAT:
|
||||
WireFormatLite::WriteFloatNoTag(value.float_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_BOOL:
|
||||
WireFormatLite::WriteBoolNoTag(value.bool_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_ENUM:
|
||||
WireFormatLite::WriteEnumNoTag(value.enum_value(), &out);
|
||||
break;
|
||||
case WireFormatLite::TYPE_STRING:
|
||||
out.WriteString(value.string_value());
|
||||
break;
|
||||
case WireFormatLite::TYPE_MESSAGE:
|
||||
out.WriteString(value.message_value().value());
|
||||
break;
|
||||
default:
|
||||
return absl::UnimplementedError(
|
||||
absl::StrCat("Cannot write type: ", field_type));
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
template <typename ValueT, FieldType kFieldType>
|
||||
static ValueT ReadValue(absl::string_view field_bytes, absl::Status* status) {
|
||||
ArrayInputStream ais(field_bytes.data(), field_bytes.size());
|
||||
CodedInputStream input(&ais);
|
||||
ValueT result;
|
||||
if (!WireFormatLite::ReadPrimitive<ValueT, kFieldType>(&input, &result)) {
|
||||
status->Update(absl::InvalidArgumentError(absl::StrCat(
|
||||
"Bad serialized value: ", MediaPipeTypeStringOrDemangled<ValueT>(),
|
||||
".")));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
absl::Status ReadValue(absl::string_view field_bytes, FieldType field_type,
|
||||
absl::string_view message_type, FieldData* result) {
|
||||
absl::Status status;
|
||||
result->Clear();
|
||||
switch (field_type) {
|
||||
case WireFormatLite::TYPE_INT32:
|
||||
result->set_int32_value(
|
||||
ReadValue<int32, WireFormatLite::TYPE_INT32>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_SINT32:
|
||||
result->set_int32_value(
|
||||
ReadValue<int32, WireFormatLite::TYPE_SINT32>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_INT64:
|
||||
result->set_int64_value(
|
||||
ReadValue<int64, WireFormatLite::TYPE_INT64>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_SINT64:
|
||||
result->set_int64_value(
|
||||
ReadValue<int64, WireFormatLite::TYPE_SINT64>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_UINT32:
|
||||
result->set_uint32_value(
|
||||
ReadValue<uint32, WireFormatLite::TYPE_UINT32>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_UINT64:
|
||||
result->set_uint64_value(
|
||||
ReadValue<uint32, WireFormatLite::TYPE_UINT32>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_DOUBLE:
|
||||
result->set_double_value(
|
||||
ReadValue<double, WireFormatLite::TYPE_DOUBLE>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_FLOAT:
|
||||
result->set_float_value(
|
||||
ReadValue<float, WireFormatLite::TYPE_FLOAT>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_BOOL:
|
||||
result->set_bool_value(
|
||||
ReadValue<bool, WireFormatLite::TYPE_BOOL>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_ENUM:
|
||||
result->set_enum_value(
|
||||
ReadValue<int32, WireFormatLite::TYPE_ENUM>(field_bytes, &status));
|
||||
break;
|
||||
case WireFormatLite::TYPE_STRING:
|
||||
result->set_string_value(std::string(field_bytes));
|
||||
break;
|
||||
case WireFormatLite::TYPE_MESSAGE:
|
||||
result->mutable_message_value()->set_value(std::string(field_bytes));
|
||||
result->mutable_message_value()->set_type_url(
|
||||
ProtoUtilLite::TypeUrl(message_type));
|
||||
break;
|
||||
default:
|
||||
status = absl::UnimplementedError(
|
||||
absl::StrCat("Cannot read type: ", field_type));
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
absl::Status ProtoUtilLite::ReadValue(absl::string_view field_bytes,
|
||||
FieldType field_type,
|
||||
absl::string_view message_type,
|
||||
FieldData* result) {
|
||||
return mediapipe::tool::ReadValue(field_bytes, field_type, message_type,
|
||||
result);
|
||||
}
|
||||
|
||||
std::string ProtoUtilLite::TypeUrl(absl::string_view type_name) {
|
||||
constexpr std::string_view kTypeUrlPrefix = "type.googleapis.com/";
|
||||
return absl::StrCat(std::string(kTypeUrlPrefix), std::string(type_name));
|
||||
}
|
||||
|
||||
std::string ProtoUtilLite::ParseTypeUrl(absl::string_view type_url) {
|
||||
constexpr std::string_view kTypeUrlPrefix = "type.googleapis.com/";
|
||||
if (absl::StartsWith(std::string(type_url), std::string(kTypeUrlPrefix))) {
|
||||
return std::string(type_url.substr(kTypeUrlPrefix.length()));
|
||||
}
|
||||
return std::string(type_url);
|
||||
}
|
||||
|
||||
} // namespace tool
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -23,10 +23,12 @@
|
||||
#include "mediapipe/framework/port/integral_types.h"
|
||||
#include "mediapipe/framework/port/proto_ns.h"
|
||||
#include "mediapipe/framework/port/status.h"
|
||||
#include "mediapipe/framework/tool/field_data.pb.h"
|
||||
|
||||
namespace mediapipe {
|
||||
namespace tool {
|
||||
|
||||
// TODO: Replace this class with a namespace following Google style.
|
||||
class ProtoUtilLite {
|
||||
public:
|
||||
// Defines field types and tag formats.
|
||||
@@ -89,6 +91,23 @@ class ProtoUtilLite {
|
||||
static absl::Status Deserialize(const std::vector<FieldValue>& field_values,
|
||||
FieldType field_type,
|
||||
std::vector<std::string>* result);
|
||||
|
||||
// Write a protobuf field value from a typed FieldData value.
|
||||
static absl::Status WriteValue(const mediapipe::FieldData& value,
|
||||
FieldType field_type,
|
||||
std::string* field_bytes);
|
||||
|
||||
// Read a protobuf field value into a typed FieldData value.
|
||||
static absl::Status ReadValue(absl::string_view field_bytes,
|
||||
FieldType field_type,
|
||||
absl::string_view message_type,
|
||||
mediapipe::FieldData* result);
|
||||
|
||||
// Returns the protobuf type-url for a protobuf type-name.
|
||||
static std::string TypeUrl(absl::string_view type_name);
|
||||
|
||||
// Returns the protobuf type-name for a protobuf type-url.
|
||||
static std::string ParseTypeUrl(absl::string_view type_url);
|
||||
};
|
||||
|
||||
} // namespace tool
|
||||
|
||||
@@ -59,7 +59,8 @@ absl::Status CombinedStatus(const std::string& general_comment,
|
||||
}
|
||||
}
|
||||
if (error_code == StatusCode::kOk) return OkStatus();
|
||||
Status combined = absl::Status(
|
||||
Status combined;
|
||||
combined = absl::Status(
|
||||
error_code,
|
||||
absl::StrCat(general_comment, "\n", absl::StrJoin(errors, "\n")));
|
||||
return combined;
|
||||
|
||||
@@ -28,8 +28,11 @@ namespace mediapipe {
|
||||
namespace {
|
||||
|
||||
using testing::ContainerEq;
|
||||
using testing::Eq;
|
||||
using testing::HasSubstr;
|
||||
using testing::IsEmpty;
|
||||
using testing::Matches;
|
||||
using testing::Pointwise;
|
||||
|
||||
TEST(StatusTest, StatusStopIsNotOk) { EXPECT_FALSE(tool::StatusStop().ok()); }
|
||||
|
||||
|
||||
@@ -293,7 +293,7 @@ absl::Status ExpandSubgraphs(CalculatorGraphConfig* config,
|
||||
if (subgraph_nodes_start == nodes->end()) break;
|
||||
std::vector<CalculatorGraphConfig> subgraphs;
|
||||
for (auto it = subgraph_nodes_start; it != nodes->end(); ++it) {
|
||||
const auto& node = *it;
|
||||
auto& node = *it;
|
||||
int node_id = it - nodes->begin();
|
||||
std::string node_name = CanonicalNodeName(*config, node_id);
|
||||
MP_RETURN_IF_ERROR(ValidateSubgraphFields(node));
|
||||
|
||||
@@ -16,79 +16,129 @@
|
||||
#define MEDIAPIPE_FRAMEWORK_TOOL_TYPE_UTIL_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "mediapipe/framework/demangle.h"
|
||||
#include "mediapipe/framework/port.h"
|
||||
|
||||
namespace mediapipe {
|
||||
|
||||
// An identifier for a type. This class is lightweight and is meant to be passed
|
||||
// by value.
|
||||
// To get the TypeId for SomeType, write kTypeId<SomeType>.
|
||||
class TypeId {
|
||||
public:
|
||||
size_t hash_code() const { return impl_.hash_code(); }
|
||||
std::string name() const { return impl_.name(); }
|
||||
bool operator==(const TypeId& other) const { return impl_ == other.impl_; }
|
||||
bool operator<(const TypeId& other) const { return impl_ < other.impl_; }
|
||||
|
||||
template <typename H>
|
||||
friend H AbslHashValue(H h, const TypeId& r) {
|
||||
return H::combine(std::move(h), r.hash_code());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static constexpr inline TypeId Of() {
|
||||
return TypeId{Impl::Get<T>()};
|
||||
}
|
||||
|
||||
private:
|
||||
// This implementation uses no RTTI. It distinguishes types, but does not
|
||||
// know their names.
|
||||
// TODO: record compile-time type string for (some or all) types.
|
||||
template <class T>
|
||||
struct TypeTag {
|
||||
static constexpr char dummy = 0;
|
||||
};
|
||||
struct NoRttiImpl {
|
||||
template <class T>
|
||||
static constexpr inline NoRttiImpl Get() {
|
||||
return {&TypeTag<T>::dummy};
|
||||
}
|
||||
size_t hash_code() const { return reinterpret_cast<uintptr_t>(tag_); }
|
||||
std::string name() const { return "<type name missing>"; }
|
||||
bool operator==(const NoRttiImpl& other) const {
|
||||
return tag_ == other.tag_;
|
||||
}
|
||||
bool operator<(const NoRttiImpl& other) const { return tag_ < other.tag_; }
|
||||
|
||||
const void* tag_;
|
||||
};
|
||||
|
||||
#if MEDIAPIPE_HAS_RTTI
|
||||
template <class T>
|
||||
static const std::type_info& GetTypeInfo() {
|
||||
return typeid(T);
|
||||
}
|
||||
// This implementation uses RTTI, and delegates all operations to
|
||||
// std::type_info. In order to support constexpr construction, we don't store
|
||||
// a type_info directly (which is not constexpr), but a pointer to a function
|
||||
// returning it (which is). This implementation is a bit slower than the
|
||||
// others. The only potential advantage would be the ability to match types
|
||||
// across multiple dynamic libraries, but we don't support that setup anyway.
|
||||
// This is provided for completeness.
|
||||
struct FullRttiImpl {
|
||||
template <class T>
|
||||
static constexpr inline FullRttiImpl Get() {
|
||||
return {GetTypeInfo<T>};
|
||||
}
|
||||
size_t hash_code() const { return get_().hash_code(); }
|
||||
std::string name() const { return Demangle(get_().name()); }
|
||||
bool operator==(const FullRttiImpl& other) const {
|
||||
return get_ == other.get_ || get_() == other.get_();
|
||||
}
|
||||
bool operator<(const FullRttiImpl& other) const {
|
||||
return get_().before(other.get_());
|
||||
}
|
||||
|
||||
decltype(&GetTypeInfo<void>) get_;
|
||||
};
|
||||
|
||||
// This implementation also stores a pointer to a std::type_info getter
|
||||
// function, but it only invokes it to get the type's name. It's equivalent to
|
||||
// NoRttiImpl for most operations, but it allows getting the type's name.
|
||||
struct FastRttiImpl {
|
||||
template <class T>
|
||||
static constexpr inline FastRttiImpl Get() {
|
||||
return {GetTypeInfo<T>};
|
||||
}
|
||||
size_t hash_code() const { return reinterpret_cast<uintptr_t>(get_); }
|
||||
std::string name() const { return Demangle(get_().name()); }
|
||||
bool operator==(const FastRttiImpl& other) const {
|
||||
return get_ == other.get_;
|
||||
}
|
||||
bool operator<(const FastRttiImpl& other) const {
|
||||
return reinterpret_cast<uintptr_t>(get_) <
|
||||
reinterpret_cast<uintptr_t>(other.get_);
|
||||
}
|
||||
|
||||
decltype(&GetTypeInfo<void>) get_;
|
||||
};
|
||||
|
||||
using Impl = FastRttiImpl;
|
||||
#else
|
||||
using Impl = NoRttiImpl;
|
||||
#endif // MEDIAPIPE_HAS_RTTI
|
||||
constexpr explicit TypeId(Impl impl) : impl_(impl) {}
|
||||
|
||||
Impl impl_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
static constexpr TypeId kTypeId = TypeId::Of<T>();
|
||||
|
||||
namespace tool {
|
||||
|
||||
#if !MEDIAPIPE_HAS_RTTI
|
||||
// A unique identifier for type T.
|
||||
class TypeInfo {
|
||||
public:
|
||||
size_t hash_code() const { return reinterpret_cast<size_t>(this); }
|
||||
bool operator==(const TypeInfo& other) const { return &other == this; }
|
||||
bool operator<(const TypeInfo& other) const { return &other < this; }
|
||||
const char* name() const { return "<unknown>"; }
|
||||
template <typename T>
|
||||
static const TypeInfo& Get() {
|
||||
static TypeInfo* static_type_info = new TypeInfo;
|
||||
return *static_type_info;
|
||||
}
|
||||
|
||||
private:
|
||||
TypeInfo() {}
|
||||
TypeInfo(const TypeInfo&) = delete;
|
||||
};
|
||||
|
||||
#else // MEDIAPIPE_HAS_RTTI
|
||||
// The std unique identifier for type T.
|
||||
class TypeInfo {
|
||||
public:
|
||||
size_t hash_code() const { return info_.hash_code(); }
|
||||
bool operator==(const TypeInfo& o) const { return info_ == o.info_; }
|
||||
bool operator<(const TypeInfo& o) const { return info_.before(o.info_); }
|
||||
const char* name() const { return info_.name(); }
|
||||
template <typename T>
|
||||
static const TypeInfo& Get() {
|
||||
static TypeInfo* static_type_info = new TypeInfo(typeid(T));
|
||||
return *static_type_info;
|
||||
}
|
||||
|
||||
private:
|
||||
TypeInfo(const std::type_info& info) : info_(info) {}
|
||||
TypeInfo(const TypeInfo&) = delete;
|
||||
|
||||
private:
|
||||
const std::type_info& info_;
|
||||
friend class TypeIndex;
|
||||
};
|
||||
#endif
|
||||
|
||||
// An associative key for TypeInfo.
|
||||
class TypeIndex {
|
||||
public:
|
||||
TypeIndex(const TypeInfo& info) : info_(info) {}
|
||||
size_t hash_code() const { return info_.hash_code(); }
|
||||
bool operator==(const TypeIndex& other) const { return info_ == other.info_; }
|
||||
bool operator<(const TypeIndex& other) const { return info_ < other.info_; }
|
||||
|
||||
private:
|
||||
const TypeInfo& info_;
|
||||
};
|
||||
|
||||
// Helper method that returns a hash code of the given type. This allows for
|
||||
// typeid testing across multiple binaries, unlike FastTypeId which used a
|
||||
// memory location that only works within the same binary. Moreover, we use this
|
||||
// for supporting multiple .so binaries in a single Android app built using the
|
||||
// same compiler and C++ libraries.
|
||||
// Note that std::type_info may still generate the same hash code for different
|
||||
// types, although the c++ standard recommends that implementations avoid this
|
||||
// as much as possible.
|
||||
// Helper method that returns a hash code of the given type.
|
||||
// Superseded by TypeId.
|
||||
template <typename T>
|
||||
ABSL_DEPRECATED("Use TypeId directly instead.")
|
||||
size_t GetTypeHash() {
|
||||
return TypeInfo::Get<T>().hash_code();
|
||||
return kTypeId<T>.hash_code();
|
||||
}
|
||||
|
||||
} // namespace tool
|
||||
|
||||
Reference in New Issue
Block a user