Auto status change to "Under Review"
@@ -0,0 +1,14 | |||||
|
1 | namespace Implab.Messaging { | |||
|
2 | public interface ISession { | |||
|
3 | /// <summary> | |||
|
4 | /// Starts message consumers, call this method after all adapters are ready | |||
|
5 | /// </summary> | |||
|
6 | void Start(); | |||
|
7 | ||||
|
8 | /// <summary> | |||
|
9 | /// Stops message consumers | |||
|
10 | /// </summary> | |||
|
11 | void Stop(); | |||
|
12 | ||||
|
13 | } | |||
|
14 | } No newline at end of file |
@@ -0,0 +1,70 | |||||
|
1 | using System; | |||
|
2 | using System.Threading.Tasks; | |||
|
3 | ||||
|
4 | namespace Implab { | |||
|
5 | public static class TaskHelpers { | |||
|
6 | ||||
|
7 | public static async Task Then(this Task that, Action fulfilled, Action<Exception> rejected) { | |||
|
8 | Safe.ArgumentNotNull(that, nameof(that)); | |||
|
9 | if (rejected != null) { | |||
|
10 | try { | |||
|
11 | await that; | |||
|
12 | } catch (Exception e) { | |||
|
13 | rejected(e); | |||
|
14 | return; | |||
|
15 | } | |||
|
16 | } else { | |||
|
17 | await that; | |||
|
18 | } | |||
|
19 | ||||
|
20 | if (fulfilled != null) | |||
|
21 | fulfilled(); | |||
|
22 | } | |||
|
23 | ||||
|
24 | public static async Task Then(this Task that, Action fulfilled) { | |||
|
25 | Safe.ArgumentNotNull(that, nameof(that)); | |||
|
26 | await that; | |||
|
27 | if (fulfilled != null) | |||
|
28 | fulfilled(); | |||
|
29 | } | |||
|
30 | ||||
|
31 | public static async Task Then(this Task that, Func<Task> fulfilled) { | |||
|
32 | Safe.ArgumentNotNull(that, nameof(that)); | |||
|
33 | await that; | |||
|
34 | if (fulfilled != null) | |||
|
35 | await fulfilled(); | |||
|
36 | } | |||
|
37 | ||||
|
38 | public static async Task Finally(this Task that, Action handler) { | |||
|
39 | Safe.ArgumentNotNull(that, nameof(that)); | |||
|
40 | try { | |||
|
41 | await that; | |||
|
42 | } finally { | |||
|
43 | if (handler != null) | |||
|
44 | handler(); | |||
|
45 | } | |||
|
46 | } | |||
|
47 | ||||
|
48 | public static async void Then(this Task that, IResolvable next) { | |||
|
49 | try { | |||
|
50 | await that; | |||
|
51 | } catch (Exception e) { | |||
|
52 | next.Reject(e); | |||
|
53 | return; | |||
|
54 | } | |||
|
55 | next.Resolve(); | |||
|
56 | } | |||
|
57 | ||||
|
58 | public static async void Then<T>(this Task<T> that, IResolvable<T> next) { | |||
|
59 | T result; | |||
|
60 | try { | |||
|
61 | result = await that; | |||
|
62 | } catch (Exception e) { | |||
|
63 | next.Reject(e); | |||
|
64 | return; | |||
|
65 | } | |||
|
66 | next.Resolve(result); | |||
|
67 | } | |||
|
68 | ||||
|
69 | } | |||
|
70 | } No newline at end of file |
@@ -1,4 +1,5 | |||||
1 | using System; |
|
1 | using System; | |
|
2 | using System.Diagnostics; | |||
2 | using System.Threading; |
|
3 | using System.Threading; | |
3 | using Xunit; |
|
4 | using Xunit; | |
4 |
|
5 | |||
@@ -9,9 +10,20 namespace Implab.Test | |||||
9 | [Fact] |
|
10 | [Fact] | |
10 | public void Test1() |
|
11 | public void Test1() | |
11 | { |
|
12 | { | |
12 | using(var cts = new CancellationTokenSource(1000)) { |
|
13 | var listener = new TextWriterTraceListener(Console.Out); | |
13 | PromiseHelper.Sleep(10000, cts.Token).Join(); |
|
14 | var source = new TraceSource("Custom",SourceLevels.ActivityTracing); | |
14 | } |
|
15 | ||
|
16 | source.Listeners.Add(listener); | |||
|
17 | ||||
|
18 | Trace.Listeners.Add(listener); | |||
|
19 | Trace.WriteLine("Hello!"); | |||
|
20 | Trace.CorrelationManager.StartLogicalOperation(); | |||
|
21 | Trace.WriteLine("Inner"); | |||
|
22 | foreach(var x in Trace.CorrelationManager.LogicalOperationStack) | |||
|
23 | Trace.WriteLine($"-{x}"); | |||
|
24 | source.TraceEvent(TraceEventType.Information, 1, "source event"); | |||
|
25 | source.TraceData(TraceEventType.Start, 1, DateTime.Now); | |||
|
26 | Trace.CorrelationManager.StopLogicalOperation(); | |||
15 | } |
|
27 | } | |
16 | } |
|
28 | } | |
17 | } |
|
29 | } |
@@ -20,7 +20,7 namespace Implab.Automaton { | |||||
20 | #region IDFADefinition implementation |
|
20 | #region IDFADefinition implementation | |
21 |
|
21 | |||
22 | public bool IsFinalState(int s) { |
|
22 | public bool IsFinalState(int s) { | |
23 |
Safe.ArgumentInRange(s |
|
23 | Safe.ArgumentInRange(s >= 0 && s < m_stateCount, nameof(s)); | |
24 |
|
24 | |||
25 | return m_finalStates.Contains(s); |
|
25 | return m_finalStates.Contains(s); | |
26 | } |
|
26 | } | |
@@ -46,7 +46,7 namespace Implab.Automaton { | |||||
46 | #endregion |
|
46 | #endregion | |
47 |
|
47 | |||
48 | public void SetInitialState(int s) { |
|
48 | public void SetInitialState(int s) { | |
49 |
Safe.Argument |
|
49 | Safe.ArgumentInRange(s >= 0, nameof(s)); | |
50 | m_stateCount = Math.Max(m_stateCount, s + 1); |
|
50 | m_stateCount = Math.Max(m_stateCount, s + 1); | |
51 | m_initialState = s; |
|
51 | m_initialState = s; | |
52 | } |
|
52 | } | |
@@ -57,9 +57,9 namespace Implab.Automaton { | |||||
57 | } |
|
57 | } | |
58 |
|
58 | |||
59 | public void Add(AutomatonTransition item) { |
|
59 | public void Add(AutomatonTransition item) { | |
60 |
Safe.ArgumentAssert(item.s1 >= 0, |
|
60 | Safe.ArgumentAssert(item.s1 >= 0, nameof(item)); | |
61 |
Safe.ArgumentAssert(item.s2 >= 0, |
|
61 | Safe.ArgumentAssert(item.s2 >= 0, nameof(item)); | |
62 |
Safe.ArgumentAssert(item.edge >= 0, |
|
62 | Safe.ArgumentAssert(item.edge >= 0, nameof(item)); | |
63 |
|
63 | |||
64 | m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1); |
|
64 | m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1); | |
65 | m_symbolCount = Math.Max(m_symbolCount, item.edge + 1); |
|
65 | m_symbolCount = Math.Max(m_symbolCount, item.edge + 1); |
@@ -15,6 +15,8 | |||||
15 |
|
15 | |||
16 | Stopping, |
|
16 | Stopping, | |
17 |
|
17 | |||
|
18 | Stopped, | |||
|
19 | ||||
18 | Failed, |
|
20 | Failed, | |
19 |
|
21 | |||
20 | Disposed, |
|
22 | Disposed, |
@@ -11,9 +11,16 namespace Implab.Components { | |||||
11 | /// Completes initialization. |
|
11 | /// Completes initialization. | |
12 | /// </summary> |
|
12 | /// </summary> | |
13 | /// <remarks> |
|
13 | /// <remarks> | |
|
14 | /// <para> | |||
14 | /// Normally virtual methods shouldn't be called from the constructor, due to the incomplete object state, but |
|
15 | /// Normally virtual methods shouldn't be called from the constructor, due to the incomplete object state, but | |
15 | /// they can be called from this method. This method is also usefull when we constructing a complex grpah |
|
16 | /// they can be called from this method. This method is also usefull when we constructing a complex grpah | |
16 | /// of components where cyclic references may take place. |
|
17 | /// of components where cyclic references may take place. | |
|
18 | /// </para> | |||
|
19 | /// <para> | |||
|
20 | /// In asyncronous patterns <see cref="Initialize()"/> can be called | |||
|
21 | /// to start initialization and the <see cref="IRunnable.Completion"/> | |||
|
22 | /// property can be used to track operation completion. | |||
|
23 | /// </para> | |||
17 | /// </remarks> |
|
24 | /// </remarks> | |
18 | void Initialize(); |
|
25 | void Initialize(); | |
19 | } |
|
26 | } |
@@ -6,23 +6,53 namespace Implab.Components { | |||||
6 | /// <summary> |
|
6 | /// <summary> | |
7 | /// Interface for the component which performs a long running task. |
|
7 | /// Interface for the component which performs a long running task. | |
8 | /// </summary> |
|
8 | /// </summary> | |
9 | public interface IRunnable : IDisposable { |
|
9 | /// <remarks> | |
|
10 | /// The access to the runnable component should be sequential, the | |||
|
11 | /// componet should support asynchronous completion of the initiated | |||
|
12 | /// operation but operations itself must be initiated sequentially. | |||
|
13 | /// </remarks> | |||
|
14 | public interface IRunnable { | |||
10 | /// <summary> |
|
15 | /// <summary> | |
11 | /// Starts this instance |
|
16 | /// Starts this instance | |
12 | /// </summary> |
|
17 | /// </summary> | |
|
18 | /// <remarks> | |||
|
19 | /// This operation is cancellable and it's expected to move to | |||
|
20 | /// the failed state or just ignore the cancellation request, | |||
|
21 | /// </remarks> | |||
13 | void Start(CancellationToken ct); |
|
22 | void Start(CancellationToken ct); | |
14 |
|
23 | |||
15 | /// <summary> |
|
24 | /// <summary> | |
16 |
/// Stops this instance and releases all resources, after the |
|
25 | /// Stops this instance and releases all resources, after the | |
|
26 | /// instance is stopped it is moved to Disposed state and | |||
|
27 | /// can't be reused. | |||
17 | /// </summary> |
|
28 | /// </summary> | |
|
29 | /// <remarks> | |||
|
30 | /// If the componet was in the starting state the pending operation | |||
|
31 | /// will be requested to cancel. The stop operatin will be | |||
|
32 | /// performed only if the component in the running state. | |||
|
33 | /// </remarks> | |||
18 | void Stop(CancellationToken ct); |
|
34 | void Stop(CancellationToken ct); | |
19 |
|
35 | |||
20 | Task<ExecutionState> Completion { get; } |
|
36 | /// <summary> | |
|
37 | /// The result of the last started operation. This property reflects | |||
|
38 | /// only the result of the last started operation and therefore should | |||
|
39 | /// change only if a new operation is initiated. | |||
|
40 | /// </summary> | |||
|
41 | Task Completion { get; } | |||
21 |
|
42 | |||
|
43 | /// <summary> | |||
|
44 | /// Current state of the componenet | |||
|
45 | /// </summary> | |||
22 | ExecutionState State { get; } |
|
46 | ExecutionState State { get; } | |
23 |
|
47 | |||
|
48 | /// <summary> | |||
|
49 | /// Event to monitor the state of the component. | |||
|
50 | /// </summary> | |||
24 | event EventHandler<StateChangeEventArgs> StateChanged; |
|
51 | event EventHandler<StateChangeEventArgs> StateChanged; | |
25 |
|
52 | |||
|
53 | /// <summary> | |||
|
54 | /// The last error | |||
|
55 | /// </summary> | |||
26 | Exception LastError { get; } |
|
56 | Exception LastError { get; } | |
27 | } |
|
57 | } | |
28 | } |
|
58 | } |
@@ -26,7 +26,7 namespace Implab.Components { | |||||
26 | } |
|
26 | } | |
27 |
|
27 | |||
28 | protected ObjectPool(int size) { |
|
28 | protected ObjectPool(int size) { | |
29 |
Safe.ArgumentInRange(size, |
|
29 | Safe.ArgumentInRange(size > 0, nameof(size)); | |
30 |
|
30 | |||
31 | m_size = size; |
|
31 | m_size = size; | |
32 | } |
|
32 | } |
@@ -1,57 +1,273 | |||||
1 | using System; |
|
1 | using System; | |
|
2 | using System.Diagnostics; | |||
2 | using System.Threading; |
|
3 | using System.Threading; | |
3 | using System.Threading.Tasks; |
|
4 | using System.Threading.Tasks; | |
4 |
|
5 | |||
5 | namespace Implab.Components |
|
6 | namespace Implab.Components { | |
6 | { |
|
7 | /// <summary> | |
7 | public class RunnableComponent : IRunnable { |
|
8 | /// Base class for implementing components which support start and stop operations, | |
|
9 | /// such components may represent running services. | |||
|
10 | /// </summary> | |||
|
11 | /// <remarks> | |||
|
12 | /// This class provides a basic lifecycle from the creation to the | |||
|
13 | /// termination of the component. | |||
|
14 | /// </remarks> | |||
|
15 | public class RunnableComponent : IRunnable, IInitializable, IDisposable { | |||
|
16 | ||||
|
17 | /// <summary> | |||
|
18 | /// This class bound <see cref="CancellationTokenSource"/> lifetime to the task, | |||
|
19 | /// when the task completes the associated token source will be disposed. | |||
|
20 | /// </summary> | |||
|
21 | class AsyncOperationDescriptor { | |||
|
22 | ||||
|
23 | public static AsyncOperationDescriptor None { get; } = new AsyncOperationDescriptor(); | |||
|
24 | ||||
|
25 | readonly CancellationTokenSource m_cts; | |||
|
26 | ||||
|
27 | bool m_done; | |||
|
28 | ||||
|
29 | public CancellationToken Token { | |||
|
30 | get { return m_cts == null ? CancellationToken.None : m_cts.Token; } | |||
|
31 | } | |||
|
32 | ||||
|
33 | public Task Task { get; private set; } | |||
|
34 | ||||
|
35 | private AsyncOperationDescriptor(Task task, CancellationTokenSource cts) { | |||
|
36 | m_cts = cts; | |||
|
37 | Task = Chain(task); | |||
|
38 | } | |||
|
39 | ||||
|
40 | private AsyncOperationDescriptor() { | |||
|
41 | Task = Task.CompletedTask; | |||
|
42 | } | |||
8 |
|
43 | |||
|
44 | public void Cancel() { | |||
|
45 | if (m_cts != null) { | |||
|
46 | lock (m_cts) { | |||
|
47 | if (!m_done) | |||
|
48 | m_cts.Cancel(); | |||
|
49 | } | |||
|
50 | } | |||
|
51 | } | |||
|
52 | ||||
|
53 | void Done() { | |||
|
54 | if (m_cts != null) { | |||
|
55 | lock (m_cts) { | |||
|
56 | m_done = true; | |||
|
57 | m_cts.Dispose(); | |||
|
58 | } | |||
|
59 | } else { | |||
|
60 | m_done = true; | |||
|
61 | } | |||
|
62 | } | |||
|
63 | ||||
|
64 | async Task Chain(Task other) { | |||
|
65 | try { | |||
|
66 | await other; | |||
|
67 | } finally { | |||
|
68 | Done(); | |||
|
69 | } | |||
|
70 | } | |||
|
71 | ||||
|
72 | public static AsyncOperationDescriptor Create(Func<CancellationToken, Task> factory, CancellationToken ct) { | |||
|
73 | var cts = ct.CanBeCanceled ? | |||
|
74 | CancellationTokenSource.CreateLinkedTokenSource(ct) : | |||
|
75 | new CancellationTokenSource(); | |||
|
76 | ||||
|
77 | return new AsyncOperationDescriptor(factory(cts.Token), cts); | |||
|
78 | } | |||
|
79 | ||||
|
80 | } | |||
|
81 | ||||
|
82 | // this lock is used to synchronize state flow of the component during | |||
|
83 | // completions or the operations. | |||
9 | readonly object m_lock = new object(); |
|
84 | readonly object m_lock = new object(); | |
10 |
|
85 | |||
11 | CancellationTokenSource m_cts; |
|
86 | // current operation cookie, used to check wheather a call to | |
|
87 | // MoveSuccess/MoveFailed method belongs to the current | |||
|
88 | // operation, if cookies didn't match ignore completion result. | |||
|
89 | object m_cookie; | |||
12 |
|
90 | |||
13 | public Task<ExecutionState> Completion { |
|
91 | AsyncOperationDescriptor m_current = AsyncOperationDescriptor.None; | |
14 | get; |
|
92 | ||
15 | private set; |
|
93 | ExecutionState m_state; | |
|
94 | ||||
|
95 | ||||
|
96 | protected RunnableComponent(bool initialized) { | |||
|
97 | State = initialized ? ExecutionState.Ready : ExecutionState.Created; | |||
16 | } |
|
98 | } | |
17 |
|
99 | |||
18 | public ExecutionState State => throw new NotImplementedException(); |
|
100 | public Task Completion { | |
|
101 | get { return m_current.Task; } | |||
|
102 | } | |||
19 |
|
103 | |||
20 | public Exception LastError => throw new NotImplementedException(); |
|
104 | public ExecutionState State { | |
|
105 | get { return m_state; } | |||
|
106 | private set { | |||
|
107 | if (m_state != value) { | |||
|
108 | m_state = value; | |||
|
109 | StateChanged.DispatchEvent(this, new StateChangeEventArgs { | |||
|
110 | State = value, | |||
|
111 | LastError = LastError | |||
|
112 | }); | |||
|
113 | } | |||
|
114 | } | |||
|
115 | } | |||
|
116 | ||||
|
117 | public Exception LastError { get; private set; } | |||
21 |
|
118 | |||
22 | public event EventHandler<StateChangeEventArgs> StateChanged; |
|
119 | public event EventHandler<StateChangeEventArgs> StateChanged; | |
23 |
|
120 | |||
|
121 | /// <summary> | |||
|
122 | /// Releases all resources used by the current component regardless of its | |||
|
123 | /// execution state. | |||
|
124 | /// </summary> | |||
|
125 | /// <remarks> | |||
|
126 | /// Calling to this method may result unexpedted results if the component | |||
|
127 | /// isn't in the stopped state. Call this method after the component is | |||
|
128 | /// stopped if needed or if the component is in the failed state. | |||
|
129 | /// </remarks> | |||
24 | public void Dispose() { |
|
130 | public void Dispose() { | |
25 | lock(m_lock) { |
|
131 | bool dispose = false; | |
|
132 | if (dispose) { | |||
26 | Dispose(true); |
|
133 | Dispose(true); | |
27 | GC.SuppressFinalize(this); |
|
134 | GC.SuppressFinalize(this); | |
28 | } |
|
135 | } | |
29 | } |
|
136 | } | |
30 |
|
137 | |||
|
138 | ~RunnableComponent() { | |||
|
139 | Dispose(false); | |||
|
140 | } | |||
|
141 | ||||
|
142 | /// <summary> | |||
|
143 | /// Releases all resources used by the current component regardless of its | |||
|
144 | /// execution state. | |||
|
145 | /// </summary> | |||
|
146 | /// <param name="disposing">Indicates that the component is disposed | |||
|
147 | /// during a normal disposing or during GC.</param> | |||
31 | protected virtual void Dispose(bool disposing) { |
|
148 | protected virtual void Dispose(bool disposing) { | |
32 | if (disposing) { |
|
149 | } | |
33 | Safe.Dispose(m_cts); |
|
150 | ||
34 | } |
|
151 | public void Initialize() { | |
|
152 | var cookie = new object(); | |||
|
153 | if (MoveInitialize(cookie)) | |||
|
154 | ScheduleTask(InitializeInternalAsync, CancellationToken.None, cookie); | |||
|
155 | } | |||
|
156 | ||||
|
157 | /// <summary> | |||
|
158 | /// This method is used for initialization during a component creation. | |||
|
159 | /// </summary> | |||
|
160 | /// <param name="ct">A cancellation token for this operation</param> | |||
|
161 | /// <remarks> | |||
|
162 | /// This method should be used for short and mostly syncronous operations, | |||
|
163 | /// other operations which require time to run shoud be placed in | |||
|
164 | /// <see cref="StartInternal(CancellationToken)"/> method. | |||
|
165 | /// </remarks> | |||
|
166 | protected virtual Task InitializeInternalAsync(CancellationToken ct) { | |||
|
167 | return Task.CompletedTask; | |||
35 | } |
|
168 | } | |
36 |
|
169 | |||
37 | public void Start(CancellationToken ct) { |
|
170 | public void Start(CancellationToken ct) { | |
38 | lock(m_lock) { |
|
171 | var cookie = new object(); | |
39 |
|
|
172 | if (MoveStart(cookie)) | |
40 | { |
|
173 | ScheduleTask(StartInternal, ct, cookie); | |
41 |
|
174 | } | ||
42 | default: |
|
175 | ||
43 | throw new InvalidOperationException(); |
|
176 | protected virtual Task StartInternal(CancellationToken ct) { | |
|
177 | return Task.CompletedTask; | |||
|
178 | } | |||
|
179 | ||||
|
180 | public void Stop(CancellationToken ct) { | |||
|
181 | var cookie = new object(); | |||
|
182 | if (MoveStop(cookie)) | |||
|
183 | ScheduleTask(StopAsync, ct, cookie); | |||
|
184 | } | |||
|
185 | ||||
|
186 | async Task StopAsync(CancellationToken ct) { | |||
|
187 | m_current.Cancel(); | |||
|
188 | await Completion; | |||
|
189 | ||||
|
190 | ct.ThrowIfCancellationRequested(); | |||
|
191 | ||||
|
192 | await StopInternalAsync(ct); | |||
|
193 | } | |||
|
194 | ||||
|
195 | protected virtual Task StopInternalAsync(CancellationToken ct) { | |||
|
196 | return Task.CompletedTask; | |||
|
197 | } | |||
|
198 | ||||
|
199 | ||||
|
200 | #region state management | |||
|
201 | ||||
|
202 | bool MoveInitialize(object cookie) { | |||
|
203 | lock (m_lock) { | |||
|
204 | if (State != ExecutionState.Created) | |||
|
205 | return false; | |||
|
206 | State = ExecutionState.Initializing; | |||
|
207 | m_cookie = cookie; | |||
|
208 | return true; | |||
|
209 | } | |||
|
210 | } | |||
|
211 | ||||
|
212 | bool MoveStart(object cookie) { | |||
|
213 | lock (m_lock) { | |||
|
214 | if (State != ExecutionState.Ready) | |||
|
215 | return false; | |||
|
216 | State = ExecutionState.Starting; | |||
|
217 | m_cookie = cookie; | |||
|
218 | return true; | |||
|
219 | } | |||
|
220 | } | |||
|
221 | ||||
|
222 | bool MoveStop(object cookie) { | |||
|
223 | lock (m_lock) { | |||
|
224 | if (State != ExecutionState.Starting && State != ExecutionState.Running) | |||
|
225 | return false; | |||
|
226 | State = ExecutionState.Stopping; | |||
|
227 | m_cookie = cookie; | |||
|
228 | return true; | |||
|
229 | } | |||
|
230 | } | |||
|
231 | ||||
|
232 | void MoveSuccess(object cookie) { | |||
|
233 | lock (m_lock) { | |||
|
234 | if (m_cookie != cookie) | |||
|
235 | return; | |||
|
236 | switch (State) { | |||
|
237 | case ExecutionState.Initializing: | |||
|
238 | State = ExecutionState.Ready; | |||
|
239 | break; | |||
|
240 | case ExecutionState.Starting: | |||
|
241 | State = ExecutionState.Running; | |||
|
242 | break; | |||
|
243 | case ExecutionState.Stopping: | |||
|
244 | State = ExecutionState.Stopped; | |||
|
245 | break; | |||
44 | } |
|
246 | } | |
45 | } |
|
247 | } | |
46 | } |
|
248 | } | |
47 |
|
249 | |||
48 | public void Stop(CancellationToken ct) { |
|
250 | void MoveFailed(Exception err, object cookie) { | |
49 | throw new NotImplementedException(); |
|
251 | lock (m_lock) { | |
|
252 | if (m_cookie != cookie) | |||
|
253 | return; | |||
|
254 | LastError = err; | |||
|
255 | State = ExecutionState.Failed; | |||
|
256 | } | |||
50 | } |
|
257 | } | |
51 |
|
258 | |||
52 | protected virtual Task StartImpl(CancellationToken ct) { |
|
259 | ||
53 |
|
260 | |||
54 | return Task.CompletedTask; |
|
261 | protected async void ScheduleTask(Func<CancellationToken, Task> next, CancellationToken ct, object cookie) { | |
|
262 | try { | |||
|
263 | m_current = AsyncOperationDescriptor.Create(next, ct); | |||
|
264 | await m_current.Task; | |||
|
265 | MoveSuccess(cookie); | |||
|
266 | } catch (Exception e) { | |||
|
267 | MoveFailed(e, cookie); | |||
|
268 | } | |||
55 | } |
|
269 | } | |
|
270 | ||||
|
271 | #endregion | |||
56 | } |
|
272 | } | |
57 | } No newline at end of file |
|
273 | } |
@@ -1,5 +1,6 | |||||
1 | using System; |
|
1 | using System; | |
2 | using System.Diagnostics; |
|
2 | using System.Diagnostics; | |
|
3 | using System.Threading.Tasks; | |||
3 |
|
4 | |||
4 | namespace Implab { |
|
5 | namespace Implab { | |
5 | /// <summary> |
|
6 | /// <summary> | |
@@ -49,5 +50,15 namespace Implab { | |||||
49 | } |
|
50 | } | |
50 | } |
|
51 | } | |
51 |
|
52 | |||
|
53 | public virtual void Resolve(Task thenable) { | |||
|
54 | if (thenable == null) | |||
|
55 | Reject(new Exception("The promise or task are expected")); | |||
|
56 | try { | |||
|
57 | thenable.Then(this); | |||
|
58 | } catch(Exception err) { | |||
|
59 | Reject(err); | |||
|
60 | } | |||
|
61 | } | |||
|
62 | ||||
52 | } |
|
63 | } | |
53 | } No newline at end of file |
|
64 | } |
@@ -1,5 +1,6 | |||||
1 | using System; |
|
1 | using System; | |
2 | using System.Diagnostics; |
|
2 | using System.Diagnostics; | |
|
3 | using System.Threading.Tasks; | |||
3 |
|
4 | |||
4 | namespace Implab { |
|
5 | namespace Implab { | |
5 | public class Deferred<T> : IResolvable<T> { |
|
6 | public class Deferred<T> : IResolvable<T> { | |
@@ -45,5 +46,16 namespace Implab { | |||||
45 | Reject(err); |
|
46 | Reject(err); | |
46 | } |
|
47 | } | |
47 | } |
|
48 | } | |
|
49 | ||||
|
50 | public virtual void Resolve(Task<T> thenable) { | |||
|
51 | if (thenable == null) | |||
|
52 | Reject(new Exception("The promise or task are expected")); | |||
|
53 | ||||
|
54 | try { | |||
|
55 | thenable.Then(this); | |||
|
56 | } catch (Exception err) { | |||
|
57 | Reject(err); | |||
|
58 | } | |||
|
59 | } | |||
48 | } |
|
60 | } | |
49 | } No newline at end of file |
|
61 | } |
@@ -43,11 +43,8 namespace Implab.Formats.Json { | |||||
43 |
|
43 | |||
44 | public static JsonStringScanner Create(string data, int offset, int length) { |
|
44 | public static JsonStringScanner Create(string data, int offset, int length) { | |
45 | Safe.ArgumentNotNull(data, nameof(data)); |
|
45 | Safe.ArgumentNotNull(data, nameof(data)); | |
46 |
Safe.Argument |
|
46 | Safe.ArgumentInRange(offset >= 0 && offset < data.Length , nameof(offset)); | |
47 |
Safe.Argument |
|
47 | Safe.ArgumentInRange(length >= 0 && offset + length <= data.Length, nameof(length)); | |
48 |
|
||||
49 | if (offset + length > data.Length) |
|
|||
50 | throw new ArgumentOutOfRangeException("Specified offset and length are out of the string bounds"); |
|
|||
51 |
|
48 | |||
52 | if (length <= _defaultBuffer) { |
|
49 | if (length <= _defaultBuffer) { | |
53 | var buffer = new char[length]; |
|
50 | var buffer = new char[length]; | |
@@ -63,11 +60,8 namespace Implab.Formats.Json { | |||||
63 |
|
60 | |||
64 | public static JsonStringScanner Create(char[] data, int offset, int length) { |
|
61 | public static JsonStringScanner Create(char[] data, int offset, int length) { | |
65 | Safe.ArgumentNotNull(data, nameof(data)); |
|
62 | Safe.ArgumentNotNull(data, nameof(data)); | |
66 |
Safe.Argument |
|
63 | Safe.ArgumentInRange(offset >= 0 && offset < data.Length , nameof(offset)); | |
67 |
Safe.Argument |
|
64 | Safe.ArgumentInRange(length >= 0 && offset + length <= data.Length, nameof(length)); | |
68 |
|
||||
69 | if (offset + length > data.Length) |
|
|||
70 | throw new ArgumentOutOfRangeException("Specified offset and length are out of the array bounds"); |
|
|||
71 |
|
65 | |||
72 | return new JsonStringScanner(null, data, offset, offset + length, offset + length); |
|
66 | return new JsonStringScanner(null, data, offset, offset + length, offset + length); | |
73 |
|
67 |
@@ -3,7 +3,9 using System.Threading.Tasks; | |||||
3 |
|
3 | |||
4 | namespace Implab.Messaging { |
|
4 | namespace Implab.Messaging { | |
5 | public interface IConsumer<T> { |
|
5 | public interface IConsumer<T> { | |
6 |
|
|
6 | T Receive(CancellationToken ct); | |
|
7 | ||||
|
8 | Task<T> ReceiveAsync(CancellationToken ct); | |||
7 |
|
9 | |||
8 | bool TryReceive(out T message); |
|
10 | bool TryReceive(out T message); | |
9 | } |
|
11 | } |
@@ -4,8 +4,12 using System.Threading.Tasks; | |||||
4 |
|
4 | |||
5 | namespace Implab.Messaging { |
|
5 | namespace Implab.Messaging { | |
6 | public interface IProducer<T> { |
|
6 | public interface IProducer<T> { | |
|
7 | void PostMessage(T message, CancellationToken ct); | |||
|
8 | ||||
7 | Task PostMessageAsync(T message, CancellationToken ct); |
|
9 | Task PostMessageAsync(T message, CancellationToken ct); | |
8 |
|
10 | |||
|
11 | void PostMessages(IEnumerable<T> messages, CancellationToken ct); | |||
|
12 | ||||
9 | Task PostMessagesAsync(IEnumerable<T> messages, CancellationToken ct); |
|
13 | Task PostMessagesAsync(IEnumerable<T> messages, CancellationToken ct); | |
10 | } |
|
14 | } | |
11 | } No newline at end of file |
|
15 | } |
@@ -54,7 +54,7 namespace Implab.Parallels { | |||||
54 | } |
|
54 | } | |
55 |
|
55 | |||
56 | public T[] GetRange(int max, int timeout) { |
|
56 | public T[] GetRange(int max, int timeout) { | |
57 |
Safe.ArgumentInRange(max, |
|
57 | Safe.ArgumentInRange(max > 0 , nameof(max)); | |
58 |
|
58 | |||
59 | var buffer = new T[max]; |
|
59 | var buffer = new T[max]; | |
60 | int actual; |
|
60 | int actual; | |
@@ -83,7 +83,7 namespace Implab.Parallels { | |||||
83 | } |
|
83 | } | |
84 |
|
84 | |||
85 | public T[] GetRange(int max) { |
|
85 | public T[] GetRange(int max) { | |
86 |
Safe.ArgumentInRange(max, |
|
86 | Safe.ArgumentInRange(max > 0, nameof(max)); | |
87 |
|
87 | |||
88 | var buffer = new T[max]; |
|
88 | var buffer = new T[max]; | |
89 | int actual; |
|
89 | int actual; |
@@ -6,6 +6,7 using System.Text.RegularExpressions; | |||||
6 | using System.Diagnostics; |
|
6 | using System.Diagnostics; | |
7 | using System.Collections; |
|
7 | using System.Collections; | |
8 | using System.Runtime.CompilerServices; |
|
8 | using System.Runtime.CompilerServices; | |
|
9 | using System.Threading.Tasks; | |||
9 |
|
10 | |||
10 | #if NET_4_5 |
|
11 | #if NET_4_5 | |
11 | using System.Threading.Tasks; |
|
12 | using System.Threading.Tasks; | |
@@ -48,14 +49,14 namespace Implab | |||||
48 | } |
|
49 | } | |
49 |
|
50 | |||
50 | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
51 | [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
51 | internal static void ArgumentGreaterThan(int value, int min, string paramName) { |
|
52 | internal static void ArgumentGreaterEqThan(int value, int min, string paramName) { | |
52 | if (value < min) |
|
53 | if (value < min) | |
53 | throw new ArgumentOutOfRangeException(paramName); |
|
54 | throw new ArgumentOutOfRangeException(paramName); | |
54 | } |
|
55 | } | |
55 |
|
56 | |||
56 | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
57 | [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
57 |
public static void ArgumentInRange( |
|
58 | public static void ArgumentInRange(bool condition, string paramName) { | |
58 | if (value < min || value > max) |
|
59 | if (!condition) | |
59 | throw new ArgumentOutOfRangeException(paramName); |
|
60 | throw new ArgumentOutOfRangeException(paramName); | |
60 | } |
|
61 | } | |
61 |
|
62 | |||
@@ -144,6 +145,12 namespace Implab | |||||
144 | public static void NoWait(IPromise promise) { |
|
145 | public static void NoWait(IPromise promise) { | |
145 | } |
|
146 | } | |
146 |
|
147 | |||
|
148 | public static void NoWait(Task promise) { | |||
|
149 | } | |||
|
150 | ||||
|
151 | public static void NoWait<T>(Task<T> promise) { | |||
|
152 | } | |||
|
153 | ||||
147 | [DebuggerStepThrough] |
|
154 | [DebuggerStepThrough] | |
148 | public static IPromise<T> Run<T>(Func<IPromise<T>> action) { |
|
155 | public static IPromise<T> Run<T>(Func<IPromise<T>> action) { | |
149 | ArgumentNotNull(action, "action"); |
|
156 | ArgumentNotNull(action, "action"); |
@@ -163,7 +163,7 namespace Implab.Xml { | |||||
163 | } |
|
163 | } | |
164 |
|
164 | |||
165 | public override string GetAttribute(int i) { |
|
165 | public override string GetAttribute(int i) { | |
166 |
Safe.ArgumentInRange(i |
|
166 | Safe.ArgumentInRange(i >= 0 && i < AttributeCount, nameof(i)); | |
167 | return m_attributes[i].Value; |
|
167 | return m_attributes[i].Value; | |
168 | } |
|
168 | } | |
169 |
|
169 |
@@ -38,6 +38,20 namespace Implab.Xml { | |||||
38 | SerializersPool<T>.Instance.Serialize(writer, obj); |
|
38 | SerializersPool<T>.Instance.Serialize(writer, obj); | |
39 | } |
|
39 | } | |
40 |
|
40 | |||
|
41 | public static void SerializeToElementChild<T>(XmlElement element, T obj) { | |||
|
42 | using(var writer = element.CreateNavigator().AppendChild()) | |||
|
43 | SerializersPool<T>.Instance.Serialize(writer, obj); | |||
|
44 | } | |||
|
45 | ||||
|
46 | public static T Deserialize<T>(XmlReader reader) { | |||
|
47 | return SerializersPool<T>.Instance.Deserialize(reader); | |||
|
48 | } | |||
|
49 | ||||
|
50 | public static T DeserializeFromFile<T>(string file) { | |||
|
51 | using(var reader = XmlReader.Create(File.OpenText(file))) | |||
|
52 | return Deserialize<T>(reader); | |||
|
53 | } | |||
|
54 | ||||
41 | public static T DeserializeFromString<T>(string data) { |
|
55 | public static T DeserializeFromString<T>(string data) { | |
42 | return SerializersPool<T>.Instance.DeserializeFromString(data); |
|
56 | return SerializersPool<T>.Instance.DeserializeFromString(data); | |
43 | } |
|
57 | } |
General Comments 3
ok, latest stable version should be in default
You need to be logged in to leave comments.
Login now