From d9b9b5b311a33d021e0438c718eecf4b1cd0a34e Mon Sep 17 00:00:00 2001 From: Jeremy Nimmer Date: Wed, 14 Jul 2021 17:34:52 -0700 Subject: [PATCH] [lcm] SerializerInterface is now cloneable Modernize "= default" boilerplate while we're here. --- bindings/pydrake/systems/_lcm_extra.py | 3 +++ bindings/pydrake/systems/lcm_py.cc | 6 ++++++ bindings/pydrake/systems/test/lcm_test.py | 8 ++++++++ systems/lcm/serializer.h | 13 ++++++++++--- systems/lcm/test/serializer_test.cc | 8 ++++++++ 5 files changed, 35 insertions(+), 3 deletions(-) diff --git a/bindings/pydrake/systems/_lcm_extra.py b/bindings/pydrake/systems/_lcm_extra.py index 2f135e98b1df..8ed1acffa322 100644 --- a/bindings/pydrake/systems/_lcm_extra.py +++ b/bindings/pydrake/systems/_lcm_extra.py @@ -13,6 +13,9 @@ def __init__(self, lcm_type): SerializerInterface.__init__(self) self._lcm_type = lcm_type + def Clone(self): + return PySerializer(self._lcm_type) + def CreateDefaultValue(self): return AbstractValue.Make(self._lcm_type()) diff --git a/bindings/pydrake/systems/lcm_py.cc b/bindings/pydrake/systems/lcm_py.cc index 830c2034e0c5..d98b81c5979d 100644 --- a/bindings/pydrake/systems/lcm_py.cc +++ b/bindings/pydrake/systems/lcm_py.cc @@ -40,6 +40,11 @@ class PySerializerInterface : public py::wrapper { // `PySerializerInterface`). C++ implementations will use the bindings on the // interface below. + std::unique_ptr Clone() const override { + PYBIND11_OVERLOAD_PURE( + std::unique_ptr, SerializerInterface, Clone); + } + std::unique_ptr CreateDefaultValue() const override { PYBIND11_OVERLOAD_PURE(std::unique_ptr, SerializerInterface, CreateDefaultValue); @@ -138,6 +143,7 @@ PYBIND11_MODULE(lcm, m) { message_bytes.size()); }, py::arg("abstract_value"), cls_doc.Serialize.doc); + DefClone(&cls); } { diff --git a/bindings/pydrake/systems/test/lcm_test.py b/bindings/pydrake/systems/test/lcm_test.py index debc28eb2477..fa2de695b0d6 100644 --- a/bindings/pydrake/systems/test/lcm_test.py +++ b/bindings/pydrake/systems/test/lcm_test.py @@ -74,6 +74,10 @@ def test_serializer(self): raw = dut.Serialize(value) reconstruct = lcmt_quaternion.decode(raw) self.assert_lcm_equal(reconstruct, model_message) + # Check cloning. + cloned_dut = dut.Clone() + fresh_value = dut.CreateDefaultValue().get_value() + self.assertIsInstance(fresh_value, lcmt_quaternion) def test_serializer_cpp(self): # Tests relevant portions of API. @@ -82,6 +86,10 @@ def test_serializer_cpp(self): self.assert_lcm_equal( self._cpp_value_to_py_message(model_value), model_message) + def test_serializer_cpp_clone(self): + serializer = mut._Serializer_[lcmt_quaternion]() + serializer.Clone().CreateDefaultValue() + def _process_event(self, dut): # Use a Simulator to invoke the update event on `dut`. (Wouldn't it be # nice if the Systems API was simple enough that we could apply events diff --git a/systems/lcm/serializer.h b/systems/lcm/serializer.h index e4f91d548fb7..ca5f4853069c 100644 --- a/systems/lcm/serializer.h +++ b/systems/lcm/serializer.h @@ -25,6 +25,9 @@ class SerializerInterface { virtual ~SerializerInterface(); + /** Creates a deep copy of this. */ + virtual std::unique_ptr Clone() const = 0; + /** * Creates a value-initialized (zeroed) instance of the message object. * The result can be used as the output object filled in by Deserialize. @@ -45,7 +48,7 @@ class SerializerInterface { std::vector* message_bytes) const = 0; protected: - SerializerInterface() {} + SerializerInterface() = default; }; /** @@ -59,8 +62,12 @@ class Serializer : public SerializerInterface { public: DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(Serializer) - Serializer() {} - ~Serializer() override {} + Serializer() = default; + ~Serializer() override = default; + + std::unique_ptr Clone() const override { + return std::make_unique(); + } std::unique_ptr CreateDefaultValue() const override { // NOTE: We create the message using value-initialization ("{}") to ensure diff --git a/systems/lcm/test/serializer_test.cc b/systems/lcm/test/serializer_test.cc index eafe52ace862..c7617591ae2a 100644 --- a/systems/lcm/test/serializer_test.cc +++ b/systems/lcm/test/serializer_test.cc @@ -5,6 +5,7 @@ #include +#include "drake/common/is_cloneable.h" #include "drake/lcm/lcmt_drake_signal_utils.h" #include "drake/lcmt_drake_signal.hpp" @@ -42,6 +43,13 @@ GTEST_TEST(SerializerTest, BasicTest) { abstract_value.get()); EXPECT_TRUE(CompareLcmtDrakeSignalMessages( abstract_value->get_value(), sample_data)); + + // Cloning works. + EXPECT_TRUE(is_cloneable::value); + auto fresh = dut->Clone(); + ASSERT_NE(fresh, nullptr); + auto fresh_value = fresh->CreateDefaultValue(); + EXPECT_EQ(fresh_value->get_value().dim, 0); } } // namespace