summaryrefslogtreecommitdiffstats
path: root/source/state.h
diff options
context:
space:
mode:
Diffstat (limited to 'source/state.h')
-rw-r--r--source/state.h57
1 files changed, 57 insertions, 0 deletions
diff --git a/source/state.h b/source/state.h
new file mode 100644
index 0000000..2f70527
--- /dev/null
+++ b/source/state.h
@@ -0,0 +1,57 @@
+#ifndef EXITEST_STATE_H_INCLUDED
+#define EXITEST_STATE_H_INCLUDED
+
+#include <stdint.h>
+#include <stddef.h>
+
+struct et_state;
+
+typedef union {
+ uintptr_t i;
+ void *p;
+} et_state_init_data;
+
+extern const et_state_init_data et_init_data_null;
+
+struct et_next_state {
+ const struct et_state *state;
+ et_state_init_data init_data;
+};
+
+/* Sets up the state. The second argument (void *) should point to at least state->private_size bytes
+ * of data. The state assumes responsibility for clearing/initializing this buffer before use.
+ *
+ * Returns < 0 for error, >= 0 for success.
+ * This function conceptually takes ownership of init_data. The implications of this depend
+ * on what init_data actually contains -- sometimes it's globally shared data.
+ *
+ * State authors: Free any data filled into init_data regardless of error states.
+ * The caller will not touch init_data again. */
+typedef int (et_state_init_f)(const struct et_state *, void *, et_state_init_data);
+
+/* Ticks the state.
+ *
+ * Returns < 0 for error (still call cleanup or exit(...)), 0 for "continue", >0 for "advance state".
+ * If a state requests to advance to the next state, the info will be in *next_state (which should be non-NULL).
+ * Note that next_state->init_data may have malloc()'d data which must be handed off by passing to the init function
+ * of the appropriate state. */
+typedef int (et_state_tick_f)(const struct et_state *, void *, struct et_next_state *);
+typedef void (et_state_cleanup_f)(const struct et_state *, void *);
+
+struct et_state {
+ et_state_init_f *init_f;
+ et_state_tick_f *tick_f;
+ et_state_cleanup_f *cleanup_f;
+ size_t private_size;
+};
+
+/* convenience macros because these existed as functions at one point
+ * (note: state expression is evaluated twice. make sure it doesn't have side effects) */
+
+#define et_state_init(_st, _data, _init_data) ((_st)->init_f(_st, _data, _init_data))
+#define et_state_tick(_st, _data, _next) ((_st)->tick_f(_st, _data, _next))
+#define et_state_cleanup(_st, _data) ((_st)->cleanup_f(_st, _data))
+
+extern const struct et_state *et_state_setup;
+
+#endif /* include guard */