diff --git a/rd-cpp/src/rd_framework_cpp/src/main/impl/RdProperty.h b/rd-cpp/src/rd_framework_cpp/src/main/impl/RdProperty.h index 1828458e8..ed4ec6e15 100644 --- a/rd-cpp/src/rd_framework_cpp/src/main/impl/RdProperty.h +++ b/rd-cpp/src/rd_framework_cpp/src/main/impl/RdProperty.h @@ -43,20 +43,29 @@ class RdProperty final : public RdPropertyBase, public ISerializable static RdProperty read(SerializationCtx& ctx, Buffer& buffer) { RdId id = RdId::read(buffer); - bool not_null = buffer.read_bool(); // not null/ - (void) not_null; - auto value = S::read(ctx, buffer); RdProperty property; - property.value = std::move(value); withId(property, id); + const bool has_value = buffer.read_bool(); + if (has_value) + { + auto value = S::read(ctx, buffer); + property.value = std::move(value); + } return property; } void write(SerializationCtx& ctx, Buffer& buffer) const override { this->rdid.write(buffer); - buffer.write_bool(true); - S::write(ctx, buffer, this->get()); + if (this->has_value()) + { + buffer.write_bool(true); + S::write(ctx, buffer, this->get()); + } + else + { + buffer.write_bool(false); + } } void advise(Lifetime lifetime, std::function handler) const override diff --git a/rd-cpp/src/rd_framework_cpp/src/main/task/RdTaskResult.h b/rd-cpp/src/rd_framework_cpp/src/main/task/RdTaskResult.h index 50b431d5a..ed9ea7d54 100644 --- a/rd-cpp/src/rd_framework_cpp/src/main/task/RdTaskResult.h +++ b/rd-cpp/src/rd_framework_cpp/src/main/task/RdTaskResult.h @@ -137,6 +137,11 @@ class RdTaskResult final : public ISerializable return v.index() == 0; } + Success& as_successful() + { + return rd::get(v); + } + bool is_canceled() const { return v.index() == 1; diff --git a/rd-cpp/src/rd_framework_cpp/src/main/task/WiredRdTaskImpl.h b/rd-cpp/src/rd_framework_cpp/src/main/task/WiredRdTaskImpl.h index 259b25d58..b0802100a 100644 --- a/rd-cpp/src/rd_framework_cpp/src/main/task/WiredRdTaskImpl.h +++ b/rd-cpp/src/rd_framework_cpp/src/main/task/WiredRdTaskImpl.h @@ -27,14 +27,15 @@ class WiredRdTaskImpl : public RdReactiveBase LifetimeImpl::counter_t termination_lifetime_id{}; template , bool> = true> - TaskResult bind_result(TaskResult task_result) const + void bind_result(TaskResult& task_result) const { if (!task_result.is_succeeded()) - return task_result; + return; auto lifetime_defintion = LifetimeDefinition(lifetime); auto result_lifetime = lifetime_defintion.lifetime; - auto value = util::attach_lifetime(task_result.get_value(), std::move(lifetime_defintion)); + auto& success = task_result.as_successful(); + auto value = util::attach_lifetime(success.value, std::move(lifetime_defintion)); result_lifetime->add_action([task_id = get_id(), cutpoint = cutpoint] { cutpoint->get_wire()->send(task_id, [](auto&) @@ -43,13 +44,12 @@ class WiredRdTaskImpl : public RdReactiveBase }); }); value->bind(result_lifetime, cutpoint, "CallResult"); - return typename TaskResult::Success(value); + success.value = value; } template , bool> = true> - TaskResult bind_result(TaskResult result) const + void bind_result(TaskResult&) const { - return result; } public: @@ -85,7 +85,7 @@ class WiredRdTaskImpl : public RdReactiveBase } else { - result = bind_result(std::move(result)); + bind_result(result); this->result->set_if_empty(std::move(result)); } }); diff --git a/rd-cpp/src/rd_framework_cpp/src/test/cases/RdTaskTest.cpp b/rd-cpp/src/rd_framework_cpp/src/test/cases/RdTaskTest.cpp index 6b7132052..dd49db687 100644 --- a/rd-cpp/src/rd_framework_cpp/src/test/cases/RdTaskTest.cpp +++ b/rd-cpp/src/rd_framework_cpp/src/test/cases/RdTaskTest.cpp @@ -204,5 +204,35 @@ TEST_F(RdFrameworkTestBase, testAsyncBindableCall) EXPECT_TRUE(server_result_lifetime_terminated) << "Expected server lifetime for result to be terminated."; EXPECT_TRUE(server_result.unique()) << "Expected server_result to be released. Test should hold only reference to server result."; + AfterTest(); +} + +TEST_F(RdFrameworkTestBase, testUninitializedPropertyInResult) +{ + RdEndpoint server_entity; + RdCall client_entity; + + statics(server_entity, static_entity_id); + statics(client_entity, static_entity_id); + + Wrapper server_result; + + server_entity.set([&](std::wstring const&) + { + server_result = wrapper::make_wrapper(); + return server_result; + }); + + bindStatic(serverProtocol.get(), server_entity, static_name); + bindStatic(clientProtocol.get(), client_entity, static_name); + + auto task_result = client_entity.start(L"xy").value_or_throw(); + auto client_result = task_result.get_value(); + auto& foo_property = client_result->get_foo(); + EXPECT_THROW(foo_property.get(), std::exception) << "Expected to throw when access unitialized property"; + + server_result->get_foo().set(2); + EXPECT_EQ(2, foo_property.get()) << "Expected to sync property value when it set on server."; + AfterTest(); } \ No newline at end of file