From 44ab21ab35d2ede6f8fc1e9391c0271bc0e58146 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 1 May 2023 04:44:03 -0700 Subject: [PATCH] Scripting: Allow callbacks to access weakrefs --- src/script/context.c | 23 +++++++++++++++------ src/script/test/stdlib.c | 44 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/script/context.c b/src/script/context.c index 352c4d278..85c3de485 100644 --- a/src/script/context.c +++ b/src/script/context.c @@ -235,12 +235,15 @@ void mScriptContextTriggerCallback(struct mScriptContext* context, const char* c do { struct mScriptFrame frame; struct mScriptCallbackInfo* info = TableIteratorGetValue(table, &iter); - mScriptFrameInit(&frame); - if (args) { - mScriptListCopy(&frame.arguments, args); + struct mScriptValue* fn = mScriptContextAccessWeakref(context, info->fn); + if (fn) { + mScriptFrameInit(&frame); + if (args) { + mScriptListCopy(&frame.arguments, args); + } + mScriptInvoke(fn, &frame); + mScriptFrameDeinit(&frame); } - mScriptInvoke(info->fn, &frame); - mScriptFrameDeinit(&frame); if (info->oneshot) { *UInt32ListAppend(&oneshots) = info->id; @@ -255,7 +258,15 @@ void mScriptContextTriggerCallback(struct mScriptContext* context, const char* c } static uint32_t mScriptContextAddCallbackInternal(struct mScriptContext* context, const char* callback, struct mScriptValue* fn, bool oneshot) { - if (fn->type->base != mSCRIPT_TYPE_FUNCTION) { + if (fn->type == mSCRIPT_TYPE_MS_WEAKREF) { + struct mScriptValue* weakref = mScriptContextAccessWeakref(context, fn); + if (!weakref) { + return 0; + } + if (weakref->type->base != mSCRIPT_TYPE_FUNCTION) { + return 0; + } + } else if (fn->type->base != mSCRIPT_TYPE_FUNCTION) { return 0; } struct Table* table = HashTableLookup(&context->callbacks, callback); diff --git a/src/script/test/stdlib.c b/src/script/test/stdlib.c index 852894a34..eda6deb7b 100644 --- a/src/script/test/stdlib.c +++ b/src/script/test/stdlib.c @@ -126,9 +126,53 @@ M_TEST_DEFINE(oneshot) { mScriptContextDeinit(&context); } +static void _tableIncrement(struct mScriptValue* table) { + assert_non_null(table); + struct mScriptValue* value = mScriptTableLookup(table, &mSCRIPT_MAKE_CHARP("key")); + assert_non_null(value); + assert_ptr_equal(value->type, mSCRIPT_TYPE_MS_S32); + ++value->value.s32; +} + +mSCRIPT_BIND_VOID_FUNCTION(tableIncrement, _tableIncrement, 1, WTABLE, table); + +M_TEST_DEFINE(callbackWeakref) { + SETUP_LUA; + + struct mScriptValue* table = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE); + struct mScriptList args; + mScriptListInit(&args, 1); + mScriptValueWrap(table, mScriptListAppend(&args)); + struct mScriptValue* lambda = mScriptLambdaCreate0(&tableIncrement, &args); + mScriptListDeinit(&args); + struct mScriptValue* weakref = mScriptContextMakeWeakref(&context, lambda); + mScriptContextAddCallback(&context, "test", weakref); + + struct mScriptValue* key = mScriptStringCreateFromUTF8("key"); + struct mScriptValue* value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S32); + value->value.s32 = 1; + mScriptTableInsert(table, key, value); + + mScriptContextTriggerCallback(&context, "test", NULL); + assert_int_equal(value->value.s32, 2); + + mScriptContextClearWeakref(&context, weakref->value.u32); + mScriptValueDeref(weakref); + + mScriptContextTriggerCallback(&context, "test", NULL); + assert_int_equal(value->value.s32, 2); + + mScriptValueDeref(table); + mScriptValueDeref(key); + mScriptValueDeref(value); + + mScriptContextDeinit(&context); +} + M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptStdlib, cmocka_unit_test(bitMask), cmocka_unit_test(bitUnmask), cmocka_unit_test(callbacks), cmocka_unit_test(oneshot), + cmocka_unit_test(callbackWeakref), )