载入中...
搜索中...
未找到
Rx.h
浏览该文件的文档.
1#pragma once
2
3#include <functional>
4#include <memory>
5#include <mutex>
6#include <string>
7#include <vector>
8
9#include "common/Exception.h"
10
11namespace eve::rx {
12
19class Value {
20public:
21 enum class Type { Nil, Int, Float, Bool, String, Ptr };
22
24 int64_t i = 0;
25 double f = 0;
26 bool b = false;
27 std::string s;
28 void* p = nullptr;
29
31 static Value makeNil() { return {}; }
33 static Value makeInt(int64_t v) {
34 Value x;
36 x.i = v;
37 return x;
38 }
40 static Value makeFloat(double v) {
41 Value x;
43 x.f = v;
44 return x;
45 }
47 static Value makeBool(bool v) {
48 Value x;
50 x.b = v;
51 return x;
52 }
54 static Value makeString(std::string v) {
55 Value x;
57 x.s = std::move(v);
58 return x;
59 }
61 static Value makePtr(void* v) {
62 Value x;
64 x.p = v;
65 return x;
66 }
67
69 bool isNil() const { return type == Type::Nil; }
70 bool isInt() const { return type == Type::Int; }
71 bool isFloat() const { return type == Type::Float; }
72 bool isBool() const { return type == Type::Bool; }
73 bool isString() const { return type == Type::String; }
74 bool isPtr() const { return type == Type::Ptr; }
75
77 int64_t toInt() const;
78 double toFloat() const;
79 bool toBool() const;
80 std::string toString() const;
81
83 bool equals(const Value& o) const;
84};
85
91public:
92 Subscription() = default;
94 explicit Subscription(std::function<void()> dispose) : dispose_(std::move(dispose)) {}
95 Subscription(const Subscription&) = delete;
97 Subscription(Subscription&& other) noexcept : dispose_(std::move(other.dispose_)), disposed_(other.disposed_) {
98 other.dispose_ = nullptr;
99 other.disposed_ = true;
100 }
102 if (this != &other) {
103 dispose();
104 dispose_ = std::move(other.dispose_);
105 disposed_ = other.disposed_;
106 other.dispose_ = nullptr;
107 other.disposed_ = true;
108 }
109 return *this;
110 }
112
114 void dispose() {
115 if (dispose_ && !disposed_) {
116 disposed_ = true;
117 auto fn = std::move(dispose_);
118 dispose_ = nullptr;
119 fn();
120 }
121 }
123 bool isDisposed() const { return disposed_; }
124
125private:
126 std::function<void()> dispose_;
127 bool disposed_ = false;
128};
129
135template <typename T>
136class Observer {
137public:
138 using NextFn = std::function<void(const T&)>;
139 using ErrorFn = std::function<void(const std::string&)>;
140 using CompletedFn = std::function<void()>;
141
148
150 bool isStopped() const { return stopped_; }
152 void setStopped() const { stopped_ = true; }
153
155 void next(const T& v) const {
156 if (!stopped_ && onNext) onNext(v);
157 }
159 void error(const std::string& e) const {
160 if (stopped_) return;
161 stopped_ = true;
162 if (onError) onError(e);
163 }
165 void completed() const {
166 if (stopped_) return;
167 stopped_ = true;
169 }
170
171private:
172 mutable bool stopped_ = false;
173};
174
179template <typename T>
181public:
182 virtual ~Observable() = default;
183
186
189 Observer<T> obs;
190 obs.onNext = std::move(next);
191 return subscribe(std::move(obs));
192 }
196 typename Observer<T>::CompletedFn completed) {
197 Observer<T> obs;
198 obs.onNext = std::move(next);
199 obs.onError = std::move(error);
200 obs.onCompleted = std::move(completed);
201 return subscribe(std::move(obs));
202 }
203
205 Observable<T>* filter(std::function<bool(const T&)> pred);
207 template <typename R>
208 Observable<R>* map(std::function<R(const T&)> fn);
210 Observable<T>* take(int n);
212 Observable<T>* skip(int n);
219};
220
222template <typename T>
224public:
226 : fn_(std::move(fn)) {}
227 Subscription subscribe(Observer<T> obs) override { return fn_(std::move(obs)); }
228
229private:
230 std::function<Subscription(Observer<T>)> fn_;
231};
232
233// ---- Operators ----
234template <typename T>
235Observable<T>* Observable<T>::filter(std::function<bool(const T&)> pred) {
236 auto* self = this;
237 return new AnonymousObservable<T>([self, pred](Observer<T> out) {
238 Observer<T> in;
239 in.onNext = [out, pred](const T& v) {
240 if (pred(v)) out.next(v);
241 };
242 in.onError = [out](const std::string& e) { out.error(e); };
243 in.onCompleted = [out]() { out.completed(); };
244 return self->subscribe(std::move(in));
245 });
246}
247
248template <typename T>
249template <typename R>
250Observable<R>* Observable<T>::map(std::function<R(const T&)> fn) {
251 auto* self = this;
252 return new AnonymousObservable<R>([self, fn](Observer<R> out) {
253 Observer<T> in;
254 in.onNext = [out, fn](const T& v) { out.next(fn(v)); };
255 in.onError = [out](const std::string& e) { out.error(e); };
256 in.onCompleted = [out]() { out.completed(); };
257 return self->subscribe(std::move(in));
258 });
259}
260
261template <typename T>
263 auto* self = this;
264 return new AnonymousObservable<T>([self, n](Observer<T> out) {
265 auto remaining = std::make_shared<int>(n);
266 Observer<T> in;
267 in.onNext = [out, remaining](const T& v) {
268 if (*remaining <= 0) return;
269 *remaining -= 1;
270 out.next(v);
271 if (*remaining == 0) {
272 out.completed();
273 // note: upstream keeps running; completed() already stopped `out`
274 }
275 };
276 in.onError = [out](const std::string& e) { out.error(e); };
277 in.onCompleted = [out]() { out.completed(); };
278 return self->subscribe(std::move(in));
279 });
280}
281
282template <typename T>
284 auto* self = this;
285 return new AnonymousObservable<T>([self, n](Observer<T> out) {
286 auto remaining = std::make_shared<int>(n);
287 Observer<T> in;
288 in.onNext = [out, remaining](const T& v) {
289 if (*remaining > 0) {
290 *remaining -= 1;
291 return;
292 }
293 out.next(v);
294 };
295 in.onError = [out](const std::string& e) { out.error(e); };
296 in.onCompleted = [out]() { out.completed(); };
297 return self->subscribe(std::move(in));
298 });
299}
300
301template <typename T>
303 auto* self = this;
304 return new AnonymousObservable<T>([self](Observer<T> out) {
305 auto done = std::make_shared<bool>(false);
306 Observer<T> in;
307 in.onNext = [out, done](const T& v) {
308 if (*done) return;
309 *done = true;
310 out.next(v);
311 out.completed();
312 };
313 in.onError = [out](const std::string& e) { out.error(e); };
314 in.onCompleted = [out]() { out.completed(); };
315 return self->subscribe(std::move(in));
316 });
317}
318
319template <typename T>
321 auto* self = this;
322 return new AnonymousObservable<T>([self, other](Observer<T> out) {
323 Observer<T> in;
324 in.onNext = [out](const T& v) { out.next(v); };
325 in.onError = [out](const std::string& e) { out.error(e); };
326 in.onCompleted = [out]() { out.completed(); };
327 auto src = std::make_shared<Subscription>(self->subscribe(std::move(in)));
328
329 Observer<T> stopper;
330 stopper.onNext = [out, src](const T&) mutable {
331 out.completed();
332 src->dispose();
333 };
334 stopper.onCompleted = [out, src]() mutable {
335 out.completed();
336 src->dispose();
337 };
338 auto stop = std::make_shared<Subscription>(other->subscribe(std::move(stopper)));
339
340 return Subscription([src, stop]() mutable {
341 src->dispose();
342 stop->dispose();
343 });
344 });
345}
346
347template <typename T>
349 auto* self = this;
350 return new AnonymousObservable<T>([self](Observer<T> out) {
351 auto last = std::make_shared<T>();
352 auto has = std::make_shared<bool>(false);
353 Observer<T> in;
354 in.onNext = [out, last, has](const T& v) {
355 if (*has && *last == v) return;
356 *has = true;
357 *last = v;
358 out.next(v);
359 };
360 in.onError = [out](const std::string& e) { out.error(e); };
361 in.onCompleted = [out]() { out.completed(); };
362 return self->subscribe(std::move(in));
363 });
364}
365
370template <typename T>
371class Subject : public Observable<T> {
372public:
373 using Observable<T>::subscribe;
374 ~Subject() override = default;
375
378 auto slot = std::make_shared<Slot>();
379 slot->observer = std::move(obs);
380 {
381 std::lock_guard<std::mutex> lock(mu_);
382 if (stopped_) {
383 // Terminal state: deliver the terminal notification immediately
384 // to a fresh copy of the observer and never register the slot.
385 Observer<T> snapshot = slot->observer;
386 snapshot.completed();
387 return Subscription{};
388 }
389 slots_.push_back(slot);
390 }
391 return Subscription([this, slot]() { removeSlot(slot); });
392 }
393
395 void onNext(const T& v) { emit([&](Observer<T>& o) { o.next(v); }); }
397 void onError(const std::string& e) {
398 emit([&](Observer<T>& o) { o.error(e); });
399 markStopped();
400 }
402 void onCompleted() {
403 emit([&](Observer<T>& o) { o.completed(); });
404 markStopped();
405 }
406
408 bool hasObservers() const {
409 std::lock_guard<std::mutex> lock(mu_);
410 for (const auto& s : slots_)
411 if (!s->removed) return true;
412 return false;
413 }
415 int observerCount() const {
416 std::lock_guard<std::mutex> lock(mu_);
417 int n = 0;
418 for (const auto& s : slots_)
419 if (!s->removed) n++;
420 return n;
421 }
422
423private:
424 struct Slot {
425 Observer<T> observer;
426 bool removed = false;
427 };
428
429 void emit(const std::function<void(Observer<T>&)>& fn) {
430 std::vector<std::shared_ptr<Slot>> copy;
431 {
432 std::lock_guard<std::mutex> lock(mu_);
433 for (auto& s : slots_)
434 if (!s->removed) copy.push_back(s);
435 }
436 for (auto& s : copy) {
437 Observer<T> snapshot = s->observer;
438 fn(snapshot);
439 }
440 }
441
442 void removeSlot(const std::shared_ptr<Slot>& slot) {
443 std::lock_guard<std::mutex> lock(mu_);
444 slot->removed = true;
445 }
446
447 void markStopped() {
448 std::lock_guard<std::mutex> lock(mu_);
449 stopped_ = true;
450 slots_.clear();
451 }
452
453 mutable std::mutex mu_;
454 std::vector<std::shared_ptr<Slot>> slots_;
455 bool stopped_ = false;
456};
457
462template <typename T>
463class BehaviorSubject : public Observable<T> {
464public:
465 using Observable<T>::subscribe;
467 explicit BehaviorSubject(T initial) : latest_(std::move(initial)) {}
468
471 T latest;
472 bool replay = false;
473 {
474 std::lock_guard<std::mutex> lock(mu_);
475 if (!completed_) {
476 latest = latest_;
477 replay = true;
478 }
479 }
480 if (replay) obs.next(latest);
481 return base_.subscribe(std::move(obs));
482 }
483
485 T getValue() const {
486 std::lock_guard<std::mutex> lock(mu_);
487 return latest_;
488 }
490 void setValue(T v) {
491 T emitted;
492 {
493 std::lock_guard<std::mutex> lock(mu_);
494 latest_ = std::move(v);
495 emitted = latest_;
496 }
497 base_.onNext(emitted);
498 }
500 void onNext(T v) { setValue(std::move(v)); }
502 void onError(const std::string& e) {
503 {
504 std::lock_guard<std::mutex> lock(mu_);
505 completed_ = true;
506 }
507 base_.onError(e);
508 }
510 void onCompleted() {
511 {
512 std::lock_guard<std::mutex> lock(mu_);
513 completed_ = true;
514 }
515 base_.onCompleted();
516 }
518 bool hasObservers() const { return base_.hasObservers(); }
519
520private:
521 mutable std::mutex mu_;
522 T latest_;
523 bool completed_ = false;
524 Subject<T> base_;
525};
526
531template <typename T>
532class ReplaySubject : public Observable<T> {
533public:
534 using Observable<T>::subscribe;
536 explicit ReplaySubject(int capacity = 0) : capacity_(capacity) {}
537
540 std::vector<T> replay;
541 {
542 std::lock_guard<std::mutex> lock(mu_);
543 replay = buffer_;
544 }
545 for (const auto& v : replay)
546 if (!obs.isStopped()) obs.next(v);
547 return base_.subscribe(std::move(obs));
548 }
549
551 void onNext(T v) {
552 T emitted = v;
553 {
554 std::lock_guard<std::mutex> lock(mu_);
555 buffer_.push_back(std::move(v));
556 if (capacity_ > 0 && static_cast<int>(buffer_.size()) > capacity_)
557 buffer_.erase(buffer_.begin());
558 }
559 base_.onNext(emitted);
560 }
562 void onError(const std::string& e) {
563 base_.onError(e);
564 }
566 void onCompleted() {
567 base_.onCompleted();
568 }
570 bool hasObservers() const { return base_.hasObservers(); }
571
572private:
573 mutable std::mutex mu_;
574 std::vector<T> buffer_;
575 int capacity_;
576 Subject<T> base_;
577};
578
583template <typename T>
585public:
587 explicit ReactiveProperty(T initial = T()) : subject_(std::move(initial)) {}
588
590 T get() const { return subject_.getValue(); }
592 void set(T v) { subject_.setValue(std::move(v)); }
593
595 Subscription subscribe(Observer<T> obs) { return subject_.subscribe(std::move(obs)); }
596 Subscription subscribe(typename Observer<T>::NextFn next) { return subject_.subscribe(std::move(next)); }
597
599 BehaviorSubject<T>* asSubject() { return &subject_; }
600 Observable<T>* asObservable() { return &subject_; }
601
602private:
603 BehaviorSubject<T> subject_;
604};
605
606} // namespace eve::rx
bool removed
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
std::string error
std::string filter
SettlementPipeline::Stage fn
int v
uint32_t s
Definition Weather.cpp:28
Internal: observable built directly from a subscribe function.
Definition Rx.h:223
Subscription subscribe(Observer< T > obs) override
Subscribes with a full observer; returns a cancel handle.
Definition Rx.h:227
AnonymousObservable(std::function< Subscription(Observer< T >)> fn)
Definition Rx.h:225
Subject that replays the latest value to every new subscriber. setValue()/onNext() update the stored ...
Definition Rx.h:463
void onCompleted()
Stops replay and delivers a terminal completion.
Definition Rx.h:510
bool hasObservers() const
True while at least one live observer is registered.
Definition Rx.h:518
T getValue() const
Current stored value.
Definition Rx.h:485
void onNext(T v)
Alias of setValue().
Definition Rx.h:500
void onError(const std::string &e)
Stops replay and delivers a terminal error.
Definition Rx.h:502
void setValue(T v)
Stores a new value and pushes it to observers.
Definition Rx.h:490
BehaviorSubject(T initial)
Creates a subject with an initial (replayed) value.
Definition Rx.h:467
Subscription subscribe(Observer< T > obs) override
Replays the latest value, then subscribes the observer.
Definition Rx.h:470
Push-based stream source. Operators return a new (caller-owned) Observable; subscribe() returns a Sub...
Definition Rx.h:180
virtual Subscription subscribe(Observer< T > obs)=0
Subscribes with a full observer; returns a cancel handle.
Observable< T > * filter(std::function< bool(const T &)> pred)
Passes values through only when pred(v) is true.
Definition Rx.h:235
Observable< T > * distinctUntilChanged()
Suppresses consecutive duplicate values (uses operator==).
Definition Rx.h:348
Observable< T > * takeUntil(Observable< T > *other)
Stops the stream when other emits or completes.
Definition Rx.h:320
Observable< R > * map(std::function< R(const T &)> fn)
Transforms each value with fn.
Definition Rx.h:250
virtual ~Observable()=default
Subscription subscribe(typename Observer< T >::NextFn next)
Subscribes with a value callback only.
Definition Rx.h:188
Observable< T > * skip(int n)
Drops the first n values.
Definition Rx.h:283
Observable< T > * take(int n)
Emits at most the first n values, then completes.
Definition Rx.h:262
Observable< T > * first()
Emits only the first value, then completes.
Definition Rx.h:302
Subscription subscribe(typename Observer< T >::NextFn next, typename Observer< T >::ErrorFn error, typename Observer< T >::CompletedFn completed)
Subscribes with value/error/completed callbacks.
Definition Rx.h:194
Callback bundle pushed to a subscriber. Once error() or completed() fires the observer is stopped and...
Definition Rx.h:136
CompletedFn onCompleted
Completion callback (terminal).
Definition Rx.h:147
void error(const std::string &e) const
Delivers a terminal error and stops.
Definition Rx.h:159
std::function< void(const T &)> NextFn
Definition Rx.h:138
void completed() const
Delivers a terminal completion and stops.
Definition Rx.h:165
NextFn onNext
Value callback.
Definition Rx.h:143
std::function< void(const std::string &)> ErrorFn
Definition Rx.h:139
bool isStopped() const
True after error()/completed() (or setStopped()).
Definition Rx.h:150
ErrorFn onError
Error callback (terminal).
Definition Rx.h:145
std::function< void()> CompletedFn
Definition Rx.h:140
void next(const T &v) const
Delivers a value unless stopped.
Definition Rx.h:155
void setStopped() const
Manually marks the observer stopped (used by operators).
Definition Rx.h:152
Observable value backed by a BehaviorSubject. get() returns the current value; set() stores and pushe...
Definition Rx.h:584
ReactiveProperty(T initial=T())
Creates a property with an initial value.
Definition Rx.h:587
BehaviorSubject< T > * asSubject()
Underlying behavior subject / observable view.
Definition Rx.h:599
T get() const
Current value.
Definition Rx.h:590
void set(T v)
Stores a new value and notifies subscribers.
Definition Rx.h:592
Subscription subscribe(typename Observer< T >::NextFn next)
Definition Rx.h:596
Subscription subscribe(Observer< T > obs)
Subscribes with a full observer or a value callback.
Definition Rx.h:595
Observable< T > * asObservable()
Definition Rx.h:600
Subject that buffers up to capacity values (0 = unlimited) and replays the buffer to every new subscr...
Definition Rx.h:532
ReplaySubject(int capacity=0)
Creates a replaying subject with the given buffer capacity.
Definition Rx.h:536
void onNext(T v)
Buffers and pushes a new value to observers.
Definition Rx.h:551
Subscription subscribe(Observer< T > obs) override
Replays buffered values, then subscribes the observer.
Definition Rx.h:539
void onCompleted()
Delivers a terminal completion to observers.
Definition Rx.h:566
void onError(const std::string &e)
Delivers a terminal error to observers.
Definition Rx.h:562
bool hasObservers() const
True while at least one live observer is registered.
Definition Rx.h:570
Multicast push-based stream: both an Observable and a push source. Thread-safe: onNext/onError/onComp...
Definition Rx.h:371
int observerCount() const
Number of live (non-disposed) observers.
Definition Rx.h:415
~Subject() override=default
Subscription subscribe(Observer< T > obs) override
Registers an observer; returns a Subscription that unregisters it.
Definition Rx.h:377
bool hasObservers() const
True while at least one live observer is registered.
Definition Rx.h:408
void onCompleted()
Pushes a terminal completion and stops the subject.
Definition Rx.h:402
void onNext(const T &v)
Pushes a value to every registered observer.
Definition Rx.h:395
void onError(const std::string &e)
Pushes a terminal error and stops the subject.
Definition Rx.h:397
RAII-style dispose handle for an active stream subscription. Disposing unsubscribes from the source; ...
Definition Rx.h:90
void dispose()
Runs the dispose callback once; idempotent.
Definition Rx.h:114
Subscription(std::function< void()> dispose)
Wraps a dispose callback (usually unsubscribing from a Subject).
Definition Rx.h:94
bool isDisposed() const
True once dispose() has run (or the handle was moved from).
Definition Rx.h:123
Subscription & operator=(Subscription &&other) noexcept
Definition Rx.h:101
Subscription(const Subscription &)=delete
Subscription & operator=(const Subscription &)=delete
Subscription(Subscription &&other) noexcept
Definition Rx.h:97
Runtime variant used by the script-facing (Squirrel) streams. The C++ core is templated (Observer<T>/...
Definition Rx.h:19
Type type
Definition Rx.h:23
bool toBool() const
Definition Rx.cpp:46
double toFloat() const
Definition Rx.cpp:31
bool isNil() const
Type predicates.
Definition Rx.h:69
bool isInt() const
Definition Rx.h:70
static Value makeFloat(double v)
Constructs a floating-point value.
Definition Rx.h:40
bool isFloat() const
Definition Rx.h:71
static Value makeNil()
Constructs a nil value.
Definition Rx.h:31
bool isString() const
Definition Rx.h:73
bool b
Definition Rx.h:26
static Value makePtr(void *v)
Constructs a pointer value (borrowed, not owned).
Definition Rx.h:61
int64_t toInt() const
Converters (throw eve::Exception on type mismatch).
Definition Rx.cpp:16
std::string s
Definition Rx.h:27
static Value makeInt(int64_t v)
Constructs an integer value.
Definition Rx.h:33
bool equals(const Value &o) const
Value equality across the supported types.
Definition Rx.cpp:68
double f
Definition Rx.h:25
void * p
Definition Rx.h:28
static Value makeString(std::string v)
Constructs a string value (takes ownership).
Definition Rx.h:54
bool isBool() const
Definition Rx.h:72
int64_t i
Definition Rx.h:24
bool isPtr() const
Definition Rx.h:74
static Value makeBool(bool v)
Constructs a boolean value.
Definition Rx.h:47
std::string toString() const
Definition Rx.cpp:57
Definition Rx.cpp:11