aboutsummaryrefslogtreecommitdiff
path: root/ExcelTaskUtil.cs
blob: c7d1b94cacfe995d14d687e62e69be2e44f60fe1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using ExcelDna.Integration;
using System.Threading.Tasks;
using System;
using System.Threading;

namespace Rehau.Sku.Assist
{
    internal static class ExcelTaskUtil
    {
        public static object Run<TResult>(string callerFunctionName, object callerParameters, Func<CancellationToken, Task<TResult>> taskSource)
        {
            return ExcelAsyncUtil.Observe(callerFunctionName, callerParameters, delegate
            {
                var cts = new CancellationTokenSource();
                var task = taskSource(cts.Token);
                return new ExcelTaskObservable<TResult>(task, cts);
            });
        }

        public static object Run<TResult>(string callerFunctionName, object callerParameters, Func<Task<TResult>> taskSource)
        {
            return ExcelAsyncUtil.Observe(callerFunctionName, callerParameters, delegate
            {
                var task = taskSource();
                return new ExcelTaskObservable<TResult>(task);
            });
        }

        class ExcelTaskObservable<TResult> : IExcelObservable
        {
            readonly Task<TResult> _task;
            readonly CancellationTokenSource _cts;
            public ExcelTaskObservable(Task<TResult> task)
            {
                _task = task;
            }

            public ExcelTaskObservable(Task<TResult> task, CancellationTokenSource cts)
                : this(task)
            {
                _cts = cts;
            }

            public IDisposable Subscribe(IExcelObserver observer)
            {
                switch (_task.Status)
                {
                    case TaskStatus.RanToCompletion:
                        observer.OnNext(_task.Result);
                        observer.OnCompleted();
                        break;
                    case TaskStatus.Faulted:
                        observer.OnError(_task.Exception.InnerException);
                        break;
                    case TaskStatus.Canceled:
                        observer.OnError(new TaskCanceledException(_task));
                        break;
                    default:
                        _task.ContinueWith(t =>
                        {
                            switch (t.Status)
                            {
                                case TaskStatus.RanToCompletion:
                                    observer.OnNext(t.Result);
                                    observer.OnCompleted();
                                    break;
                                case TaskStatus.Faulted:
                                    observer.OnError(t.Exception.InnerException);
                                    break;
                                case TaskStatus.Canceled:
                                    observer.OnError(new TaskCanceledException(t));
                                    break;
                            }
                        });
                        break;
                }

                if (_cts != null)
                {
                    return new CancellationDisposable(_cts);
                }

                return DefaultDisposable.Instance;
            }
        }

        sealed class DefaultDisposable : IDisposable
        {

            public static readonly DefaultDisposable Instance = new DefaultDisposable();

            DefaultDisposable()
            {
            }

            public void Dispose()
            {
            }
        }

        sealed class CancellationDisposable : IDisposable
        {

            readonly CancellationTokenSource cts;
            public CancellationDisposable(CancellationTokenSource cts)
            {
                if (cts == null)
                {
                    throw new ArgumentNullException("cts");
                }

                this.cts = cts;
            }

            public CancellationDisposable()
                : this(new CancellationTokenSource())
            {
            }

            public CancellationToken Token
            {
                get { return cts.Token; }
            }

            public void Dispose()
            {
                cts.Cancel();
            }
        }

    }
}