Skip to content

Commit 84dc7d8

Browse files
committed
documentation updated
1 parent 28b0d33 commit 84dc7d8

File tree

6 files changed

+1169
-11
lines changed

6 files changed

+1169
-11
lines changed

README.md

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,32 +31,44 @@ Create a simple Xstate model file `ping.ts` with few lines to trigger C++ genera
3131
const CppGen = require('xstate-cpp-generator');
3232
const path = require('path');
3333

34-
import { Machine, createMachine, assign } from 'xstate';
34+
import { Machine } from 'xstate';
3535

36-
const pingPongMachine = Machine({
37-
id: 'ping',
38-
initial: 'init',
36+
const engineerMachine = Machine({
37+
id: 'engineer',
38+
initial: 'sleeping',
3939
states: {
40-
init: {
40+
sleeping: {
41+
entry: 'startWakeupTimer',
42+
exit: 'morningRoutine',
4143
on: {
42-
'START': { target: 'pinging', actions: ['savePongActorAddress', 'spawnPongActor'] }
44+
'TIMER': { target: 'working', actions: ['startHungryTimer', 'startTiredTimer'] },
45+
'TIRED': { target: 'sleeping' }
4346
}
4447
},
45-
pinging: {
46-
onEntry: 'sendPingToPongActor',
48+
working: {
49+
entry: ['checkEmail', 'startHungryTimer' ],
4750
on: {
48-
'PONG': { target: 'pinging', actions: ['sendPingToPongActor']}
51+
'HUNGRY': { target: 'eating', actions: ['checkEmail']},
52+
'TIRED': { target: 'sleeping' }
53+
},
54+
},
55+
eating: {
56+
entry: 'startShortTimer',
57+
exit: [ 'checkEmail', 'startHungryTimer', 'startTiredTimer' ],
58+
on: {
59+
'TIMER': { target: 'working', actions: ['startHungryTimer'] },
60+
'TIRED': { target: 'sleeping' }
4961
}
5062
}
5163
}
5264
});
5365

5466

5567
CppGen.generateCpp({
56-
xstateMachine: pingPongMachine,
68+
xstateMachine: engineerMachine,
5769
destinationPath: "",
5870
namespace: "mongo",
59-
pathForIncludes: "example-ping-pong",
71+
pathForIncludes: "",
6072
tsScriptName: path.basename(__filename)
6173
});
6274
```

demo-project/engineer.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//const CppGen = require('xstate-cpp-generator');
2+
import { generateCpp } from '../src/cpp_state_machine_generator';
3+
const path = require('path');
4+
5+
import { Machine } from 'xstate';
6+
7+
const engineerMachine = Machine({
8+
id: 'engineer',
9+
initial: 'sleeping',
10+
states: {
11+
sleeping: {
12+
entry: 'startWakeupTimer',
13+
exit: 'morningRoutine',
14+
on: {
15+
'TIMER': { target: 'working', actions: ['startHungryTimer', 'startTiredTimer'] },
16+
'TIRED': { target: 'sleeping' }
17+
}
18+
},
19+
working: {
20+
entry: ['checkEmail', 'startHungryTimer' ],
21+
on: {
22+
'HUNGRY': { target: 'eating', actions: ['checkEmail']},
23+
'TIRED': { target: 'sleeping' }
24+
},
25+
},
26+
eating: {
27+
entry: 'startShortTimer',
28+
exit: [ 'checkEmail', 'startHungryTimer', 'startTiredTimer' ],
29+
on: {
30+
'TIMER': { target: 'working', actions: ['startHungryTimer'] },
31+
'TIRED': { target: 'sleeping' }
32+
}
33+
}
34+
}
35+
});
36+
37+
38+
//CppGen.
39+
generateCpp({
40+
xstateMachine: engineerMachine,
41+
destinationPath: "",
42+
namespace: "engineer_demo",
43+
pathForIncludes: "",
44+
tsScriptName: path.basename(__filename)
45+
});

demo-project/engineer_demo.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#include "engineer_sm.h"
2+
3+
#include <chrono>
4+
#include <thread>
5+
6+
namespace engineer_demo {
7+
8+
template<typename Function>
9+
void startTimer(Function function, int delayMs) {
10+
std::thread t([=]() {
11+
std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
12+
function();
13+
});
14+
t.detach();
15+
}
16+
17+
struct EngineerContext {
18+
// The demo will end after the Engineer wakes up 7 times.
19+
int wakeUpCount = 0;
20+
};
21+
22+
struct EngineerSpec {
23+
// Spec should always contain some 'using' for the StateMachineContext.
24+
using StateMachineContext = EngineerContext;
25+
26+
// Then it should have a list of 'using' declarations for every event payload.
27+
using EventTimerPayload = std::nullptr_t;
28+
using EventHungryPayload = std::nullptr_t;
29+
using EventTiredPayload = std::nullptr_t;
30+
31+
/**
32+
* This block is for transition actions.
33+
*/
34+
static void startHungryTimer (EngineerSM<EngineerSpec>* sm, EventTimerPayload* payload) {
35+
std::clog << "Start HungryTimer from timer event" << std::endl;
36+
startTimer([sm] {
37+
std::clog << "Ok, I'm hungry" << std::endl;
38+
sm->postEventHungry(std::nullptr_t());
39+
}, 100);
40+
}
41+
static void startTiredTimer (EngineerSM<EngineerSpec>* sm, EventTimerPayload* payload) {
42+
std::clog << "Start TiredTimer from timer event" << std::endl;
43+
startTimer([sm] {
44+
std::clog << "Ok, I'm tired" << std::endl;
45+
sm->postEventTired(std::nullptr_t());
46+
}, 1000);
47+
}
48+
static void checkEmail (EngineerSM<EngineerSpec>* sm, EventHungryPayload* payload) {
49+
std::clog << "Checking Email, while being hugry! ok..." << std::endl;
50+
}
51+
52+
/**
53+
* This block is for entry and exit state actions.
54+
*/
55+
static void startWakeupTimer (EngineerSM<EngineerSpec>* sm) {
56+
std::clog << "Do startWakeupTimer" << std::endl;
57+
startTimer([sm] {
58+
std::clog << "Hey wake up" << std::endl;
59+
sm->postEventTimer(std::nullptr_t());
60+
}, 1000);
61+
}
62+
static void checkEmail (EngineerSM<EngineerSpec>* sm) {
63+
std::clog << "Checking Email, hmmm..." << std::endl;
64+
}
65+
static void startHungryTimer (EngineerSM<EngineerSpec>* sm) {
66+
std::clog << "Start HungryTimer" << std::endl;
67+
startTimer([sm] {
68+
std::clog << "Ok, I'm hungry" << std::endl;
69+
sm->postEventHungry(std::nullptr_t());
70+
}, 100);
71+
}
72+
73+
static void startShortTimer (EngineerSM<EngineerSpec>* sm) {
74+
std::clog << "Start short Timer" << std::endl;
75+
startTimer([sm] {
76+
std::clog << "Hey, timer is ringing." << std::endl;
77+
sm->postEventTimer(std::nullptr_t());
78+
}, 10);
79+
}
80+
81+
static void morningRoutine (EngineerSM<EngineerSpec>* sm) {
82+
sm->accessContextLocked([] (StateMachineContext& userContext) {
83+
++userContext.wakeUpCount;
84+
std::clog << "This is my " << userContext.wakeUpCount << " day of working..." << std::endl;
85+
});
86+
}
87+
88+
static void startTiredTimer (EngineerSM<EngineerSpec>* sm) {
89+
std::clog << "Start TiredTimer" << std::endl;
90+
startTimer([sm] {
91+
std::clog << "Ok, I'm tired" << std::endl;
92+
sm->postEventTired(std::nullptr_t());
93+
}, 1000);
94+
}
95+
};
96+
97+
} // namespace
98+
99+
int main(int argc, char** argv) {
100+
engineer_demo::EngineerSM<engineer_demo::EngineerSpec> stateMachine;
101+
// Kick off the state machine with a timer event...
102+
stateMachine.postEventTimer(std::nullptr_t());
103+
104+
int wakeUpCount = 0; // We end the week after waking up 7 times.
105+
while (wakeUpCount < 7) {
106+
stateMachine.accessContextLocked([&wakeUpCount] (engineer_demo::EngineerContext& userContext) {
107+
wakeUpCount = userContext.wakeUpCount;
108+
});
109+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
110+
stateMachine.postEventTimer(std::nullptr_t());
111+
}
112+
return 0;
113+
}

demo-project/engineer_sm.cpp

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/**
2+
* This code is automatically generated using the Xstate to C++ code generator:
3+
* https://github.com/shuvalov-mdb/xstate-cpp-generator , @author Andrew Shuvalov
4+
*/
5+
6+
#include "engineer_sm.h"
7+
8+
namespace engineer_demo {
9+
10+
std::string EngineerSMStateToString(EngineerSMState state) {
11+
switch (state) {
12+
case EngineerSMState::UNDEFINED_OR_ERROR_STATE:
13+
return "UNDEFINED";
14+
case EngineerSMState::sleeping:
15+
return "EngineerSMState::sleeping";
16+
case EngineerSMState::working:
17+
return "EngineerSMState::working";
18+
case EngineerSMState::eating:
19+
return "EngineerSMState::eating";
20+
default:
21+
return "ERROR";
22+
}
23+
}
24+
25+
std::ostream& operator << (std::ostream& os, const EngineerSMState& state) {
26+
os << EngineerSMStateToString(state);
27+
return os;
28+
}
29+
30+
31+
bool isValidEngineerSMState(EngineerSMState state) {
32+
if (state == EngineerSMState::UNDEFINED_OR_ERROR_STATE) { return true; }
33+
if (state == EngineerSMState::sleeping) { return true; }
34+
if (state == EngineerSMState::working) { return true; }
35+
if (state == EngineerSMState::eating) { return true; }
36+
return false;
37+
}
38+
39+
std::string EngineerSMEventToString(EngineerSMEvent event) {
40+
switch (event) {
41+
case EngineerSMEvent::UNDEFINED_OR_ERROR_EVENT:
42+
return "UNDEFINED";
43+
case EngineerSMEvent::TIMER:
44+
return "EngineerSMEvent::TIMER";
45+
case EngineerSMEvent::TIRED:
46+
return "EngineerSMEvent::TIRED";
47+
case EngineerSMEvent::HUNGRY:
48+
return "EngineerSMEvent::HUNGRY";
49+
default:
50+
return "ERROR";
51+
}
52+
}
53+
54+
bool isValidEngineerSMEvent(EngineerSMEvent event) {
55+
if (event == EngineerSMEvent::UNDEFINED_OR_ERROR_EVENT) { return true; }
56+
if (event == EngineerSMEvent::TIMER) { return true; }
57+
if (event == EngineerSMEvent::TIRED) { return true; }
58+
if (event == EngineerSMEvent::HUNGRY) { return true; }
59+
return false;
60+
}
61+
62+
std::ostream& operator << (std::ostream& os, const EngineerSMEvent& event) {
63+
os << EngineerSMEventToString(event);
64+
return os;
65+
}
66+
67+
std::ostream& operator << (std::ostream& os, const EngineerSMTransitionPhase& phase) {
68+
switch (phase) {
69+
case EngineerSMTransitionPhase::LEAVING_STATE:
70+
os << "Leaving state ";
71+
break;
72+
case EngineerSMTransitionPhase::ENTERING_STATE:
73+
os << "Entering state ";
74+
break;
75+
case EngineerSMTransitionPhase::ENTERED_STATE:
76+
os << "Entered state ";
77+
break;
78+
case EngineerSMTransitionPhase::TRANSITION_NOT_FOUND:
79+
os << "Transition not found ";
80+
break;
81+
default:
82+
os << "ERROR ";
83+
break;
84+
}
85+
return os;
86+
}
87+
88+
89+
// static
90+
const std::vector<EngineerSMTransitionToStatesPair>&
91+
EngineerSMValidTransitionsFromSleepingState() {
92+
static const auto* transitions = new const std::vector<EngineerSMTransitionToStatesPair> {
93+
{ EngineerSMEvent::TIMER, {
94+
EngineerSMState::working } },
95+
{ EngineerSMEvent::TIRED, {
96+
EngineerSMState::sleeping } },
97+
};
98+
return *transitions;
99+
}
100+
101+
// static
102+
const std::vector<EngineerSMTransitionToStatesPair>&
103+
EngineerSMValidTransitionsFromWorkingState() {
104+
static const auto* transitions = new const std::vector<EngineerSMTransitionToStatesPair> {
105+
{ EngineerSMEvent::HUNGRY, {
106+
EngineerSMState::eating } },
107+
{ EngineerSMEvent::TIRED, {
108+
EngineerSMState::sleeping } },
109+
};
110+
return *transitions;
111+
}
112+
113+
// static
114+
const std::vector<EngineerSMTransitionToStatesPair>&
115+
EngineerSMValidTransitionsFromEatingState() {
116+
static const auto* transitions = new const std::vector<EngineerSMTransitionToStatesPair> {
117+
{ EngineerSMEvent::TIMER, {
118+
EngineerSMState::working } },
119+
{ EngineerSMEvent::TIRED, {
120+
EngineerSMState::sleeping } },
121+
};
122+
return *transitions;
123+
}
124+
125+
126+
127+
} // namespace engineer_demo

0 commit comments

Comments
 (0)