elementdrawing 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/LICENSE +21 -0
  2. package/dist/elementdrawing.min.js +3 -0
  3. package/dist/elementdrawing.min.js.LICENSE.txt +8 -0
  4. package/dist/elementdrawing.min.js.map +1 -0
  5. package/dist/index.html +1 -0
  6. package/package.json +127 -0
  7. package/src/core/bridge.h +855 -0
  8. package/src/core/diff.c +900 -0
  9. package/src/core/element.c +1078 -0
  10. package/src/core/event.c +813 -0
  11. package/src/core/fiber.c +1027 -0
  12. package/src/core/hooks.c +919 -0
  13. package/src/core/renderer.c +963 -0
  14. package/src/core/scheduler.c +702 -0
  15. package/src/core/state.c +803 -0
  16. package/src/css/animations.css +779 -0
  17. package/src/css/base.css +615 -0
  18. package/src/css/components.css +1311 -0
  19. package/src/css/tailwind.css +370 -0
  20. package/src/css/themes.css +517 -0
  21. package/src/css/utilities.css +475 -0
  22. package/src/index.js +746 -0
  23. package/src/js/animation.js +655 -0
  24. package/src/js/dom.js +665 -0
  25. package/src/js/events.js +585 -0
  26. package/src/js/http.js +446 -0
  27. package/src/js/index.js +26 -0
  28. package/src/js/router.js +483 -0
  29. package/src/js/store.js +539 -0
  30. package/src/js/utils.js +593 -0
  31. package/src/js/validator.js +529 -0
  32. package/src/jsx/components/Accordion.jsx +210 -0
  33. package/src/jsx/components/Alert.jsx +169 -0
  34. package/src/jsx/components/Avatar.jsx +214 -0
  35. package/src/jsx/components/Badge.jsx +136 -0
  36. package/src/jsx/components/Breadcrumb.jsx +200 -0
  37. package/src/jsx/components/Button.jsx +188 -0
  38. package/src/jsx/components/Card.jsx +192 -0
  39. package/src/jsx/components/Carousel.jsx +278 -0
  40. package/src/jsx/components/Checkbox.jsx +215 -0
  41. package/src/jsx/components/Dialog.jsx +242 -0
  42. package/src/jsx/components/Drawer.jsx +190 -0
  43. package/src/jsx/components/Dropdown.jsx +268 -0
  44. package/src/jsx/components/Form.jsx +274 -0
  45. package/src/jsx/components/Input.jsx +285 -0
  46. package/src/jsx/components/Menu.jsx +276 -0
  47. package/src/jsx/components/Modal.jsx +274 -0
  48. package/src/jsx/components/Navbar.jsx +292 -0
  49. package/src/jsx/components/Pagination.jsx +268 -0
  50. package/src/jsx/components/Progress.jsx +252 -0
  51. package/src/jsx/components/Radio.jsx +208 -0
  52. package/src/jsx/components/Select.jsx +397 -0
  53. package/src/jsx/components/Sidebar.jsx +250 -0
  54. package/src/jsx/components/Slider.jsx +310 -0
  55. package/src/jsx/components/Spinner.jsx +198 -0
  56. package/src/jsx/components/Switch.jsx +201 -0
  57. package/src/jsx/components/Table.jsx +332 -0
  58. package/src/jsx/components/Tabs.jsx +227 -0
  59. package/src/jsx/components/Textarea.jsx +212 -0
  60. package/src/jsx/components/Toast.jsx +270 -0
  61. package/src/jsx/components/Tooltip.jsx +178 -0
  62. package/src/jsx/components/Typography.jsx +299 -0
  63. package/src/jsx/components/index.jsx +70 -0
  64. package/src/jsx/core/element.js +3 -0
  65. package/src/jsx/hooks/index.js +356 -0
  66. package/src/jsx/hooks/useCallback.js +472 -0
  67. package/src/jsx/hooks/useContext.js +586 -0
  68. package/src/jsx/hooks/useEffect.js +704 -0
  69. package/src/jsx/hooks/useLayoutEffect.js +508 -0
  70. package/src/jsx/hooks/useMemo.js +689 -0
  71. package/src/jsx/hooks/useReducer.js +729 -0
  72. package/src/jsx/hooks/useRef.js +542 -0
  73. package/src/jsx/hooks/useState.js +854 -0
  74. package/src/jsx/runtime/commit.js +903 -0
  75. package/src/jsx/runtime/createElement.js +860 -0
  76. package/src/jsx/runtime/index.js +356 -0
  77. package/src/jsx/runtime/reconcile.js +687 -0
  78. package/src/jsx/runtime/render.js +914 -0
