diff --git a/include/mp/proxy-types.h b/include/mp/proxy-types.h index f1127da5..ea04a3a6 100644 --- a/include/mp/proxy-types.h +++ b/include/mp/proxy-types.h @@ -285,7 +285,7 @@ void BuildList(TypeList, InvokeContext& invoke_context, Output&& outp { auto list = output.init(value.size()); size_t i = 0; - for (const auto& elem : value) { + for (auto&& elem : value) { BuildField(TypeList(), invoke_context, ListOutput(list, i), elem); ++i; } diff --git a/src/mp/gen.cpp b/src/mp/gen.cpp index c8db469d..2d463e55 100644 --- a/src/mp/gen.cpp +++ b/src/mp/gen.cpp @@ -338,6 +338,7 @@ static void Generate(kj::StringPtr src_prefix, cpp_client << "#include \n"; cpp_client << "#include \n"; cpp_client << "#include \n"; + cpp_client << "#include \n"; cpp_client << "#include \n"; cpp_client << "#include \n"; cpp_client << "#include \n"; diff --git a/test/mp/test/foo.capnp b/test/mp/test/foo.capnp index 31736452..edf7841c 100644 --- a/test/mp/test/foo.capnp +++ b/test/mp/test/foo.capnp @@ -36,6 +36,7 @@ interface FooInterface $Proxy.wrap("mp::test::FooImplementation") { callFnAsync @18 (context :Proxy.Context) -> (); callIntFnAsync @21 (context :Proxy.Context, arg :Int32) -> (result :Int32); passDataPointers @22 (arg :List(Data)) -> (result :List(Data)); + listCallbacks @24 (context :Proxy.Context, n :Int32) -> (result :List(FooCallback)); } interface FooCallback $Proxy.wrap("mp::test::FooCallback") { diff --git a/test/mp/test/foo.h b/test/mp/test/foo.h index 5b66b85e..17aeeb83 100644 --- a/test/mp/test/foo.h +++ b/test/mp/test/foo.h @@ -59,6 +59,15 @@ class FooCallback virtual int call(int arg) = 0; }; +//! Concrete FooCallback that returns a fixed value, used by listCallbacks tests. +class SimpleCallback : public FooCallback +{ +public: + explicit SimpleCallback(int value) : m_value(value) {} + int call(int) override { return m_value; } + int m_value; +}; + class ExtendedCallback : public FooCallback { public: @@ -89,6 +98,13 @@ class FooImplementation double passDouble(double value) { return value; } int passFn(std::function fn) { return fn(); } std::vector passDataPointers(std::vector values) { return values; } + std::vector> listCallbacks(int n) + { + std::vector> result; + result.reserve(n); + for (int i = 0; i < n; ++i) result.push_back(std::make_unique(i)); + return result; + } std::shared_ptr m_callback; void callFn() { assert(m_fn); m_fn(); } void callFnAsync() { assert(m_fn); m_fn(); } diff --git a/test/mp/test/test.cpp b/test/mp/test/test.cpp index 1fc30691..41ca506c 100644 --- a/test/mp/test/test.cpp +++ b/test/mp/test/test.cpp @@ -258,6 +258,16 @@ KJ_TEST("Call FooInterface methods") KJ_REQUIRE(data_out[0] != nullptr); KJ_EXPECT(*data_out[0] == *data_in[0]); KJ_EXPECT(!data_out[1]); + + // Test returning vector> from server. This exercises + // BuildList with interface element types, which requires non-const iteration + // so unique_ptr::release() can transfer ownership to the proxy server. + std::vector> callbacks{foo->listCallbacks(3)}; + KJ_REQUIRE(callbacks.size() == 3u); + for (int i = 0; i < 3; ++i) { + KJ_REQUIRE(callbacks[i] != nullptr); + KJ_EXPECT(callbacks[i]->call(0) == i); + } } KJ_TEST("Call IPC method after client connection is closed")