-
Notifications
You must be signed in to change notification settings - Fork 254
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
Readable and Writable storage #18
Readable and Writable storage #18
Conversation
I discussed this with @Karsten1987, and two ideas came up for other ways to organize the API in this pull request. One would be to organize it more like the STL's https://en.cppreference.com/w/cpp/io Specifically, it has a https://en.cppreference.com/w/File:std-io-complete-inheritance.svg This prevents the situation in this pull request where So you could change this such that there is a "read interface" and a "read implementation" which additionally implements Another approach, that I suggested and is actually what I think would be best, is using the "policy design pattern" based on templated inheritance. I put together a skeleton of this in a gist at @Karsten1987's request: #include <string>
#include <vector>
struct SerializedMessage
{
// ...
};
class RosbagIOStorageInterface
{
public:
virtual
const char *
get_open_flags() = 0;
};
class RosbagReadStorageInterface : public RosbagIOStorageInterface
{
public:
virtual
SerializedMessage
read_next_message();
virtual
std::vector<std::string>
list_topics();
const char *
get_open_flags() override {return "r";}
// ...
};
class RosbagWriteStorageInterface : public RosbagIOStorageInterface
{
public:
virtual
void
add_topic(const std::string & topic_name/*, ... */);
virtual
void
write_message(const SerializedMessage & serialized_message_instance);
const char *
get_open_flags() override {return "a+";}
};
class RosbagReadWriteStorageInterface
: public RosbagReadStorageInterface,
public RosbagWriteStorageInterface
{
public:
const char *
get_open_flags() override {return RosbagWriteStorageInterface::get_open_flags();}
};
template<typename IOInterfaceT>
class RosbagStorageInterface : public IOInterfaceT
{
public:
RosbagStorageInterface()
{
static_assert(
std::is_base_of<RosbagIOStorageInterface, IOInterfaceT>::value,
"Must use a class based on RosbagIOStorageInterface with RosbagStorageInterface");
}
virtual
bool
open(const std::string & bag_uri)
{
(void)bag_uri;
const char * open_flags = this->get_open_flags();
(void)open_flags;
return true;
}
};
void
look_at_bag(RosbagReadStorageInterface * ro_bag_interface)
{
ro_bag_interface->read_next_message();
}
void
add_to_bag(RosbagWriteStorageInterface * wo_bag_interface)
{
wo_bag_interface->write_message(SerializedMessage());
}
void
rewrite_bag(RosbagReadWriteStorageInterface * rw_bag_interface)
{
rw_bag_interface->write_message(rw_bag_interface->read_next_message());
}
int main()
{
RosbagStorageInterface<RosbagReadStorageInterface> ro_interface;
ro_interface.open("foo");
ro_interface.read_next_message();
// compile error:
// no member named 'write_message' in 'RosbagStorageInterface<RosbagReadStorageInterface>'
// ro_interface.write_message(SerializedMessage());
look_at_bag(&ro_interface);
// compile error:
// no matching function for call to 'add_to_bag'
// add_to_bag(&ro_interface);
// compile error:
// no matching function for call to 'rewrite_bag'
// rewrite_bag(&ro_interface);
RosbagStorageInterface<RosbagWriteStorageInterface> wo_interface; // is this necessary?
wo_interface.open("foo");
// compile error:
// no member named 'read_next_message' in 'RosbagStorageInterface<RosbagWriteStorageInterface>'
// wo_interface.read_next_message();
wo_interface.write_message(SerializedMessage());
// compile error:
// no matching function for call to 'look_at_bag'
// look_at_bag(&wo_interface);
add_to_bag(&wo_interface);
// compile error:
// no matching function for call to 'rewrite_bag'
// rewrite_bag(&wo_interface);
RosbagStorageInterface<RosbagReadWriteStorageInterface> rw_interface;
rw_interface.open("foo");
rw_interface.read_next_message();
rw_interface.write_message(SerializedMessage());
look_at_bag(&rw_interface);
add_to_bag(&rw_interface);
rewrite_bag(&rw_interface);
// compile error:
// base specifier must name a class
// RosbagStorageInterface<float> wont_compile;
// compile error:
// Must use a class based on RosbagIOStorageInterface with RosbagStorageInterface
// RosbagStorageInterface<std::string> wont_either;
return 0;
} |
Link to policy based design on wikipedia: https://en.wikipedia.org/wiki/Policy-based_design |
I don't think that the policy based design is going to work as we want to load a specific storage plugin (which would be parametrized with policies) during runtime via the pluginlib. This prevents compile time mechanisms. |
We iterated a bit on the storage design. Basically, our suggestion would be:
Since our initial demo was pushed to the branch, I pushed our changes for this, too - i.e. the demo would remain fully functional. The interface does not yet use the |
As discussed offline, I am going ahead and merge this branch on the original PR in order to accumulate discussions in a single place. |
Signed-off-by: James Smith <james@foxglove.dev>
This PR separates into readable/writable/general storage. This means that any plugin author only needs to implement any interface and we won't have to check whether methods are supported or not.
The user of
librosbag2_storage
would then get a storage handle depending on the type of the operations he/she needs to call.The branch also builds cleanly on all supported platforms.
Not yet part of this branch:
Currently, we cannot distinguish between the different "open" for writing/reading/etc.