1+ // ---------------------------------------------------------------------------------------------------------------------
2+ // Imports
3+ // ---------------------------------------------------------------------------------------------------------------------
4+ namespace CodeOfChaos . Extensions . Debouncers ;
5+
6+ // ---------------------------------------------------------------------------------------------------------------------
7+ // Code
8+ // ---------------------------------------------------------------------------------------------------------------------
9+ public sealed class ThrottledDebouncer : ThrottledDebouncerBase < ThrottledDebouncer . EmptyUnit > {
10+ public readonly struct EmptyUnit ; // Workaround for reusing ThrottledDebouncerBase<T> instead of creating a fully new DebouncerBase without generics
11+ private object Callback { get ; init ; } = null ! ;
12+
13+ // -----------------------------------------------------------------------------------------------------------------
14+ // Constructors
15+ // -----------------------------------------------------------------------------------------------------------------
16+ private ThrottledDebouncer ( ) { }
17+ public static ThrottledDebouncer FromDelegate ( Action action , int debounceMs = DefaultDebounceMs , int throttleMs = DefaultThrottleMs )
18+ => new ( ) {
19+ Callback = action ,
20+ DebounceMs = debounceMs ,
21+ ThrottleMs = throttleMs
22+ } ;
23+
24+ public static ThrottledDebouncer FromDelegate ( Func < CancellationToken , Task > func , int debounceMs = DefaultDebounceMs , int throttleMs = DefaultThrottleMs )
25+ => new ( ) {
26+ Callback = func ,
27+ DebounceMs = debounceMs ,
28+ ThrottleMs = throttleMs
29+ } ;
30+
31+ public static ThrottledDebouncer FromDelegate ( Func < Task > func , int debounceMs = DefaultDebounceMs , int throttleMs = DefaultThrottleMs )
32+ => new ( ) {
33+ Callback = func ,
34+ DebounceMs = debounceMs ,
35+ ThrottleMs = throttleMs
36+ } ;
37+
38+ // -----------------------------------------------------------------------------------------------------------------
39+ // Methods
40+ // -----------------------------------------------------------------------------------------------------------------
41+ public Task InvokeDebouncedAsync ( CancellationToken ct = default )
42+ => DebouncerLogicAsync ( default , ct ) ;
43+
44+ protected async override ValueTask InvokeCallbackAsync ( EmptyUnit item , CancellationToken ct = default ) {
45+ if ( ct . IsCancellationRequested ) return ;
46+
47+ switch ( Callback ) {
48+
49+ case Action action : {
50+ action . Invoke ( ) ;
51+ break ;
52+ }
53+
54+ case Func < Task > func : {
55+ await func . Invoke ( ) ;
56+ break ;
57+ }
58+
59+ case Func < CancellationToken , Task > func : {
60+ await func . Invoke ( ct ) ;
61+ break ;
62+ }
63+
64+ default : throw new InvalidOperationException ( "Invalid function type" ) ;
65+ }
66+ }
67+ }
68+
69+ public sealed class ThrottledDebouncer < T > : ThrottledDebouncerBase < T > {
70+ private object Callback { get ; init ; } = null ! ;
71+
72+ // -----------------------------------------------------------------------------------------------------------------
73+ // Constructors
74+ // -----------------------------------------------------------------------------------------------------------------
75+ private ThrottledDebouncer ( ) { }
76+ public static ThrottledDebouncer < T > FromDelegate ( Action < T > action , int debounceMs = DefaultDebounceMs , int throttleMs = DefaultThrottleMs )
77+ => new ( ) {
78+ Callback = action ,
79+ DebounceMs = debounceMs ,
80+ ThrottleMs = throttleMs
81+ } ;
82+
83+ public static ThrottledDebouncer < T > FromDelegate ( Func < T , Task > func , int debounceMs = DefaultDebounceMs , int throttleMs = DefaultThrottleMs )
84+ => new ( ) {
85+ Callback = func ,
86+ DebounceMs = debounceMs ,
87+ ThrottleMs = throttleMs
88+ } ;
89+
90+ public static ThrottledDebouncer < T > FromDelegate ( Func < T , CancellationToken , Task > func , int debounceMs = DefaultDebounceMs , int throttleMs = DefaultThrottleMs )
91+ => new ( ) {
92+ Callback = func ,
93+ DebounceMs = debounceMs ,
94+ ThrottleMs = throttleMs
95+ } ;
96+
97+ // -----------------------------------------------------------------------------------------------------------------
98+ // Methods
99+ // -----------------------------------------------------------------------------------------------------------------
100+ public Task InvokeDebouncedAsync ( T item , CancellationToken ct = default )
101+ => DebouncerLogicAsync ( item , ct ) ;
102+
103+ protected async override ValueTask InvokeCallbackAsync ( T item , CancellationToken ct = default ) {
104+ if ( ct . IsCancellationRequested ) return ;
105+
106+ switch ( Callback ) {
107+ case Action < T > action : {
108+ action . Invoke ( item ) ;
109+ break ;
110+ }
111+
112+ case Func < T , Task > func : {
113+ await func . Invoke ( item ) ;
114+ break ;
115+ }
116+
117+ case Func < T , CancellationToken , Task > func : {
118+ await func . Invoke ( item , ct ) ;
119+ break ;
120+ }
121+
122+ default : throw new InvalidOperationException ( "Invalid function type" ) ;
123+ }
124+ }
125+ }
0 commit comments