From 746a80e5cb6d1de1e3e85b6855847bd3a16f5ce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9=20Larivi=C3=A8re?= Date: Wed, 14 Feb 2024 16:10:35 +0100 Subject: [PATCH 1/2] Lock access to fn in Cmd.debounce to avoid null crash --- src/Fabulous/Cmd.fs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/Fabulous/Cmd.fs b/src/Fabulous/Cmd.fs index 2c01fb7ad..0cadd9c87 100644 --- a/src/Fabulous/Cmd.fs +++ b/src/Fabulous/Cmd.fs @@ -194,19 +194,23 @@ module Cmd = fun (value: 'value) -> [ fun dispatch -> - if cts <> null then - cts.Cancel() - cts.Dispose() - - cts <- new CancellationTokenSource() - - Async.Start( - async { - do! Async.Sleep(timeout) - dispatch(fn value) - - cts.Dispose() - cts <- null - }, - cts.Token - ) ] + lock fn (fun () -> + if cts <> null then + cts.Cancel() + cts.Dispose() + + cts <- new CancellationTokenSource() + + Async.Start( + async { + do! Async.Sleep(timeout) + lock fn (fun () -> + dispatch(fn value) + + if cts <> null then + cts.Dispose() + cts <- null + ) + }, + cts.Token + ) ) ] From 1045e0388b8f85bc6f8bd78e5ef3f570ac0af054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9=20Larivi=C3=A8re?= Date: Wed, 14 Feb 2024 16:34:03 +0100 Subject: [PATCH 2/2] Change to lock object --- src/Fabulous/Cmd.fs | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/Fabulous/Cmd.fs b/src/Fabulous/Cmd.fs index 0cadd9c87..4a4b96956 100644 --- a/src/Fabulous/Cmd.fs +++ b/src/Fabulous/Cmd.fs @@ -190,27 +190,28 @@ module Cmd = /// Command to issue a message if no other message has been issued within the specified timeout let debounce (timeout: int) (fn: 'value -> 'msg) : 'value -> Cmd<'msg> = + let funLock = obj() let mutable cts: CancellationTokenSource = null fun (value: 'value) -> [ fun dispatch -> - lock fn (fun () -> - if cts <> null then - cts.Cancel() - cts.Dispose() - - cts <- new CancellationTokenSource() - - Async.Start( - async { - do! Async.Sleep(timeout) - lock fn (fun () -> - dispatch(fn value) - - if cts <> null then - cts.Dispose() - cts <- null - ) - }, - cts.Token - ) ) ] + lock funLock (fun () -> + if cts <> null then + cts.Cancel() + cts.Dispose() + + cts <- new CancellationTokenSource() + + Async.Start( + async { + do! Async.Sleep(timeout) + + lock funLock (fun () -> + dispatch(fn value) + + if cts <> null then + cts.Dispose() + cts <- null) + }, + cts.Token + )) ]