summaryrefslogtreecommitdiff
path: root/external/aspnetwebstack/src/System.Web.Razor/StateMachine.cs
blob: 395596e7b194b44946ec59f43d10476e1c0e09bd (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
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.

namespace System.Web.Razor
{
    public abstract class StateMachine<TReturn>
    {
        protected delegate StateResult State();

        protected abstract State StartState { get; }

        protected State CurrentState { get; set; }

        protected virtual TReturn Turn()
        {
            if (CurrentState != null)
            {
                StateResult result;
                do
                {
                    // Keep running until we get a null result or output
                    result = CurrentState();
                    CurrentState = result.Next;
                }
                while (result != null && !result.HasOutput);

                if (result == null)
                {
                    return default(TReturn); // Terminated
                }
                return result.Output;
            }
            return default(TReturn);
        }

        /// <summary>
        /// Returns a result indicating that the machine should stop executing and return null output.
        /// </summary>
        protected StateResult Stop()
        {
            return null;
        }

        /// <summary>
        /// Returns a result indicating that this state has no output and the machine should immediately invoke the specified state
        /// </summary>
        /// <remarks>
        /// By returning no output, the state machine will invoke the next state immediately, before returning
        /// controller to the caller of <see cref="Turn"/>
        /// </remarks>
        protected StateResult Transition(State newState)
        {
            return new StateResult(newState);
        }

        /// <summary>
        /// Returns a result containing the specified output and indicating that the next call to
        /// <see cref="Turn"/> should invoke the provided state.
        /// </summary>
        protected StateResult Transition(TReturn output, State newState)
        {
            return new StateResult(output, newState);
        }

        /// <summary>
        /// Returns a result indicating that this state has no output and the machine should remain in this state
        /// </summary>
        /// <remarks>
        /// By returning no output, the state machine will re-invoke the current state again before returning
        /// controller to the caller of <see cref="Turn"/>
        /// </remarks>
        protected StateResult Stay()
        {
            return new StateResult(CurrentState);
        }

        /// <summary>
        /// Returns a result containing the specified output and indicating that the next call to
        /// <see cref="Turn"/> should re-invoke the current state.
        /// </summary>
        protected StateResult Stay(TReturn output)
        {
            return new StateResult(output, CurrentState);
        }

        protected class StateResult
        {
            public StateResult(State next)
            {
                HasOutput = false;
                Next = next;
            }

            public StateResult(TReturn output, State next)
            {
                HasOutput = true;
                Output = output;
                Next = next;
            }

            public bool HasOutput { get; set; }
            public TReturn Output { get; set; }
            public State Next { get; set; }
        }
    }
}