1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. 2 3 namespace System.Web.Razor 4 { 5 public abstract class StateMachine<TReturn> 6 { State()7 protected delegate StateResult State(); 8 9 protected abstract State StartState { get; } 10 11 protected State CurrentState { get; set; } 12 Turn()13 protected virtual TReturn Turn() 14 { 15 if (CurrentState != null) 16 { 17 StateResult result; 18 do 19 { 20 // Keep running until we get a null result or output 21 result = CurrentState(); 22 CurrentState = result.Next; 23 } 24 while (result != null && !result.HasOutput); 25 26 if (result == null) 27 { 28 return default(TReturn); // Terminated 29 } 30 return result.Output; 31 } 32 return default(TReturn); 33 } 34 35 /// <summary> 36 /// Returns a result indicating that the machine should stop executing and return null output. 37 /// </summary> Stop()38 protected StateResult Stop() 39 { 40 return null; 41 } 42 43 /// <summary> 44 /// Returns a result indicating that this state has no output and the machine should immediately invoke the specified state 45 /// </summary> 46 /// <remarks> 47 /// By returning no output, the state machine will invoke the next state immediately, before returning 48 /// controller to the caller of <see cref="Turn"/> 49 /// </remarks> Transition(State newState)50 protected StateResult Transition(State newState) 51 { 52 return new StateResult(newState); 53 } 54 55 /// <summary> 56 /// Returns a result containing the specified output and indicating that the next call to 57 /// <see cref="Turn"/> should invoke the provided state. 58 /// </summary> Transition(TReturn output, State newState)59 protected StateResult Transition(TReturn output, State newState) 60 { 61 return new StateResult(output, newState); 62 } 63 64 /// <summary> 65 /// Returns a result indicating that this state has no output and the machine should remain in this state 66 /// </summary> 67 /// <remarks> 68 /// By returning no output, the state machine will re-invoke the current state again before returning 69 /// controller to the caller of <see cref="Turn"/> 70 /// </remarks> Stay()71 protected StateResult Stay() 72 { 73 return new StateResult(CurrentState); 74 } 75 76 /// <summary> 77 /// Returns a result containing the specified output and indicating that the next call to 78 /// <see cref="Turn"/> should re-invoke the current state. 79 /// </summary> Stay(TReturn output)80 protected StateResult Stay(TReturn output) 81 { 82 return new StateResult(output, CurrentState); 83 } 84 85 protected class StateResult 86 { StateResult(State next)87 public StateResult(State next) 88 { 89 HasOutput = false; 90 Next = next; 91 } 92 StateResult(TReturn output, State next)93 public StateResult(TReturn output, State next) 94 { 95 HasOutput = true; 96 Output = output; 97 Next = next; 98 } 99 100 public bool HasOutput { get; set; } 101 public TReturn Output { get; set; } 102 public State Next { get; set; } 103 } 104 } 105 } 106