Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactors the MessageWidget class #402

Merged
merged 5 commits into from
May 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ QT5_ADD_RESOURCES(TopicInterfacePlugin_RCC topic_interface_plugin.qrc)

add_library(TopicInterfacePlugin
${CMAKE_CURRENT_SOURCE_DIR}/topic_interface_plugin.cc
${CMAKE_CURRENT_SOURCE_DIR}/message_widget.cc
${CMAKE_CURRENT_SOURCE_DIR}/message.cc
${TopicInterfacePlugin_MOC}
${TopicInterfacePlugin_RCC}
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// Copyright 2021 Toyota Research Institute
#include "message_widget.h"
#include "message.h"

namespace delphyne {
namespace gui {
namespace internal {

void MessageWidget::Parse(const std::string& _scopedName, google::protobuf::Message* _msg) {
void Message::Parse(const std::string& _scopedName, google::protobuf::Message* _msg) {
constexpr bool kIsRepeated{true};
constexpr bool kIsNotRepeated{!kIsRepeated};

Expand Down Expand Up @@ -36,80 +37,80 @@ void MessageWidget::Parse(const std::string& _scopedName, google::protobuf::Mess
// Evaluate the type.
if (fieldType == google::protobuf::FieldDescriptor::TYPE_MESSAGE) {
auto& value = reflection->GetRepeatedMessage(*_msg, fieldDescriptor, count);
children[itemName] = std::make_unique<MessageWidget>(itemName, &value, kIsRepeated);
children[itemName] = std::make_unique<Message>(itemName, &value, kIsRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_DOUBLE) {
const double value = reflection->GetRepeatedDouble(*_msg, fieldDescriptor, count);
children[itemName] = std::make_unique<MessageWidget>(itemName, value, kIsRepeated);
children[itemName] = std::make_unique<Message>(itemName, value, kIsRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_FLOAT) {
const float value = reflection->GetRepeatedFloat(*_msg, fieldDescriptor, count);
children[itemName] = std::make_unique<MessageWidget>(itemName, value, kIsRepeated);
children[itemName] = std::make_unique<Message>(itemName, value, kIsRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_INT64) {
const int64_t value = reflection->GetRepeatedInt64(*_msg, fieldDescriptor, count);
children[itemName] = std::make_unique<MessageWidget>(itemName, value, kIsRepeated);
children[itemName] = std::make_unique<Message>(itemName, value, kIsRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_INT32) {
const int32_t value = reflection->GetRepeatedInt32(*_msg, fieldDescriptor, count);
children[itemName] = std::make_unique<MessageWidget>(itemName, value, kIsRepeated);
children[itemName] = std::make_unique<Message>(itemName, value, kIsRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_UINT64) {
const uint64_t value = reflection->GetRepeatedUInt64(*_msg, fieldDescriptor, count);
children[itemName] = std::make_unique<MessageWidget>(itemName, value, kIsRepeated);
children[itemName] = std::make_unique<Message>(itemName, value, kIsRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_UINT32) {
const uint32_t value = reflection->GetRepeatedUInt32(*_msg, fieldDescriptor, count);
children[itemName] = std::make_unique<MessageWidget>(itemName, value, kIsRepeated);
children[itemName] = std::make_unique<Message>(itemName, value, kIsRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_BOOL) {
const bool value = reflection->GetRepeatedBool(*_msg, fieldDescriptor, count);
children[itemName] = std::make_unique<MessageWidget>(itemName, value, kIsRepeated);
children[itemName] = std::make_unique<Message>(itemName, value, kIsRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_STRING) {
const std::string value = reflection->GetRepeatedString(*_msg, fieldDescriptor, count);
children[itemName] = std::make_unique<MessageWidget>(itemName, value, kIsRepeated);
children[itemName] = std::make_unique<Message>(itemName, value, kIsRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_ENUM) {
auto enumValueDescriptor = reflection->GetRepeatedEnum(*_msg, fieldDescriptor, count);
const int enumValue = enumValueDescriptor->number();
const std::string enumName = enumValueDescriptor->name();
children[itemName] = std::make_unique<MessageWidget>(itemName, EnumValue{enumValue, enumName}, kIsRepeated);
children[itemName] = std::make_unique<Message>(itemName, EnumValue{enumValue, enumName}, kIsRepeated);
} else {
// Unhandled message type.
}
}
} else { // It's not a repeated message, then we just need to parse them.
if (fieldType == google::protobuf::FieldDescriptor::TYPE_MESSAGE) {
auto& value = reflection->GetMessage(*_msg, fieldDescriptor);
children[scopedName] = std::make_unique<MessageWidget>(scopedName, &value, kIsNotRepeated);
children[scopedName] = std::make_unique<Message>(scopedName, &value, kIsNotRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_DOUBLE) {
const double value = reflection->GetDouble(*_msg, fieldDescriptor);
children[scopedName] = std::make_unique<MessageWidget>(scopedName, value, kIsNotRepeated);
children[scopedName] = std::make_unique<Message>(scopedName, value, kIsNotRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_FLOAT) {
const float value = reflection->GetFloat(*_msg, fieldDescriptor);
children[scopedName] = std::make_unique<MessageWidget>(scopedName, value, kIsNotRepeated);
children[scopedName] = std::make_unique<Message>(scopedName, value, kIsNotRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_INT64) {
const int64_t value = reflection->GetInt64(*_msg, fieldDescriptor);
children[scopedName] = std::make_unique<MessageWidget>(scopedName, value, kIsNotRepeated);
children[scopedName] = std::make_unique<Message>(scopedName, value, kIsNotRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_INT32) {
const int32_t value = reflection->GetInt32(*_msg, fieldDescriptor);
children[scopedName] = std::make_unique<MessageWidget>(scopedName, value, kIsNotRepeated);
children[scopedName] = std::make_unique<Message>(scopedName, value, kIsNotRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_UINT64) {
const uint64_t value = reflection->GetUInt64(*_msg, fieldDescriptor);
children[scopedName] = std::make_unique<MessageWidget>(scopedName, value, kIsNotRepeated);
children[scopedName] = std::make_unique<Message>(scopedName, value, kIsNotRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_UINT32) {
const uint32_t value = reflection->GetUInt32(*_msg, fieldDescriptor);
children[scopedName] = std::make_unique<MessageWidget>(scopedName, value, kIsNotRepeated);
children[scopedName] = std::make_unique<Message>(scopedName, value, kIsNotRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_BOOL) {
const bool value = reflection->GetBool(*_msg, fieldDescriptor);
children[scopedName] = std::make_unique<MessageWidget>(scopedName, value, kIsNotRepeated);
children[scopedName] = std::make_unique<Message>(scopedName, value, kIsNotRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_STRING) {
const std::string value = reflection->GetString(*_msg, fieldDescriptor);
children[scopedName] = std::make_unique<MessageWidget>(scopedName, value, kIsNotRepeated);
children[scopedName] = std::make_unique<Message>(scopedName, value, kIsNotRepeated);
} else if (fieldType == google::protobuf::FieldDescriptor::TYPE_ENUM) {
auto enumValueDescriptor = reflection->GetEnum(*_msg, fieldDescriptor);
const int enumValue = enumValueDescriptor->number();
const std::string enumName = enumValueDescriptor->name();
children[scopedName] =
std::make_unique<MessageWidget>(scopedName, EnumValue{enumValue, enumName}, kIsNotRepeated);
children[scopedName] = std::make_unique<Message>(scopedName, EnumValue{enumValue, enumName}, kIsNotRepeated);
} else {
// Unhandled message type.
}
}
}
}

} // namespace internal
} // namespace gui
} // namespace delphyne
113 changes: 113 additions & 0 deletions delphyne_gui/visualizer/topic_interface_plugin/message.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2021 Toyota Research Institute
#pragma once

#include <map>
#include <memory>
#include <optional>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <variant>

#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>

#include <ignition/common/Console.hh>

namespace delphyne {
namespace gui {
namespace internal {

/// @brief Holds the information of a google::protobuf::Message to be consumed
/// by a Qt widget.
/// @details Holds a variant when it is a leaf node in the message tree
/// ( @see Message::Variant ). Otherwise, when it is a compound type,
/// it populates a dictionary of Messages.
/// See Parse() implementation for a full description of how it uses
/// the reflection API in Google Protobuf Message class to get the
/// information of each field.
class Message {
public:
/// Wraps an enumeration field in Google Protobuf.
struct EnumValue {
int value; ///< The integer value of the enum.
std::string name; ///< The string label the enum has.
};

/// It simplifies the operation by consumers when dealing with the type.
/// An instance is well-constructed iff none or just one field has a value.
using Variant = std::variant<double, float, int64_t, int32_t, uint32_t, uint64_t, bool, std::string, EnumValue>;

/// @brief Constructs a Message.
///
/// @details It is a template constuctor that behaves differently based on T.
/// When T is one of the possible Variant's types, it just stores the
/// value in `variantValue`. When it is a pointer (it'll compile
/// only for google::protobuf::Message*) it'll forward a copy of
/// @p _value to Parse() nodes.
/// @param _name The message name. The fully qualified attribute name will be
/// used when it is recursively built.
/// @param _value The value to hold. When it is a pointer, it is assumed to be
/// a google::protobuf::Message* which will request a recursive
/// introspection via Parse() to populate children.
/// @param _isRepeated Whether or not this message is a repeated field in a
/// google::protobuf::Message definition.
template <typename T>
Message(const std::string& _name, T _value, bool _isRepeated) {
name = _name;
isRepeated = _isRepeated;
if constexpr (std::is_pointer<T>::value) {
auto msg = _value->New();
msg->CopyFrom(*_value);
Parse(name, msg);
} else {
typeName = typeid(_value).name();
variantValue = _value;
}
}

/// @return The full name of this item in the proto message hierarchy. It
/// uses "::" to separate field names and injects "::X::" where X is
/// a non-negative number to differentiate repeated fields.
std::string Name() const { return name; }

/// @return The type name of the message.
std::string TypeName() const { return typeName; }

/// @return Whether this type is compound or not.
bool IsCompound() const { return !children.empty(); }

/// @return The value this message holds.
Variant Value() const { return variantValue; }

/// @return Whether the message is a repeated value of a type at the certain
/// level in the hierarchy.
bool IsRepeated() const { return isRepeated; }

/// @return The children dictionary.
const std::map<std::string, std::unique_ptr<Message>>& Children() const { return children; }

private:
/// @brief Parses @p _msg and stores children Message into
/// `variantValue` using @p _scopedName as `name`.
void Parse(const std::string& _scopedName, google::protobuf::Message* _msg);

/// @brief This message full name.
std::string name{""};

/// @brief Holds the type name of the data.
std::string typeName{""};

/// @brief Holds the data of a terminal node.
Variant variantValue;

/// @brief Whether or not this is a repeated field.
bool isRepeated{false};

/// @brief Holds the children, nested values.
std::map<std::string, std::unique_ptr<Message>> children;
};

} // namespace internal
} // namespace gui
} // namespace delphyne
159 changes: 0 additions & 159 deletions delphyne_gui/visualizer/topic_interface_plugin/message_widget.h

This file was deleted.

Loading