From 7a637967fe34a9cb9c71006f34a26061aad8d96c Mon Sep 17 00:00:00 2001 From: Orkuncakilkaya Date: Mon, 28 Sep 2026 01:21:53 +0300 Subject: [PATCH] fix(leaks): effects_live_into / effects_live_count and hints_rail_into - a HUD's read-outs into lists it keeps Co-Authored-By: Claude Opus 5.5 --- packages/ludic.effects/queries.ludic | 18 +++++++++++++++--- .../ludic.effects/tests/effects_test.ludic | 5 +++++ packages/ludic.hints/index.ludic | 1 + packages/ludic.hints/rail_into.ludic | 7 +++++++ packages/ludic.hints/tests/hints_test.ludic | 5 +++++ 5 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 packages/ludic.hints/rail_into.ludic diff --git a/packages/ludic.effects/queries.ludic b/packages/ludic.effects/queries.ludic index 5ce998c2..65245069 100644 --- a/packages/ludic.effects/queries.ludic +++ b/packages/ludic.effects/queries.ludic @@ -38,10 +38,22 @@ export function effects_at(effects_st: EffectsState, i: int) -> Effect { return e } -# the indices of the ones that have begun, for a read-out +# the indices of the ones that have begun, for a read-out (a frame's read-out fills its own list) export function effects_live(effects_st: EffectsState) -> []int { let out = new []int - let all = ef_all(effects_st) - for i in 0 .. len(all) { if ef_live(all[i]) { push(out, i) } } + effects_live_into(effects_st, out) return out } + +export function effects_live_into(effects_st: EffectsState, out: []int) -> void { + List.clear(out) + let all = ef_all(effects_st) + for i in 0 .. len(all) { if ef_live(all[i]) { push(out, i) } } +} + +export function effects_live_count(effects_st: EffectsState) -> int { + var n = 0 + let all = ef_all(effects_st) + for i in 0 .. len(all) { if ef_live(all[i]) { n += 1 } } + return n +} diff --git a/packages/ludic.effects/tests/effects_test.ludic b/packages/ludic.effects/tests/effects_test.ludic index d370e92d..cce617df 100644 --- a/packages/ludic.effects/tests/effects_test.ludic +++ b/packages/ludic.effects/tests/effects_test.ludic @@ -71,6 +71,11 @@ program EffectsTest { effects_add_after(effects_st, 20.0, LEGS, -5.0, 15.0, false, "Sugar crash") expect(effects_sum(effects_st, LEGS) == 8.0) expect_eq(len(effects_live(effects_st)), 1) + expect_eq(effects_live_count(effects_st), 1) + let kept = new []int + effects_live_into(effects_st, kept) + effects_live_into(effects_st, kept) + expect_eq(len(kept), 1) tick_minutes(25.0) expect(effects_sum(effects_st, LEGS) == -5.0) tick_minutes(20.0) diff --git a/packages/ludic.hints/index.ludic b/packages/ludic.hints/index.ludic index 95bf889e..630237f6 100644 --- a/packages/ludic.hints/index.ludic +++ b/packages/ludic.hints/index.ludic @@ -6,6 +6,7 @@ import "ludic.base" import "defs.ludic" import "port.ludic" import "rail.ludic" +import "rail_into.ludic" import "card.ludic" import "mute.ludic" import "system.ludic" diff --git a/packages/ludic.hints/rail_into.ludic b/packages/ludic.hints/rail_into.ludic new file mode 100644 index 00000000..07adfae1 --- /dev/null +++ b/packages/ludic.hints/rail_into.ludic @@ -0,0 +1,7 @@ +# rail_into.ludic - the rail into a list the caller keeps: a HUD asks every frame, and a list made +# each time is never given back +export function hints_rail_into(hints_st: HintsState, out: []int) -> void { + List.clear(out) + if not HintsWorld.showing() { return } + for k in 0 .. hints_st.hn_n { push(out, hints_st.hn_top[k]) } +} diff --git a/packages/ludic.hints/tests/hints_test.ludic b/packages/ludic.hints/tests/hints_test.ludic index 941a203f..a8642a6f 100644 --- a/packages/ludic.hints/tests/hints_test.ludic +++ b/packages/ludic.hints/tests/hints_test.ludic @@ -74,6 +74,11 @@ program HintsTest { hints_test_st.showing = true hints_sort(hints_st) expect_eq(len(hints_rail(hints_st)), 1) + let kept = new []int + hints_rail_into(hints_st, kept) + hints_rail_into(hints_st, kept) + expect_eq(len(kept), 1) + expect_eq(kept[0], hints_rail(hints_st)[0]) } test "the key opens the picked chip, the arrows walk round, the key puts it down" (hints_st: mut HintsState, hints_test_st: mut HintsTestState) {