@@ -0,0 +1,803 @@
1
+ /*
2
+ * state.c - ElementDrawing Core: State Management
3
+ *
4
+ * Implements the state management system for the ElementDrawing engine.
5
+ * Provides a centralized state manager, individual state nodes with
6
+ * versioning, update batching, transaction support, and a state tree
7
+ * for hierarchical state management.
8
+ */
9
+
10
+ #include "bridge.h"
11
+
12
+ /* ================================================================
13
+ * State Update Record
14
+ * ================================================================ */
15
+
16
+ typedef struct EDStateUpdate {
17
+ void* new_value;
18
+ EDStateUpdater reducer;
19
+ void* action;
20
+ uint64_t timestamp;
21
+ bool is_applied;
22
+ struct EDStateUpdate* next;
23
+ } EDStateUpdate;
24
+
25
+ static EDStateUpdate* ed_state_update_create(void* new_value)
26
+ {
27
+ EDStateUpdate* update = (EDStateUpdate*)calloc(1, sizeof(EDStateUpdate));
28
+ if (!update) return NULL;
29
+
30
+ update->new_value = new_value;
31
+ update->reducer = NULL;
32
+ update->action = NULL;
33
+ update->timestamp = ed_get_timestamp_ms();
34
+ update->is_applied = false;
35
+ update->next = NULL;
36
+
37
+ return update;
38
+ }
39
+
40
+ static void ed_state_update_destroy(EDStateUpdate* update)
41
+ {
42
+ if (!update) return;
43
+ free(update);
44
+ }
45
+
46
+ /* ================================================================
47
+ * Transaction Support
48
+ * ================================================================ */
49
+
50
+ typedef struct EDStateTransaction {
51
+ uint32_t id;
52
+ bool is_active;
53
+ bool is_committed;
54
+ bool is_rolled_back;
55
+ uint32_t update_count;
56
+
57
+ /* Snapshot of state versions at transaction start */
58
+ uint32_t* version_snapshots;
59
+ void** value_snapshots;
60
+ uint32_t snapshot_capacity;
61
+
62
+ struct EDStateTransaction* next;
63
+ } EDStateTransaction;
64
+
65
+ static EDStateTransaction* g_active_transaction = NULL;
66
+ static uint32_t g_transaction_id_counter = 0;
67
+
68
+ static EDStateTransaction* ed_transaction_create(uint32_t state_count)
69
+ {
70
+ EDStateTransaction* txn = (EDStateTransaction*)calloc(1, sizeof(EDStateTransaction));
71
+ if (!txn) return NULL;
72
+
73
+ txn->id = ++g_transaction_id_counter;
74
+ txn->is_active = true;
75
+ txn->is_committed = false;
76
+ txn->is_rolled_back = false;
77
+ txn->update_count = 0;
78
+
79
+ if (state_count > 0) {
80
+ txn->snapshot_capacity = state_count;
81
+ txn->version_snapshots = (uint32_t*)calloc(state_count, sizeof(uint32_t));
82
+ txn->value_snapshots = (void**)calloc(state_count, sizeof(void*));
83
+ } else {
84
+ txn->snapshot_capacity = 16;
85
+ txn->version_snapshots = (uint32_t*)calloc(16, sizeof(uint32_t));
86
+ txn->value_snapshots = (void**)calloc(16, sizeof(void*));
87
+ }
88
+
89
+ return txn;
90
+ }
91
+
92
+ static void ed_transaction_destroy(EDStateTransaction* txn)
93
+ {
94
+ if (!txn) return;
95
+ if (txn->version_snapshots) free(txn->version_snapshots);
96
+ if (txn->value_snapshots) free(txn->value_snapshots);
97
+ free(txn);
98
+ }
99
+
100
+ /* ================================================================
101
+ * State Manager Creation and Destruction
102
+ * ================================================================ */
103
+
104
+ EDStateManager* ed_state_manager_create(void)
105
+ {
106
+ EDStateManager* manager = (EDStateManager*)calloc(1, sizeof(EDStateManager));
107
+ if (!manager) return NULL;
108
+
109
+ for (uint32_t i = 0; i < ED_HOOKS_STATE_SLOTS; i++) {
110
+ manager->states[i] = NULL;
111
+ manager->state_counts[i] = 0;
112
+ }
113
+
114
+ manager->total_states = 0;
115
+ manager->active_states = 0;
116
+ manager->total_updates = 0;
117
+ manager->batched_updates = 0;
118
+ manager->is_batching = false;
119
+ manager->batch_callback = NULL;
120
+
121
+ ed_log_debug("State manager created");
122
+ return manager;
123
+ }
124
+
125
+ void ed_state_manager_destroy(EDStateManager* manager)
126
+ {
127
+ if (!manager) return;
128
+
129
+ /* Destroy all state nodes */
130
+ for (uint32_t i = 0; i < ED_HOOKS_STATE_SLOTS; i++) {
131
+ EDStateNode* node = manager->states[i];
132
+ while (node) {
133
+ EDStateNode* next = node->next;
134
+ ed_state_destroy(node);
135
+ node = next;
136
+ }
137
+ manager->states[i] = NULL;
138
+ }
139
+
140
+ free(manager);
141
+ ed_log_debug("State manager destroyed");
142
+ }
143
+
144
+ /* ================================================================
145
+ * State Node Creation and Destruction
146
+ * ================================================================ */
147
+
148
+ EDStateNode* ed_state_create(void* initial_value)
149
+ {
150
+ EDStateNode* state = (EDStateNode*)calloc(1, sizeof(EDStateNode));
151
+ if (!state) return NULL;
152
+
153
+ state->value = initial_value;
154
+ state->updater = NULL;
155
+ state->version = 0;
156
+ state->last_update_time = ed_get_timestamp_ms();
157
+ state->is_pending = false;
158
+ state->next = NULL;
159
+
160
+ return state;
161
+ }
162
+
163
+ void ed_state_destroy(EDStateNode* state)
164
+ {
165
+ if (!state) return;
166
+
167
+ /* Free update queue if present */
168
+ state->updater = NULL;
169
+ state->value = NULL;
170
+ free(state);
171
+ }
172
+
173
+ /* ================================================================
174
+ * State Registration
175
+ * ================================================================ */
176
+
177
+ static uint32_t ed_state_compute_slot(EDStateNode* state)
178
+ {
179
+ /* Simple slot computation based on pointer hash */
180
+ uintptr_t ptr = (uintptr_t)state;
181
+ return (uint32_t)(ptr % ED_HOOKS_STATE_SLOTS);
182
+ }
183
+
184
+ static void ed_state_manager_register(EDStateManager* manager, EDStateNode* state)
185
+ {
186
+ if (!manager || !state) return;
187
+
188
+ uint32_t slot = ed_state_compute_slot(state);
189
+ state->next = manager->states[slot];
190
+ manager->states[slot] = state;
191
+ manager->state_counts[slot]++;
192
+ manager->total_states++;
193
+ manager->active_states++;
194
+ }
195
+
196
+ static void ed_state_manager_unregister(EDStateManager* manager, EDStateNode* state)
197
+ {
198
+ if (!manager || !state) return;
199
+
200
+ uint32_t slot = ed_state_compute_slot(state);
201
+ EDStateNode** prev = &manager->states[slot];
202
+ EDStateNode* current = manager->states[slot];
203
+
204
+ while (current) {
205
+ if (current == state) {
206
+ *prev = current->next;
207
+ state->next = NULL;
208
+ manager->state_counts[slot]--;
209
+ manager->active_states--;
210
+ return;
211
+ }
212
+ prev = &current->next;
213
+ current = current->next;
214
+ }
215
+ }
216
+
217
+ /* ================================================================
218
+ * State Updates
219
+ * ================================================================ */
220
+
221
+ void ed_state_update(EDStateNode* state, void* new_value)
222
+ {
223
+ if (!state) return;
224
+
225
+ if (g_active_transaction && g_active_transaction->is_active) {
226
+ /* Record in transaction */
227
+ g_active_transaction->update_count++;
228
+ }
229
+
230
+ state->value = new_value;
231
+ state->version++;
232
+ state->last_update_time = ed_get_timestamp_ms();
233
+ state->is_pending = false;
234
+ }
235
+
236
+ void ed_state_batch_update(EDStateManager* manager, EDStateNode** states,
237
+ void** values, uint32_t count)
238
+ {
239
+ if (!manager || !states || !values || count == 0) return;
240
+
241
+ manager->is_batching = true;
242
+
243
+ /* Apply all updates */
244
+ for (uint32_t i = 0; i < count; i++) {
245
+ if (states[i]) {
246
+ states[i]->value = values[i];
247
+ states[i]->version++;
248
+ states[i]->last_update_time = ed_get_timestamp_ms();
249
+ states[i]->is_pending = true; /* Mark as pending until flush */
250
+ manager->batched_updates++;
251
+ }
252
+ }
253
+
254
+ manager->total_updates += count;
255
+
256
+ /* If auto-flush is enabled, flush immediately */
257
+ if (!manager->is_batching) {
258
+ ed_state_flush_updates(manager);
259
+ }
260
+ }
261
+
262
+ void ed_state_flush_updates(EDStateManager* manager)
263
+ {
264
+ if (!manager) return;
265
+
266
+ /* Mark all pending states as committed */
267
+ for (uint32_t i = 0; i < ED_HOOKS_STATE_SLOTS; i++) {
268
+ EDStateNode* state = manager->states[i];
269
+ while (state) {
270
+ if (state->is_pending) {
271
+ state->is_pending = false;
272
+ }
273
+ state = state->next;
274
+ }
275
+ }
276
+
277
+ manager->is_batching = false;
278
+
279
+ /* Invoke batch callback if set */
280
+ if (manager->batch_callback) {
281
+ /* In a real implementation, this would trigger re-render */
282
+ }
283
+
284
+ ed_log_debug("State updates flushed (total=%llu, batched=%llu)",
285
+ (unsigned long long)manager->total_updates,
286
+ (unsigned long long)manager->batched_updates);
287
+ }
288
+
289
+ uint32_t ed_state_version(EDStateNode* state)
290
+ {
291
+ return state ? state->version : 0;
292
+ }
293
+
294
+ /* ================================================================
295
+ * State Tree (Hierarchical State)
296
+ * ================================================================ */
297
+
298
+ typedef struct EDStateTree {
299
+ EDStateNode* root;
300
+ uint32_t depth;
301
+ uint32_t node_count;
302
+ } EDStateTree;
303
+
304
+ static EDStateTree* ed_state_tree_create(void)
305
+ {
306
+ EDStateTree* tree = (EDStateTree*)calloc(1, sizeof(EDStateTree));
307
+ if (!tree) return NULL;
308
+
309
+ tree->root = NULL;
310
+ tree->depth = 0;
311
+ tree->node_count = 0;
312
+
313
+ return tree;
314
+ }
315
+
316
+ static void ed_state_tree_destroy(EDStateTree* tree)
317
+ {
318
+ if (!tree) return;
319
+ /* StateNodes are owned by the StateManager, not the tree */
320
+ free(tree);
321
+ }
322
+
323
+ typedef struct EDStateTreeNode {
324
+ EDStateNode* state;
325
+ struct EDStateTreeNode* parent;
326
+ struct EDStateTreeNode* first_child;
327
+ struct EDStateTreeNode* next_sibling;
328
+ uint32_t child_count;
329
+ } EDStateTreeNode;
330
+
331
+ static EDStateTreeNode* ed_state_tree_node_create(EDStateNode* state)
332
+ {
333
+ EDStateTreeNode* node = (EDStateTreeNode*)calloc(1, sizeof(EDStateTreeNode));
334
+ if (!node) return NULL;
335
+
336
+ node->state = state;
337
+ node->parent = NULL;
338
+ node->first_child = NULL;
339
+ node->next_sibling = NULL;
340
+ node->child_count = 0;
341
+
342
+ return node;
343
+ }
344
+
345
+ static void ed_state_tree_node_add_child(EDStateTreeNode* parent, EDStateTreeNode* child)
346
+ {
347
+ if (!parent || !child) return;
348
+
349
+ child->parent = parent;
350
+
351
+ if (!parent->first_child) {
352
+ parent->first_child = child;
353
+ } else {
354
+ /* Add as last sibling */
355
+ EDStateTreeNode* sibling = parent->first_child;
356
+ while (sibling->next_sibling) {
357
+ sibling = sibling->next_sibling;
358
+ }
359
+ sibling->next_sibling = child;
360
+ }
361
+ parent->child_count++;
362
+ }
363
+
364
+ static EDStateTreeNode* ed_state_tree_find(EDStateTreeNode* root, EDStateNode* target)
365
+ {
366
+ if (!root) return NULL;
367
+ if (root->state == target) return root;
368
+
369
+ EDStateTreeNode* found = ed_state_tree_find(root->first_child, target);
370
+ if (found) return found;
371
+
372
+ return ed_state_tree_find(root->next_sibling, target);
373
+ }
374
+
375
+ /* ================================================================
376
+ * Transaction Implementation
377
+ * ================================================================ */
378
+
379
+ static EDStateTransaction* ed_state_begin_transaction(EDStateManager* manager)
380
+ {
381
+ if (!manager) return NULL;
382
+
383
+ if (g_active_transaction && g_active_transaction->is_active) {
384
+ ed_log_warn("Transaction already active (id=%u)", g_active_transaction->id);
385
+ return g_active_transaction;
386
+ }
387
+
388
+ EDStateTransaction* txn = ed_transaction_create(manager->active_states);
389
+ if (!txn) return NULL;
390
+
391
+ /* Snapshot current state versions */
392
+ uint32_t idx = 0;
393
+ for (uint32_t i = 0; i < ED_HOOKS_STATE_SLOTS && idx < txn->snapshot_capacity; i++) {
394
+ EDStateNode* state = manager->states[i];
395
+ while (state && idx < txn->snapshot_capacity) {
396
+ txn->version_snapshots[idx] = state->version;
397
+ txn->value_snapshots[idx] = state->value;
398
+ idx++;
399
+ state = state->next;
400
+ }
401
+ }
402
+
403
+ g_active_transaction = txn;
404
+ ed_log_debug("Transaction started (id=%u)", txn->id);
405
+ return txn;
406
+ }
407
+
408
+ static bool ed_state_commit_transaction(EDStateManager* manager, EDStateTransaction* txn)
409
+ {
410
+ if (!manager || !txn || !txn->is_active) return false;
411
+
412
+ txn->is_active = false;
413
+ txn->is_committed = true;
414
+
415
+ /* Flush updates */
416
+ ed_state_flush_updates(manager);
417
+
418
+ ed_log_debug("Transaction committed (id=%u, updates=%u)",
419
+ txn->id, txn->update_count);
420
+
421
+ if (g_active_transaction == txn) {
422
+ g_active_transaction = NULL;
423
+ }
424
+
425
+ ed_transaction_destroy(txn);
426
+ return true;
427
+ }
428
+
429
+ static bool ed_state_rollback_transaction(EDStateManager* manager, EDStateTransaction* txn)
430
+ {
431
+ if (!manager || !txn || !txn->is_active) return false;
432
+
433
+ txn->is_active = false;
434
+ txn->is_rolled_back = true;
435
+
436
+ /* Restore state values from snapshots */
437
+ uint32_t idx = 0;
438
+ for (uint32_t i = 0; i < ED_HOOKS_STATE_SLOTS && idx < txn->snapshot_capacity; i++) {
439
+ EDStateNode* state = manager->states[i];
440
+ while (state && idx < txn->snapshot_capacity) {
441
+ if (state->version != txn->version_snapshots[idx]) {
442
+ state->value = txn->value_snapshots[idx];
443
+ state->version = txn->version_snapshots[idx];
444
+ state->is_pending = false;
445
+ }
446
+ idx++;
447
+ state = state->next;
448
+ }
449
+ }
450
+
451
+ ed_log_debug("Transaction rolled back (id=%u)", txn->id);
452
+
453
+ if (g_active_transaction == txn) {
454
+ g_active_transaction = NULL;
455
+ }
456
+
457
+ ed_transaction_destroy(txn);
458
+ return true;
459
+ }
460
+
461
+ /* ================================================================
462
+ * Update Batching with Priority
463
+ * ================================================================ */
464
+
465
+ typedef struct EDBatchedUpdate {
466
+ EDStateNode* state;
467
+ void* new_value;
468
+ EDSchedulerPriority priority;
469
+ uint64_t timestamp;
470
+ struct EDBatchedUpdate* next;
471
+ } EDBatchedUpdate;
472
+
473
+ typedef struct EDBatchQueue {
474
+ EDBatchedUpdate* head;
475
+ EDBatchedUpdate* tail;
476
+ uint32_t count;
477
+ } EDBatchQueue;
478
+
479
+ static EDBatchQueue g_batch_queue = {0};
480
+
481
+ static void ed_batch_queue_push(EDBatchQueue* queue, EDStateNode* state,
482
+ void* new_value, EDSchedulerPriority priority)
483
+ {
484
+ if (!queue || !state) return;
485
+
486
+ EDBatchedUpdate* update = (EDBatchedUpdate*)calloc(1, sizeof(EDBatchedUpdate));
487
+ if (!update) return;
488
+
489
+ update->state = state;
490
+ update->new_value = new_value;
491
+ update->priority = priority;
492
+ update->timestamp = ed_get_timestamp_ms();
493
+ update->next = NULL;
494
+
495
+ if (!queue->tail) {
496
+ queue->head = update;
497
+ queue->tail = update;
498
+ } else {
499
+ /* Insert by priority (highest first) */
500
+ EDBatchedUpdate** prev = &queue->head;
501
+ EDBatchedUpdate* current = queue->head;
502
+
503
+ while (current && current->priority <= priority) {
504
+ prev = &current->next;
505
+ current = current->next;
506
+ }
507
+
508
+ update->next = current;
509
+ *prev = update;
510
+
511
+ if (!update->next) {
512
+ queue->tail = update;
513
+ }
514
+ }
515
+ queue->count++;
516
+ }
517
+
518
+ static EDBatchedUpdate* ed_batch_queue_pop(EDBatchQueue* queue)
519
+ {
520
+ if (!queue || !queue->head) return NULL;
521
+
522
+ EDBatchedUpdate* update = queue->head;
523
+ queue->head = update->next;
524
+ if (!queue->head) {
525
+ queue->tail = NULL;
526
+ }
527
+ queue->count--;
528
+
529
+ return update;
530
+ }
531
+
532
+ static void ed_batch_queue_flush(EDStateManager* manager)
533
+ {
534
+ if (!manager) return;
535
+
536
+ uint32_t applied = 0;
537
+ while (g_batch_queue.count > 0) {
538
+ EDBatchedUpdate* update = ed_batch_queue_pop(&g_batch_queue);
539
+ if (update) {
540
+ ed_state_update(update->state, update->new_value);
541
+ applied++;
542
+ free(update);
543
+ }
544
+ }
545
+
546
+ ed_state_flush_updates(manager);
547
+
548
+ ed_log_debug("Batch queue flushed: %u updates applied", applied);
549
+ }
550
+
551
+ /* ================================================================
552
+ * State Observer Pattern
553
+ * ================================================================ */
554
+
555
+ typedef void (*EDStateObserver)(EDStateNode* state, void* old_value, void* new_value);
556
+
557
+ typedef struct EDStateObserverEntry {
558
+ EDStateNode* target;
559
+ EDStateObserver callback;
560
+ void* context;
561
+ struct EDStateObserverEntry* next;
562
+ } EDStateObserverEntry;
563
+
564
+ #define ED_MAX_OBSERVERS 256
565
+
566
+ static EDStateObserverEntry* g_observers[ED_MAX_OBSERVERS] = {0};
567
+ static uint32_t g_observer_count = 0;
568
+
569
+ static uint32_t ed_state_add_observer(EDStateNode* state, EDStateObserver callback, void* context)
570
+ {
571
+ if (!state || !callback || g_observer_count >= ED_MAX_OBSERVERS) return 0;
572
+
573
+ EDStateObserverEntry* entry = (EDStateObserverEntry*)calloc(1, sizeof(EDStateObserverEntry));
574
+ if (!entry) return 0;
575
+
576
+ entry->target = state;
577
+ entry->callback = callback;
578
+ entry->context = context;
579
+
580
+ uint32_t slot = g_observer_count;
581
+ entry->next = g_observers[slot];
582
+ g_observers[slot] = entry;
583
+ g_observer_count++;
584
+
585
+ return slot;
586
+ }
587
+
588
+ static void ed_state_notify_observers(EDStateNode* state, void* old_value, void* new_value)
589
+ {
590
+ if (!state) return;
591
+
592
+ for (uint32_t i = 0; i < g_observer_count; i++) {
593
+ EDStateObserverEntry* entry = g_observers[i];
594
+ while (entry) {
595
+ if (entry->target == state && entry->callback) {
596
+ entry->callback(state, old_value, new_value);
597
+ }
598
+ entry = entry->next;
599
+ }
600
+ }
601
+ }
602
+
603
+ /* ================================================================
604
+ * State Snapshot and Restore
605
+ * ================================================================ */
606
+
607
+ typedef struct EDStateSnapshot {
608
+ void** values;
609
+ uint32_t* versions;
610
+ uint32_t count;
611
+ } EDStateSnapshot;
612
+
613
+ static EDStateSnapshot* ed_state_create_snapshot(EDStateManager* manager)
614
+ {
615
+ if (!manager) return NULL;
616
+
617
+ EDStateSnapshot* snapshot = (EDStateSnapshot*)calloc(1, sizeof(EDStateSnapshot));
618
+ if (!snapshot) return NULL;
619
+
620
+ uint32_t count = manager->active_states;
621
+ snapshot->values = (void**)calloc(count, sizeof(void*));
622
+ snapshot->versions = (uint32_t*)calloc(count, sizeof(uint32_t));
623
+ snapshot->count = count;
624
+
625
+ if (!snapshot->values || !snapshot->versions) {
626
+ free(snapshot->values);
627
+ free(snapshot->versions);
628
+ free(snapshot);
629
+ return NULL;
630
+ }
631
+
632
+ /* Capture current state */
633
+ uint32_t idx = 0;
634
+ for (uint32_t i = 0; i < ED_HOOKS_STATE_SLOTS && idx < count; i++) {
635
+ EDStateNode* state = manager->states[i];
636
+ while (state && idx < count) {
637
+ snapshot->values[idx] = state->value;
638
+ snapshot->versions[idx] = state->version;
639
+ idx++;
640
+ state = state->next;
641
+ }
642
+ }
643
+
644
+ return snapshot;
645
+ }
646
+
647
+ static void ed_state_destroy_snapshot(EDStateSnapshot* snapshot)
648
+ {
649
+ if (!snapshot) return;
650
+ free(snapshot->values);
651
+ free(snapshot->versions);
652
+ free(snapshot);
653
+ }
654
+
655
+ static bool ed_state_restore_snapshot(EDStateManager* manager, EDStateSnapshot* snapshot)
656
+ {
657
+ if (!manager || !snapshot) return false;
658
+
659
+ uint32_t idx = 0;
660
+ for (uint32_t i = 0; i < ED_HOOKS_STATE_SLOTS && idx < snapshot->count; i++) {
661
+ EDStateNode* state = manager->states[i];
662
+ while (state && idx < snapshot->count) {
663
+ state->value = snapshot->values[idx];
664
+ state->version = snapshot->versions[idx];
665
+ state->is_pending = false;
666
+ idx++;
667
+ state = state->next;
668
+ }
669
+ }
670
+
671
+ ed_log_debug("State restored from snapshot (%u states)", snapshot->count);
672
+ return true;
673
+ }
674
+
675
+ /* ================================================================
676
+ * State Manager Statistics
677
+ * ================================================================ */
678
+
679
+ typedef struct EDStateManagerStats {
680
+ uint32_t total_states;
681
+ uint32_t active_states;
682
+ uint64_t total_updates;
683
+ uint64_t batched_updates;
684
+ uint32_t active_transactions;
685
+ } EDStateManagerStats;
686
+
687
+ static EDStateManagerStats ed_state_manager_get_stats(EDStateManager* manager)
688
+ {
689
+ EDStateManagerStats stats = {0};
690
+ if (!manager) return stats;
691
+
692
+ stats.total_states = manager->total_states;
693
+ stats.active_states = manager->active_states;
694
+ stats.total_updates = manager->total_updates;
695
+ stats.batched_updates = manager->batched_updates;
696
+ stats.active_transactions = (g_active_transaction && g_active_transaction->is_active) ? 1 : 0;
697
+
698
+ return stats;
699
+ }
700
+
701
+ /* ================================================================
702
+ * State Derivation (Computed Values)
703
+ * ================================================================ */
704
+
705
+ typedef void* (*EDStateDeriver)(void** inputs, uint32_t input_count);
706
+
707
+ typedef struct EDDerivedState {
708
+ EDStateDeriver deriver;
709
+ EDStateNode** inputs;
710
+ uint32_t input_count;
711
+ EDStateNode* output;
712
+ uint32_t* cached_versions; /* Versions of inputs when last computed */
713
+ bool is_dirty;
714
+ } EDDerivedState;
715
+
716
+ static EDDerivedState* ed_derived_state_create(EDStateDeriver deriver,
717
+ EDStateNode** inputs,
718
+ uint32_t input_count)
719
+ {
720
+ if (!deriver || !inputs || input_count == 0) return NULL;
721
+
722
+ EDDerivedState* derived = (EDDerivedState*)calloc(1, sizeof(EDDerivedState));
723
+ if (!derived) return NULL;
724
+
725
+ derived->deriver = deriver;
726
+ derived->inputs = inputs;
727
+ derived->input_count = input_count;
728
+ derived->output = ed_state_create(NULL);
729
+ derived->cached_versions = (uint32_t*)calloc(input_count, sizeof(uint32_t));
730
+ derived->is_dirty = true;
731
+
732
+ if (!derived->output || !derived->cached_versions) {
733
+ if (derived->output) ed_state_destroy(derived->output);
734
+ free(derived->cached_versions);
735
+ free(derived);
736
+ return NULL;
737
+ }
738
+
739
+ /* Record initial versions */
740
+ for (uint32_t i = 0; i < input_count; i++) {
741
+ if (inputs[i]) {
742
+ derived->cached_versions[i] = inputs[i]->version;
743
+ }
744
+ }
745
+
746
+ return derived;
747
+ }
748
+
749
+ static void ed_derived_state_destroy(EDDerivedState* derived)
750
+ {
751
+ if (!derived) return;
752
+ if (derived->output) ed_state_destroy(derived->output);
753
+ free(derived->cached_versions);
754
+ free(derived);
755
+ }
756
+
757
+ static bool ed_derived_state_check_dirty(EDDerivedState* derived)
758
+ {
759
+ if (!derived) return false;
760
+
761
+ for (uint32_t i = 0; i < derived->input_count; i++) {
762
+ if (derived->inputs[i] &&
763
+ derived->inputs[i]->version != derived->cached_versions[i]) {
764
+ derived->is_dirty = true;
765
+ return true;
766
+ }
767
+ }
768
+
769
+ return derived->is_dirty;
770
+ }
771
+
772
+ static void* ed_derived_state_compute(EDDerivedState* derived)
773
+ {
774
+ if (!derived || !derived->deriver) return NULL;
775
+
776
+ if (!ed_derived_state_check_dirty(derived)) {
777
+ return derived->output->value;
778
+ }
779
+
780
+ /* Compute new value */
781
+ void** input_values = (void**)calloc(derived->input_count, sizeof(void*));
782
+ if (!input_values) return derived->output->value;
783
+
784
+ for (uint32_t i = 0; i < derived->input_count; i++) {
785
+ input_values[i] = derived->inputs[i] ? derived->inputs[i]->value : NULL;
786
+ }
787
+
788
+ void* result = derived->deriver(input_values, derived->input_count);
789
+
790
+ /* Update cached versions */
791
+ for (uint32_t i = 0; i < derived->input_count; i++) {
792
+ if (derived->inputs[i]) {
793
+ derived->cached_versions[i] = derived->inputs[i]->version;
794
+ }
795
+ }
796
+
797
+ derived->output->value = result;
798
+ derived->output->version++;
799
+ derived->is_dirty = false;
800
+
801
+ free(input_values);
802
+ return result;
803
+ }