LeviLamina
Loading...
Searching...
No Matches
Observable.h
1#pragma once
2
3#include <cstdint>
4#include <map>
5#include <memory>
6#include <utility>
7
8#include "ll/api/base/StdInt.h"
9#include "mc/platform/brstd/move_only_function.h"
10
11namespace ll::data {
12
13template <class T>
14class Observable {
15public:
16 using Callback = brstd::move_only_function<void(T const&)>;
17 using SubscriptionId = uint32;
18
19private:
20 struct State {
21 explicit State(T initial) : data(std::move(initial)) {}
22
23 std::map<SubscriptionId, Callback> callbacks;
24 SubscriptionId nextId{};
25 T data;
26 };
27
28 std::shared_ptr<State> state;
29
30public:
31 explicit Observable(T initial) : state(std::make_shared<State>(std::move(initial))) {}
32
33 Observable(Observable const&) = default;
34 Observable& operator=(Observable const&) = default;
35 Observable(Observable&&) noexcept = default;
36 Observable& operator=(Observable&&) noexcept = default;
37
38 [[nodiscard]] T getData() const { return state->data; }
39
40 void setData(T value) {
41 if (state->data == value) {
42 return;
43 }
44 state->data = std::move(value);
45
46 for (auto& [_, callback] : state->callbacks) {
47 callback(state->data);
48 }
49 }
50
51 SubscriptionId subscribe(Callback callback) {
52 if (!callback) {
53 return 0;
54 }
55
56 auto const id = ++state->nextId;
57 state->callbacks.emplace(id, std::move(callback));
58 return id;
59 }
60
61 bool unsubscribe(SubscriptionId id) {
62 if (id == 0) {
63 return false;
64 }
65 return state->callbacks.erase(id) != 0;
66 }
67};
68
69} // namespace ll::data
Definition move_only_function.h:9