diff --git a/src/lib_c5t_actor_model.h b/src/lib_c5t_actor_model.h index ad84221..77002e8 100644 --- a/src/lib_c5t_actor_model.h +++ b/src/lib_c5t_actor_model.h @@ -314,6 +314,7 @@ class ActorSubscriberScope final { ActorSubscriberScope(ActorSubscriberScope const&) = delete; ActorSubscriberScope& operator=(ActorSubscriberScope const&) = delete; + friend class NullableActorSubscriberScope; std::unique_ptr type_erased_impl_; public: @@ -352,10 +353,17 @@ class NullableActorSubscriberScope final { return *this; } + NullableActorSubscriberScope& operator=(ActorSubscriberScope&& rhs) { + type_erased_impl_ = std::move(rhs.type_erased_impl_); + return *this; + } + NullableActorSubscriberScope& operator=(std::nullptr_t) { type_erased_impl_ = nullptr; return *this; } + + operator bool() const { return type_erased_impl_ != nullptr; } }; template diff --git a/src/lib_c5t_storage.h b/src/lib_c5t_storage.h index 2ac70c9..ddf1156 100644 --- a/src/lib_c5t_storage.h +++ b/src/lib_c5t_storage.h @@ -154,6 +154,15 @@ class C5T_STORAGE_FIELD_ACCESSOR final { bool Has(std::string key) const { return InnerGet(std::move(key)) != nullptr; } + T GetOrDefault(std::string key, T def = T()) const { + auto const& p = InnerGet(std::move(key)); + if (p != nullptr) { + return *p; + } else { + return def; + } + } + template T const& GetOrThrow(std::string key, ARGS&&... args) const { auto const& p = InnerGet(std::move(key)); diff --git a/src/lib_test_actor_model.h b/src/lib_test_actor_model.h index c63a9da..6ef478e 100644 --- a/src/lib_test_actor_model.h +++ b/src/lib_test_actor_model.h @@ -1,12 +1,8 @@ #pragma once -// #include "lib_c5t_actor_model.h" - #include "typesystem/types.h" struct Event_DL2TEST final : crnt::CurrentSuper { int v; Event_DL2TEST(int v) : v(v) {} }; - -void DefineTestStorageFields(); diff --git a/src/test_c5t_actor_model.cc b/src/test_c5t_actor_model.cc index 134a42b..6df8339 100644 --- a/src/test_c5t_actor_model.cc +++ b/src/test_c5t_actor_model.cc @@ -165,6 +165,39 @@ TEST(ActorModelTest, Smoke) { } } +TEST(ActorModelTest, Nullable) { + auto const b = Topic>("b"); + + std::ostringstream oss; + ActorSubscriberScope s1 = C5T_SUBSCRIBE(b, oss); + + NullableActorSubscriberScope s2; + NullableActorSubscriberScope s3(nullptr); + s2 = nullptr; + EXPECT_FALSE(s2); + EXPECT_FALSE(s3); + + s2 = std::move(s1); + EXPECT_TRUE(s2); + EXPECT_FALSE(s3); + + s3 = std::move(s2); + EXPECT_FALSE(s2); + EXPECT_TRUE(s3); + + oss.clear(); + C5T_EMIT>(b, 501); + C5T_ACTORS_DEBUG_WAIT_FOR_ALL_EVENTS_TO_PROPAGATE(); + EXPECT_EQ("b501", oss.str()); + + s3 = nullptr; + EXPECT_FALSE(s2); + EXPECT_FALSE(s3); + C5T_EMIT>(b, 502); + C5T_ACTORS_DEBUG_WAIT_FOR_ALL_EVENTS_TO_PROPAGATE(); + EXPECT_EQ("b501", oss.str()); +} + TEST(ActorModelTest, InjectedFromDLib) { EXPECT_EQ(42, C5T_DLIB_CALL("test_actor_model", [&](C5T_DLib& dlib) { return dlib.CallOrDefault("Smoke42"); })); diff --git a/src/test_c5t_storage.cc b/src/test_c5t_storage.cc index 6f51eec..3cdffc0 100644 --- a/src/test_c5t_storage.cc +++ b/src/test_c5t_storage.cc @@ -78,6 +78,7 @@ TEST(StorageTest, MapStringString) { { ASSERT_FALSE(C5T_STORAGE(kv1).Has("k")); + ASSERT_EQ("nope", C5T_STORAGE(kv1).GetOrDefault("k", "nope")); ASSERT_THROW(C5T_STORAGE(kv1).GetOrThrow("k"), StorageKeyNotFoundException); ASSERT_FALSE(Exists(C5T_STORAGE(kv1).Get("k"))); } @@ -88,6 +89,8 @@ TEST(StorageTest, MapStringString) { ASSERT_TRUE(C5T_STORAGE(kv1).Has("k")); EXPECT_EQ("v", C5T_STORAGE(kv1).GetOrThrow("k")); + ASSERT_EQ("v", C5T_STORAGE(kv1).GetOrDefault("k", "nope")); + auto const o = C5T_STORAGE(kv1).Get("k"); ASSERT_TRUE(Exists(o)); EXPECT_EQ("v", Value(o));