| 85 | } |
| 86 | |
| 87 | static ProtoField resolveProtoPath( |
| 88 | google::protobuf::Message* message, const std::string& path, bool create) |
| 89 | { |
| 90 | std::string::size_type dot = path.rfind('.'); |
| 91 | std::string leading = (dot == std::string::npos) ? "" : path.substr(0, dot); |
| 92 | std::string trailing = |
| 93 | (dot == std::string::npos) ? path : path.substr(dot + 1); |
| 94 | |
| 95 | auto fail = [&]() |
| 96 | { |
| 97 | throw ProtoPathNotFoundException( |
| 98 | fmt::format("no such config field '{}' in '{}'", trailing, path)); |
| 99 | }; |
| 100 | |
| 101 | const auto* descriptor = message->GetDescriptor(); |
| 102 | |
| 103 | std::string item; |
| 104 | std::stringstream ss(leading); |
| 105 | while (std::getline(ss, item, '.')) |
| 106 | { |
| 107 | static const std::regex INDEX_REGEX("(\\w+)\\[([0-9]+)\\]"); |
| 108 | |
| 109 | int index = splitIndexedField(item); |
| 110 | |
| 111 | const auto* field = descriptor->FindFieldByName(item); |
| 112 | if (!field) |
| 113 | throw ProtoPathNotFoundException( |
| 114 | fmt::format("no such config field '{}' in '{}'", item, path)); |
| 115 | if (field->type() != google::protobuf::FieldDescriptor::TYPE_MESSAGE) |
| 116 | throw ProtoPathNotFoundException(fmt::format( |
| 117 | "config field '{}' in '{}' is not a message", item, path)); |
| 118 | |
| 119 | const auto* reflection = message->GetReflection(); |
| 120 | if (!field->is_repeated() && (index != -1)) |
| 121 | throw ProtoPathNotFoundException(fmt::format( |
| 122 | "config field '{}[{}]' is indexed, but not repeated", |
| 123 | item, |
| 124 | index)); |
| 125 | |
| 126 | if (field->is_repeated()) |
| 127 | { |
| 128 | if (index == -1) |
| 129 | throw ProtoPathNotFoundException(fmt::format( |
| 130 | "config field '{}' is repeated and must be indexed", item)); |
| 131 | while (reflection->FieldSize(*message, field) <= index) |
| 132 | reflection->AddMessage(message, field); |
| 133 | |
| 134 | message = reflection->MutableRepeatedMessage(message, field, index); |
| 135 | } |
| 136 | else |
| 137 | { |
| 138 | if (!create && !reflection->HasField(*message, field)) |
| 139 | throw ProtoPathNotFoundException(fmt::format( |
| 140 | "could not find config field '{}'", field->name())); |
| 141 | message = reflection->MutableMessage(message, field); |
| 142 | } |
| 143 | |
| 144 | descriptor = message->GetDescriptor(); |
no test coverage detected