5#include <simplesquirrel/simplesquirrel.hpp>
9#include <unordered_map>
23 return static_cast<int64_t
>(std::stoll(
s));
53 default:
return false;
98 sq_pushstring(
vm,
v.s.c_str(),
static_cast<SQInteger
>(
v.s.size()));
106 switch (sq_gettype(
vm, index)) {
110 sq_getinteger(
vm, index, &i);
115 sq_getfloat(
vm, index, &
f);
120 sq_getbool(
vm, index, &
b);
124 const SQChar*
s =
nullptr;
125 sq_getstring(
vm, index, &
s);
128 case OT_USERPOINTER: {
129 SQUserPointer
p =
nullptr;
130 sq_getuserpointer(
vm, index, &
p);
154Value callScript(
const ssq::Function&
fn,
const std::vector<Value>& args,
bool wantResult) {
157 SQInteger top = sq_gettop(raw);
158 sq_pushobject(raw,
fn.getRaw());
159 sq_pushroottable(raw);
162 if (SQ_SUCCEEDED(sq_call(raw,
static_cast<SQInteger
>(args.size() + 1),
163 wantResult ? SQTrue : SQFalse, SQTrue))) {
164 if (wantResult && sq_gettop(raw) > top) result = ssq::detail::popValue<Value>(raw, -1);
170std::function<void()> scriptCompleted(ssq::Function
fn) {
171 return [
fn]() { callScript(
fn, {},
false); };
173std::function<void(
const Value&)> scriptNext(ssq::Function
fn) {
174 return [
fn](
const Value&
v) { callScript(
fn, {
v},
false); };
176std::function<void(
const std::string&)> scriptError(ssq::Function
fn) {
180bool isClosure(
const ssq::Object& obj) {
181 if (obj.isEmpty())
return false;
182 auto t = obj.getType();
183 return t == ssq::Type::CLOSURE || t == ssq::Type::NATIVECLOSURE;
187ssq::Object asClosure(
const ssq::Object& obj) {
188 if (isClosure(obj))
return obj;
189 return ssq::Object();
194 ssq::Object
n = asClosure(next);
195 ssq::Object e = asClosure(
error);
196 ssq::Object
c = asClosure(done);
197 if (!
n.isEmpty()) o.
onNext = scriptNext(
n.toFunction());
198 if (!e.isEmpty()) o.
onError = scriptError(e.toFunction());
199 if (!
c.isEmpty()) o.
onCompleted = scriptCompleted(
c.toFunction());
214 in.
onError = [out](
const std::string& e) { out.
error(e); };
225 if (callScript(pred, {
v},
true).toBool()) out.
next(
v);
227 in.
onError = [out](
const std::string& e) { out.
error(e); };
236 auto remaining = std::make_shared<int>(
n);
239 if (*remaining <= 0)
return;
244 in.
onError = [out](
const std::string& e) { out.
error(e); };
253 auto remaining = std::make_shared<int>(
n);
256 if (*remaining > 0) {
262 in.
onError = [out](
const std::string& e) { out.
error(e); };
271 auto done = std::make_shared<bool>(
false);
279 in.
onError = [out](
const std::string& e) { out.
error(e); };
286 if (!self)
throw eve::Exception(
"Rx.distinctUntilChanged: null observable");
288 auto last = std::make_shared<Value>();
289 auto has = std::make_shared<bool>(
false);
292 if (*has && last->equals(
v))
return;
297 in.
onError = [out](
const std::string& e) { out.
error(e); };
320 auto subject = std::make_shared<SubjectV>();
322 std::lock_guard<std::mutex> lock(mu_);
323 bridges_[
name] = subject;
329 return subject->subscribe(std::move(out));
336 while ((msg = ev->
poll()) !=
nullptr) {
339 for (
const auto&
a : msg->
args) {
346 std::shared_ptr<SubjectV> subject;
348 std::lock_guard<std::mutex> lock(mu_);
349 auto it = bridges_.find(
name);
350 if (it != bridges_.end()) subject = it->second;
358 std::unordered_map<std::string, std::shared_ptr<SubjectV>> bridges_;
370void bindCommon(ssq::Class&
cls) {
371 cls.addFunc(
"subscribe",
373 [](
ObservableV* self, ssq::Object
n) {
return doSubscribe(self,
n, {}, {}); }));
374 cls.addFunc(
"subscribe3",
375 std::function<Subscription*(
ObservableV*, ssq::Object, ssq::Object, ssq::Object)>(
376 [](
ObservableV* self, ssq::Object
n, ssq::Object e, ssq::Object
d) {
377 return doSubscribe(self,
n, e,
d);
381 [](
ObservableV* self, ssq::Function
f) {
return doMap(self,
f); }));
382 cls.addFunc(
"filter",
384 [](
ObservableV* self, ssq::Function
p) {
return doFilter(self,
p); }));
393 cls.addFunc(
"distinctUntilChanged",
395 [](
ObservableV* self) {
return doDistinctUntilChanged(self); }));
400void Rx::expose(ssq::Table& table) {
401 auto cls = table.addClass(
name, Rx::create,
false);
405 "Observable", std::function<ObservableV*()>([]() ->
ObservableV* {
return nullptr; }),
true);
408 auto subject = table.addClass<
SubjectV>(
409 "Subject", std::function<SubjectV*()>([]() ->
SubjectV* {
return nullptr; }),
true);
417 "BehaviorSubject", std::function<BehaviorSubjectV*()>([]() ->
BehaviorSubjectV* {
return nullptr; }),
true);
424 bindCommon(behavior);
427 "ReplaySubject", std::function<ReplaySubjectV*()>([]() ->
ReplaySubjectV* {
return nullptr; }),
true);
435 "ReactiveProperty", std::function<ReactivePropertyV*()>([]() ->
ReactivePropertyV* {
return nullptr; }),
true);
438 prop.addFunc(
"subscribe",
442 return doSubscribe(self->asObservable(),
n, {}, {});
444 prop.addFunc(
"subscribe3",
445 std::function<Subscription*(
ReactivePropertyV*, ssq::Object, ssq::Object, ssq::Object)>(
448 return doSubscribe(self->asObservable(),
n, e,
d);
451 auto sub = table.addClass<Subscription>(
452 "Subscription", std::function<Subscription*()>([]() -> Subscription* {
return nullptr; }),
true);
457void Rx::expose(ssq::Class&
cls) {
struct SQVM * HSQUIRRELVM
#define Module_IMPL(ModuleName, newExpr)
SettlementPipeline::Stage fn
virtual std::string getName() const =0
Message * poll()
Pops the oldest message, or nullptr if the queue is empty (caller must delete).
A named event carrying an ordered list of Variant payloads. Pushed messages are heap-allocated; the q...
const std::vector< Variant > args
Internal: observable built directly from a subscribe function.
Subject that replays the latest value to every new subscriber. setValue()/onNext() update the stored ...
void onCompleted()
Stops replay and delivers a terminal completion.
bool hasObservers() const
True while at least one live observer is registered.
T getValue() const
Current stored value.
void onNext(T v)
Alias of setValue().
void onError(const std::string &e)
Stops replay and delivers a terminal error.
void setValue(T v)
Stores a new value and pushes it to observers.
Push-based stream source. Operators return a new (caller-owned) Observable; subscribe() returns a Sub...
virtual Subscription subscribe(Observer< T > obs)=0
Subscribes with a full observer; returns a cancel handle.
Callback bundle pushed to a subscriber. Once error() or completed() fires the observer is stopped and...
CompletedFn onCompleted
Completion callback (terminal).
void error(const std::string &e) const
Delivers a terminal error and stops.
void completed() const
Delivers a terminal completion and stops.
NextFn onNext
Value callback.
ErrorFn onError
Error callback (terminal).
void next(const T &v) const
Delivers a value unless stopped.
Observable value backed by a BehaviorSubject. get() returns the current value; set() stores and pushe...
T get() const
Current value.
void set(T v)
Stores a new value and notifies subscribers.
Subject that buffers up to capacity values (0 = unlimited) and replays the buffer to every new subscr...
void onNext(T v)
Buffers and pushes a new value to observers.
void onCompleted()
Delivers a terminal completion to observers.
void onError(const std::string &e)
Delivers a terminal error to observers.
bool hasObservers() const
True while at least one live observer is registered.
ReactivePropertyV * newProperty(const Value &initial)
ReplaySubjectV * newReplaySubject(int capacity=0)
BehaviorSubjectV * newBehaviorSubject(const Value &initial)
ObservableV * fromEvent(const std::string &name)
void pump(event::Event *ev)
Multicast push-based stream: both an Observable and a push source. Thread-safe: onNext/onError/onComp...
bool hasObservers() const
True while at least one live observer is registered.
void onCompleted()
Pushes a terminal completion and stops the subject.
void onNext(const T &v)
Pushes a value to every registered observer.
void onError(const std::string &e)
Pushes a terminal error and stops the subject.
RAII-style dispose handle for an active stream subscription. Disposing unsubscribes from the source; ...
void dispose()
Runs the dispose callback once; idempotent.
bool isDisposed() const
True once dispose() has run (or the handle was moved from).
Runtime variant used by the script-facing (Squirrel) streams. The C++ core is templated (Observer<T>/...
static Value makeFloat(double v)
Constructs a floating-point value.
static Value makeNil()
Constructs a nil value.
static Value makePtr(void *v)
Constructs a pointer value (borrowed, not owned).
int64_t toInt() const
Converters (throw eve::Exception on type mismatch).
static Value makeInt(int64_t v)
Constructs an integer value.
bool equals(const Value &o) const
Value equality across the supported types.
static Value makeString(std::string v)
Constructs a string value (takes ownership).
static Value makeBool(bool v)
Constructs a boolean value.
std::string toString() const
ReactiveProperty< Value > ReactivePropertyV
Observable< Value > ObservableV
Subject< Value > SubjectV
BehaviorSubject< Value > BehaviorSubjectV
ReplaySubject< Value > ReplaySubjectV
void pushValue(HSQUIRRELVM vm, const eve::rx::Value &v)
eve::rx::Value popValue(HSQUIRRELVM vm, SQInteger index)
EVEngine ECS 集成层:底层实现使用 sunxfancy/ECS.hpp https://github.com/sunxfancy/ECS.hpp