Fiber.cs
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license.
4 //
5 // Microsoft Bot Framework: http://botframework.com
6 //
7 // Bot Builder SDK GitHub:
8 // https://github.com/Microsoft/BotBuilder
9 //
10 // Copyright (c) Microsoft Corporation
11 // All rights reserved.
12 //
13 // MIT License:
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33 
34 using System;
35 using System.Collections.Generic;
36 using System.Threading;
37 using System.Threading.Tasks;
38 
39 namespace Microsoft.Bot.Builder.Internals.Fibers
40 {
47  public interface IWaiter<C>
48  {
52  IWait<C> Mark { get; set; }
53 
57  IWait<C> Wait { get; set; }
58  }
59 
60  public interface IFiber<C> : IWaiter<C>
61  {
62  IWaitFactory<C> Waits { get; }
63  IReadOnlyList<IFrame<C>> Frames { get; }
64  void Push();
65  void Done();
66  }
67 
68  public interface IFiberLoop<C> : IFiber<C>
69  {
70  Task<IWait<C>> PollAsync(C context, CancellationToken token);
71  }
72 
73  public interface IFrameLoop<C>
74  {
75  Task<IWait<C>> PollAsync(IFiber<C> fiber, C context, CancellationToken token);
76  }
77 
78 
79  public interface IFrame<C> : IWaiter<C>, IFrameLoop<C>
80  {
81  }
82 
83  [Serializable]
84  public sealed class Frame<C> : IFrame<C>
85  {
86  private IWait<C> mark = NullWait<C>.Instance;
87  private IWait<C> wait = NullWait<C>.Instance;
88 
89  public override string ToString()
90  {
91  return this.wait.ToString();
92  }
93 
95  {
96  get { return this.mark; }
97  set { this.mark = value; }
98  }
99 
101  {
102  get { return this.wait; }
103  set
104  {
105  if (this.wait is NullWait<C>)
106  {
107  this.wait = null;
108  }
109 
110  if (this.wait != null)
111  {
112  this.wait.ValidateNeed(Need.Call);
113  this.wait = null;
114  }
115 
116  this.wait = value;
117  }
118  }
119 
120  async Task<IWait<C>> IFrameLoop<C>.PollAsync(IFiber<C> fiber, C context, CancellationToken token)
121  {
122  return await this.wait.PollAsync(fiber, context, token);
123  }
124  }
125 
126  public interface IFrameFactory<C>
127  {
128  IFrame<C> Make();
129  }
130 
131  [Serializable]
132  public sealed class FrameFactory<C> : IFrameFactory<C>
133  {
135  {
136  return new Frame<C>();
137  }
138  }
139 
140  [Serializable]
141  public sealed class Fiber<C> : IFiber<C>, IFiberLoop<C>
142  {
143  private readonly List<IFrame<C>> stack = new List<IFrame<C>>();
144  private readonly IFrameFactory<C> frames;
145  private readonly IWaitFactory<C> waits;
146 
147  public Fiber(IFrameFactory<C> factory, IWaitFactory<C> waits)
148  {
149  SetField.NotNull(out this.frames, nameof(factory), factory);
150  SetField.NotNull(out this.waits, nameof(waits), waits);
151  }
152 
153  IWaitFactory<C> IFiber<C>.Waits => this.waits;
154 
155  IReadOnlyList<IFrame<C>> IFiber<C>.Frames => this.stack;
156 
157  void IFiber<C>.Push()
158  {
159  this.stack.Push(this.frames.Make());
160  }
161 
162  void IFiber<C>.Done()
163  {
164  this.stack.Pop();
165  }
166 
168  {
169  get
170  {
171  if (this.stack.Count > 0)
172  {
173  var leaf = this.stack.Peek();
174  return leaf.Mark;
175  }
176  else
177  {
178  return NullWait<C>.Instance;
179  }
180  }
181  set
182  {
183  this.stack.Peek().Mark = value;
184  }
185  }
186 
188  {
189  get
190  {
191  if (this.stack.Count > 0)
192  {
193  var leaf = this.stack.Peek();
194  return leaf.Wait;
195  }
196  else
197  {
198  return NullWait<C>.Instance;
199  }
200  }
201  set
202  {
203  this.stack.Peek().Wait = value;
204  }
205  }
206 
207  async Task<IWait<C>> IFiberLoop<C>.PollAsync(C context, CancellationToken token)
208  {
209  while (this.stack.Count > 0)
210  {
211  var leaf = this.stack.Peek();
212  var wait = leaf.Wait;
213  switch (wait.Need)
214  {
215  case Need.None:
216  case Need.Wait:
217  case Need.Done:
218  return wait;
219  case Need.Poll:
220  break;
221  default:
222  throw new InvalidNeedException(wait, Need.Poll);
223  }
224 
225  try
226  {
227  var next = await leaf.PollAsync(this, context, token);
228  var peek = this.stack.Peek();
229  bool fine = object.ReferenceEquals(next, peek.Wait) || next is NullWait<C>;
230  if (!fine)
231  {
232  throw new InvalidNextException(next);
233  }
234  }
235  catch (Exception error)
236  {
237  this.stack.Pop();
238  if (this.stack.Count == 0)
239  {
240  throw;
241  }
242  else
243  {
244  var parent = this.stack.Peek();
245  parent.Wait.Fail(error);
246  }
247  }
248  }
249 
250  return NullWait<C>.Instance;
251  }
252  }
253 }
Fiber(IFrameFactory< C > factory, IWaitFactory< C > waits)
Definition: Fiber.cs:147
IReadOnlyList< IFrame< C > > Frames
Definition: Fiber.cs:63
Waiters wait for an item to be posted.
Definition: Fiber.cs:47
Need
This is the stage of the wait, showing what the wait needs during its lifecycle.
Definition: Wait.cs:58
static readonly IWait< C > Instance
Definition: Wait.cs:129
Task< IWait< C > > PollAsync(IFiber< C > fiber, C context, CancellationToken token)
IWait< C > Wait
The active wait for this waiter.
Definition: Fiber.cs:57
The wait has completed executing the rest delegate.
Null object pattern implementation of wait interface.
Definition: Wait.cs:127
Task< IWait< C > > PollAsync(C context, CancellationToken token)
IWait< C > Mark
A "mailbox" for storing a wait associated with this frame.
Definition: Fiber.cs:52