-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
28b0d33
commit 84dc7d8
Showing
6 changed files
with
1,169 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
//const CppGen = require('xstate-cpp-generator'); | ||
import { generateCpp } from '../src/cpp_state_machine_generator'; | ||
const path = require('path'); | ||
|
||
import { Machine } from 'xstate'; | ||
|
||
const engineerMachine = Machine({ | ||
id: 'engineer', | ||
initial: 'sleeping', | ||
states: { | ||
sleeping: { | ||
entry: 'startWakeupTimer', | ||
exit: 'morningRoutine', | ||
on: { | ||
'TIMER': { target: 'working', actions: ['startHungryTimer', 'startTiredTimer'] }, | ||
'TIRED': { target: 'sleeping' } | ||
} | ||
}, | ||
working: { | ||
entry: ['checkEmail', 'startHungryTimer' ], | ||
on: { | ||
'HUNGRY': { target: 'eating', actions: ['checkEmail']}, | ||
'TIRED': { target: 'sleeping' } | ||
}, | ||
}, | ||
eating: { | ||
entry: 'startShortTimer', | ||
exit: [ 'checkEmail', 'startHungryTimer', 'startTiredTimer' ], | ||
on: { | ||
'TIMER': { target: 'working', actions: ['startHungryTimer'] }, | ||
'TIRED': { target: 'sleeping' } | ||
} | ||
} | ||
} | ||
}); | ||
|
||
|
||
//CppGen. | ||
generateCpp({ | ||
xstateMachine: engineerMachine, | ||
destinationPath: "", | ||
namespace: "engineer_demo", | ||
pathForIncludes: "", | ||
tsScriptName: path.basename(__filename) | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
#include "engineer_sm.h" | ||
|
||
#include <chrono> | ||
#include <thread> | ||
|
||
namespace engineer_demo { | ||
|
||
template<typename Function> | ||
void startTimer(Function function, int delayMs) { | ||
std::thread t([=]() { | ||
std::this_thread::sleep_for(std::chrono::milliseconds(delayMs)); | ||
function(); | ||
}); | ||
t.detach(); | ||
} | ||
|
||
struct EngineerContext { | ||
// The demo will end after the Engineer wakes up 7 times. | ||
int wakeUpCount = 0; | ||
}; | ||
|
||
struct EngineerSpec { | ||
// Spec should always contain some 'using' for the StateMachineContext. | ||
using StateMachineContext = EngineerContext; | ||
|
||
// Then it should have a list of 'using' declarations for every event payload. | ||
using EventTimerPayload = std::nullptr_t; | ||
using EventHungryPayload = std::nullptr_t; | ||
using EventTiredPayload = std::nullptr_t; | ||
|
||
/** | ||
* This block is for transition actions. | ||
*/ | ||
static void startHungryTimer (EngineerSM<EngineerSpec>* sm, EventTimerPayload* payload) { | ||
std::clog << "Start HungryTimer from timer event" << std::endl; | ||
startTimer([sm] { | ||
std::clog << "Ok, I'm hungry" << std::endl; | ||
sm->postEventHungry(std::nullptr_t()); | ||
}, 100); | ||
} | ||
static void startTiredTimer (EngineerSM<EngineerSpec>* sm, EventTimerPayload* payload) { | ||
std::clog << "Start TiredTimer from timer event" << std::endl; | ||
startTimer([sm] { | ||
std::clog << "Ok, I'm tired" << std::endl; | ||
sm->postEventTired(std::nullptr_t()); | ||
}, 1000); | ||
} | ||
static void checkEmail (EngineerSM<EngineerSpec>* sm, EventHungryPayload* payload) { | ||
std::clog << "Checking Email, while being hugry! ok..." << std::endl; | ||
} | ||
|
||
/** | ||
* This block is for entry and exit state actions. | ||
*/ | ||
static void startWakeupTimer (EngineerSM<EngineerSpec>* sm) { | ||
std::clog << "Do startWakeupTimer" << std::endl; | ||
startTimer([sm] { | ||
std::clog << "Hey wake up" << std::endl; | ||
sm->postEventTimer(std::nullptr_t()); | ||
}, 1000); | ||
} | ||
static void checkEmail (EngineerSM<EngineerSpec>* sm) { | ||
std::clog << "Checking Email, hmmm..." << std::endl; | ||
} | ||
static void startHungryTimer (EngineerSM<EngineerSpec>* sm) { | ||
std::clog << "Start HungryTimer" << std::endl; | ||
startTimer([sm] { | ||
std::clog << "Ok, I'm hungry" << std::endl; | ||
sm->postEventHungry(std::nullptr_t()); | ||
}, 100); | ||
} | ||
|
||
static void startShortTimer (EngineerSM<EngineerSpec>* sm) { | ||
std::clog << "Start short Timer" << std::endl; | ||
startTimer([sm] { | ||
std::clog << "Hey, timer is ringing." << std::endl; | ||
sm->postEventTimer(std::nullptr_t()); | ||
}, 10); | ||
} | ||
|
||
static void morningRoutine (EngineerSM<EngineerSpec>* sm) { | ||
sm->accessContextLocked([] (StateMachineContext& userContext) { | ||
++userContext.wakeUpCount; | ||
std::clog << "This is my " << userContext.wakeUpCount << " day of working..." << std::endl; | ||
}); | ||
} | ||
|
||
static void startTiredTimer (EngineerSM<EngineerSpec>* sm) { | ||
std::clog << "Start TiredTimer" << std::endl; | ||
startTimer([sm] { | ||
std::clog << "Ok, I'm tired" << std::endl; | ||
sm->postEventTired(std::nullptr_t()); | ||
}, 1000); | ||
} | ||
}; | ||
|
||
} // namespace | ||
|
||
int main(int argc, char** argv) { | ||
engineer_demo::EngineerSM<engineer_demo::EngineerSpec> stateMachine; | ||
// Kick off the state machine with a timer event... | ||
stateMachine.postEventTimer(std::nullptr_t()); | ||
|
||
int wakeUpCount = 0; // We end the week after waking up 7 times. | ||
while (wakeUpCount < 7) { | ||
stateMachine.accessContextLocked([&wakeUpCount] (engineer_demo::EngineerContext& userContext) { | ||
wakeUpCount = userContext.wakeUpCount; | ||
}); | ||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); | ||
stateMachine.postEventTimer(std::nullptr_t()); | ||
} | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
/** | ||
* This code is automatically generated using the Xstate to C++ code generator: | ||
* https://github.com/shuvalov-mdb/xstate-cpp-generator , @author Andrew Shuvalov | ||
*/ | ||
|
||
#include "engineer_sm.h" | ||
|
||
namespace engineer_demo { | ||
|
||
std::string EngineerSMStateToString(EngineerSMState state) { | ||
switch (state) { | ||
case EngineerSMState::UNDEFINED_OR_ERROR_STATE: | ||
return "UNDEFINED"; | ||
case EngineerSMState::sleeping: | ||
return "EngineerSMState::sleeping"; | ||
case EngineerSMState::working: | ||
return "EngineerSMState::working"; | ||
case EngineerSMState::eating: | ||
return "EngineerSMState::eating"; | ||
default: | ||
return "ERROR"; | ||
} | ||
} | ||
|
||
std::ostream& operator << (std::ostream& os, const EngineerSMState& state) { | ||
os << EngineerSMStateToString(state); | ||
return os; | ||
} | ||
|
||
|
||
bool isValidEngineerSMState(EngineerSMState state) { | ||
if (state == EngineerSMState::UNDEFINED_OR_ERROR_STATE) { return true; } | ||
if (state == EngineerSMState::sleeping) { return true; } | ||
if (state == EngineerSMState::working) { return true; } | ||
if (state == EngineerSMState::eating) { return true; } | ||
return false; | ||
} | ||
|
||
std::string EngineerSMEventToString(EngineerSMEvent event) { | ||
switch (event) { | ||
case EngineerSMEvent::UNDEFINED_OR_ERROR_EVENT: | ||
return "UNDEFINED"; | ||
case EngineerSMEvent::TIMER: | ||
return "EngineerSMEvent::TIMER"; | ||
case EngineerSMEvent::TIRED: | ||
return "EngineerSMEvent::TIRED"; | ||
case EngineerSMEvent::HUNGRY: | ||
return "EngineerSMEvent::HUNGRY"; | ||
default: | ||
return "ERROR"; | ||
} | ||
} | ||
|
||
bool isValidEngineerSMEvent(EngineerSMEvent event) { | ||
if (event == EngineerSMEvent::UNDEFINED_OR_ERROR_EVENT) { return true; } | ||
if (event == EngineerSMEvent::TIMER) { return true; } | ||
if (event == EngineerSMEvent::TIRED) { return true; } | ||
if (event == EngineerSMEvent::HUNGRY) { return true; } | ||
return false; | ||
} | ||
|
||
std::ostream& operator << (std::ostream& os, const EngineerSMEvent& event) { | ||
os << EngineerSMEventToString(event); | ||
return os; | ||
} | ||
|
||
std::ostream& operator << (std::ostream& os, const EngineerSMTransitionPhase& phase) { | ||
switch (phase) { | ||
case EngineerSMTransitionPhase::LEAVING_STATE: | ||
os << "Leaving state "; | ||
break; | ||
case EngineerSMTransitionPhase::ENTERING_STATE: | ||
os << "Entering state "; | ||
break; | ||
case EngineerSMTransitionPhase::ENTERED_STATE: | ||
os << "Entered state "; | ||
break; | ||
case EngineerSMTransitionPhase::TRANSITION_NOT_FOUND: | ||
os << "Transition not found "; | ||
break; | ||
default: | ||
os << "ERROR "; | ||
break; | ||
} | ||
return os; | ||
} | ||
|
||
|
||
// static | ||
const std::vector<EngineerSMTransitionToStatesPair>& | ||
EngineerSMValidTransitionsFromSleepingState() { | ||
static const auto* transitions = new const std::vector<EngineerSMTransitionToStatesPair> { | ||
{ EngineerSMEvent::TIMER, { | ||
EngineerSMState::working } }, | ||
{ EngineerSMEvent::TIRED, { | ||
EngineerSMState::sleeping } }, | ||
}; | ||
return *transitions; | ||
} | ||
|
||
// static | ||
const std::vector<EngineerSMTransitionToStatesPair>& | ||
EngineerSMValidTransitionsFromWorkingState() { | ||
static const auto* transitions = new const std::vector<EngineerSMTransitionToStatesPair> { | ||
{ EngineerSMEvent::HUNGRY, { | ||
EngineerSMState::eating } }, | ||
{ EngineerSMEvent::TIRED, { | ||
EngineerSMState::sleeping } }, | ||
}; | ||
return *transitions; | ||
} | ||
|
||
// static | ||
const std::vector<EngineerSMTransitionToStatesPair>& | ||
EngineerSMValidTransitionsFromEatingState() { | ||
static const auto* transitions = new const std::vector<EngineerSMTransitionToStatesPair> { | ||
{ EngineerSMEvent::TIMER, { | ||
EngineerSMState::working } }, | ||
{ EngineerSMEvent::TIRED, { | ||
EngineerSMState::sleeping } }, | ||
}; | ||
return *transitions; | ||
} | ||
|
||
|
||
|
||
} // namespace engineer_demo |
Oops, something went wrong.