feat(cpp/core): añadir process_state_machine pure
This commit is contained in:
@@ -39,6 +39,7 @@ add_imgui_app(primitives_gallery
|
||||
${CMAKE_SOURCE_DIR}/functions/core/toast.cpp
|
||||
${CMAKE_SOURCE_DIR}/functions/core/tree_view.cpp
|
||||
${CMAKE_SOURCE_DIR}/functions/core/process_runner.cpp
|
||||
${CMAKE_SOURCE_DIR}/functions/core/process_state_machine.cpp
|
||||
# Viz primitives demoed
|
||||
${CMAKE_SOURCE_DIR}/functions/viz/kpi_card.cpp
|
||||
${CMAKE_SOURCE_DIR}/functions/viz/bar_chart.cpp
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "core/process_state_machine.h"
|
||||
|
||||
namespace fn_ui {
|
||||
|
||||
ProcessState process_transition(ProcessState s, ProcessEvent e) {
|
||||
using S = ProcessState;
|
||||
using E = ProcessEvent;
|
||||
switch (s) {
|
||||
case S::Idle:
|
||||
// Trigger es una solicitud, el cambio real ocurre con Spawned.
|
||||
if (e == E::Spawned) return S::Running;
|
||||
return s;
|
||||
case S::Running:
|
||||
if (e == E::Finished) return S::Success;
|
||||
if (e == E::Failed || e == E::Timeout) return S::Error;
|
||||
return s;
|
||||
case S::Success:
|
||||
case S::Error:
|
||||
if (e == E::Reset) return S::Idle;
|
||||
return s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
const char* process_state_name(ProcessState s) {
|
||||
switch (s) {
|
||||
case ProcessState::Idle: return "Idle";
|
||||
case ProcessState::Running: return "Running";
|
||||
case ProcessState::Success: return "Success";
|
||||
case ProcessState::Error: return "Error";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
const char* process_event_name(ProcessEvent e) {
|
||||
switch (e) {
|
||||
case ProcessEvent::Trigger: return "Trigger";
|
||||
case ProcessEvent::Spawned: return "Spawned";
|
||||
case ProcessEvent::Finished: return "Finished";
|
||||
case ProcessEvent::Failed: return "Failed";
|
||||
case ProcessEvent::Timeout: return "Timeout";
|
||||
case ProcessEvent::Reset: return "Reset";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
} // namespace fn_ui
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
// process_state_machine — logica pura de transiciones de un proceso async
|
||||
// (idle/running/success/error) a partir de eventos. Sin threads, sin I/O.
|
||||
//
|
||||
// Diseñada para que `process_runner` (impuro, threads + popen) delegue las
|
||||
// transiciones aqui y la UI/CLI puedan razonar sobre el estado sin depender
|
||||
// de la implementacion concreta del runner.
|
||||
|
||||
namespace fn_ui {
|
||||
|
||||
enum class ProcessState {
|
||||
Idle,
|
||||
Running,
|
||||
Success,
|
||||
Error,
|
||||
};
|
||||
|
||||
enum class ProcessEvent {
|
||||
Trigger, // se solicita lanzar (no cambia estado por si solo)
|
||||
Spawned, // el proceso/task realmente arranco
|
||||
Finished, // termino con exito
|
||||
Failed, // termino con error
|
||||
Timeout, // se cancelo por timeout (-> Error)
|
||||
Reset, // limpiar a Idle (solo desde Success/Error)
|
||||
};
|
||||
|
||||
// Pura: dado (state, event) devuelve el nuevo estado. Transiciones invalidas
|
||||
// devuelven el mismo estado sin mutar.
|
||||
ProcessState process_transition(ProcessState s, ProcessEvent e);
|
||||
|
||||
// Nombres legibles para logs/UI (sin alocar — punteros a literales staticos).
|
||||
const char* process_state_name(ProcessState s);
|
||||
const char* process_event_name(ProcessEvent e);
|
||||
|
||||
} // namespace fn_ui
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
name: process_state_machine
|
||||
kind: function
|
||||
lang: cpp
|
||||
domain: core
|
||||
version: "1.0.0"
|
||||
purity: pure
|
||||
signature: "fn_ui::ProcessState fn_ui::process_transition(fn_ui::ProcessState s, fn_ui::ProcessEvent e); const char* fn_ui::process_state_name(fn_ui::ProcessState); const char* fn_ui::process_event_name(fn_ui::ProcessEvent)"
|
||||
description: "State machine puro para procesos async. Estados: Idle, Running, Success, Error. Eventos: Trigger, Spawned, Finished, Failed, Timeout, Reset. Transiciones invalidas devuelven el mismo estado sin mutar."
|
||||
tags: [state_machine, process, async, runner, pure]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: ""
|
||||
imports: []
|
||||
tested: true
|
||||
tests: ["process_transition: idle/spawned -> running", "process_transition: running -> success/error", "process_transition: reset from terminal", "process_transition: invalid events keep state", "process_state_name and process_event_name"]
|
||||
test_file_path: "cpp/tests/test_process_state_machine.cpp"
|
||||
file_path: "cpp/functions/core/process_state_machine.cpp"
|
||||
params:
|
||||
- name: s
|
||||
desc: "Estado actual (Idle, Running, Success, Error)"
|
||||
- name: e
|
||||
desc: "Evento a aplicar (Trigger, Spawned, Finished, Failed, Timeout, Reset)"
|
||||
output: "Nuevo ProcessState. Si la transicion (s, e) no esta definida, devuelve s sin cambios. process_state_name y process_event_name retornan punteros a literales staticos (no alocan)."
|
||||
---
|
||||
|
||||
# process_state_machine
|
||||
|
||||
Las apps del registry usan `process_runner` (impuro: threads, mutex, popen)
|
||||
para lanzar reindex, builds, deploys... Esta funcion extrae el contrato de
|
||||
estados a una tabla pura que se puede testear, simular y compartir con CLIs
|
||||
y bots sin depender del runner concreto.
|
||||
|
||||
## Tabla de transiciones
|
||||
|
||||
| Estado actual | Evento | Nuevo estado |
|
||||
|---------------|------------|--------------|
|
||||
| Idle | Spawned | Running |
|
||||
| Idle | Trigger | Idle (la solicitud no cambia el estado por si sola — el runner debe Spawnar) |
|
||||
| Running | Finished | Success |
|
||||
| Running | Failed | Error |
|
||||
| Running | Timeout | Error |
|
||||
| Success | Reset | Idle |
|
||||
| Error | Reset | Idle |
|
||||
| cualquier otra combinacion | | mismo estado |
|
||||
|
||||
`Trigger` se mantiene como evento explicito para que el runner pueda emitir
|
||||
"se pidio lanzar" antes de saber si el proceso arranca (util para logs y UI).
|
||||
|
||||
## API
|
||||
|
||||
```cpp
|
||||
namespace fn_ui {
|
||||
|
||||
enum class ProcessState { Idle, Running, Success, Error };
|
||||
enum class ProcessEvent { Trigger, Spawned, Finished, Failed, Timeout, Reset };
|
||||
|
||||
ProcessState process_transition(ProcessState s, ProcessEvent e);
|
||||
const char* process_state_name(ProcessState s);
|
||||
const char* process_event_name(ProcessEvent e);
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## Uso desde process_runner
|
||||
|
||||
`process_runner` mantiene su `std::atomic<int>` con el estado, pero llama a
|
||||
`process_transition` para decidir el siguiente valor. Esto evita que la
|
||||
logica de transicion se duplique entre el thread productor y la UI consumer.
|
||||
Reference in New Issue
Block a user