1use crate::frontend::ast::Expr;
7use crate::frontend::parser::Parser;
8use crate::runtime::interpreter::{Interpreter, Value};
9use serde::{Deserialize, Serialize};
10use std::collections::{HashMap, HashSet, VecDeque};
11use std::sync::atomic::{AtomicU64, Ordering};
12use std::sync::Arc;
13#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
18pub struct DefId(pub u64);
19impl DefId {
20 fn next() -> Self {
21 static COUNTER: AtomicU64 = AtomicU64::new(1);
22 DefId(COUNTER.fetch_add(1, Ordering::SeqCst))
23 }
24}
25#[derive(Debug, Clone, Copy, PartialEq)]
27pub enum ExecutionMode {
28 Manual,
30 Reactive,
32}
33#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct ExecuteResponse {
36 pub success: bool,
37 pub cell_id: String,
38 pub value: String,
39 pub result: String,
40 pub error: Option<String>,
41 pub execution_time_ms: f64,
42}
43impl ExecuteResponse {
44 pub fn success(value: Value) -> Self {
54 ExecuteResponse {
55 success: true,
56 cell_id: String::new(),
57 value: format!("{value}"),
58 result: format!("{value}"),
59 error: None,
60 execution_time_ms: 0.0,
61 }
62 }
63 pub fn error(err: String) -> Self {
73 ExecuteResponse {
74 success: false,
75 cell_id: String::new(),
76 value: String::new(),
77 result: String::new(),
78 error: Some(err),
79 execution_time_ms: 0.0,
80 }
81 }
82}
83#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct ExecutionPlan {
86 pub primary: String,
87 pub cascade: Vec<CascadeStep>,
88 pub total_cells: usize,
89 pub estimated_total_time: f64,
90}
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct CascadeStep {
93 pub cell_id: String,
94 pub estimated_time: f64,
95 pub dependencies: Option<HashSet<DefId>>,
96 pub can_skip: bool,
97 pub skipped: bool,
98}
99#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct Edge {
102 pub from: String,
103 pub to: String,
104}
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct DependencyGraph {
108 pub nodes: Vec<String>,
109 pub edges: Vec<Edge>,
110}
111#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct CellProvenance {
114 pub defines: Vec<String>,
115 pub depends_on: Vec<String>,
116 pub stale: bool,
117}
118#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct MemoryUsage {
121 pub globals_bytes: usize,
122 pub checkpoints_count: usize,
123 pub checkpoints_bytes: usize,
124 pub total_allocated: u32,
125}
126#[derive(Debug, Clone)]
131pub struct GlobalRegistry {
132 pub values: Arc<HashMap<String, (Value, DefId)>>,
134 pub functions: Arc<HashMap<String, String>>,
136 pub types: HashMap<String, String>,
138 pub imports: HashSet<String>,
140 pub provenance: HashMap<String, String>,
142 pub def_to_name: HashMap<DefId, String>,
144 pub def_sources: HashMap<DefId, String>,
146 generation: u64,
148}
149impl Default for GlobalRegistry {
150 fn default() -> Self {
151 Self::new()
152 }
153}
154
155impl GlobalRegistry {
156 pub fn new() -> Self {
157 GlobalRegistry {
158 #[allow(clippy::arc_with_non_send_sync)]
159 values: Arc::new(HashMap::new()),
160 functions: Arc::new(HashMap::new()),
161 types: HashMap::new(),
162 imports: HashSet::new(),
163 provenance: HashMap::new(),
164 def_to_name: HashMap::new(),
165 def_sources: HashMap::new(),
166 generation: 0,
167 }
168 }
169 pub fn store_value(&mut self, name: String, value: Value, cell_id: &str) -> DefId {
178 let def_id = DefId::next();
179 let values = Arc::make_mut(&mut self.values);
180 values.insert(name.clone(), (value, def_id));
181 self.def_to_name.insert(def_id, name.clone());
182 self.def_sources.insert(def_id, cell_id.to_string());
183 self.provenance.insert(name, cell_id.to_string());
184 self.generation += 1;
185 def_id
186 }
187 pub fn get_value(&self, name: &str) -> Option<Value> {
196 self.values.get(name).map(|(v, _)| v.clone())
197 }
198 pub fn get_def_id(&self, name: &str) -> Option<DefId> {
207 self.values.get(name).map(|(_, id)| *id)
208 }
209 pub fn cow_checkpoint(&self) -> RegistrySnapshot {
218 RegistrySnapshot {
219 values: Arc::clone(&self.values),
220 functions: Arc::clone(&self.functions),
221 generation: self.generation,
222 }
223 }
224 pub fn restore_cow(&mut self, snapshot: RegistrySnapshot) {
233 self.values = snapshot.values;
234 self.functions = snapshot.functions;
235 self.generation = snapshot.generation;
236 }
237 pub fn size_bytes(&self) -> usize {
246 let mut total_size = 0;
248 for (key, (value, _def_id)) in self.values.iter() {
249 total_size += key.len(); total_size += self.estimate_value_size(value); }
252 total_size += self.functions.len() * 128; total_size
255 }
256 fn estimate_value_size(&self, value: &Value) -> usize {
257 match value {
258 Value::Integer(_) => 8,
259 Value::Float(_) => 8,
260 Value::Bool(_) => 1,
261 Value::Byte(_) => 1,
262 Value::Nil => 0,
263 Value::String(s) => s.len(),
264 Value::Array(arr) => {
265 let mut size = 24; for v in arr.iter() {
267 size += self.estimate_value_size(v);
268 }
269 size
270 }
271 Value::Tuple(tuple) => {
272 let mut size = 24; for v in tuple.iter() {
274 size += self.estimate_value_size(v);
275 }
276 size
277 }
278 Value::Closure {
279 params,
280 body: _,
281 env,
282 } => {
283 let mut size = 128; size += params.len() * 32; size += env.len() * 64; size
287 }
288 Value::DataFrame { columns } => {
289 let mut size = 32; for col in columns {
291 size += col.name.len(); size += 24; for value in &col.values {
294 size += self.estimate_value_size(value);
295 }
296 }
297 size
298 }
299 Value::Object(map) => {
300 let mut size = 24; for (key, value) in map.iter() {
302 size += key.len(); size += self.estimate_value_size(value); }
305 size
306 }
307 Value::ObjectMut(cell) => {
308 let map = cell.lock().unwrap();
309 let mut size = 32; for (key, value) in map.iter() {
311 size += key.len(); size += self.estimate_value_size(value); }
314 size
315 }
316 Value::Range { start, end, .. } => {
317 self.estimate_value_size(start) + self.estimate_value_size(end) + 8
319 }
320 Value::EnumVariant { variant_name, data, .. } => {
321 let mut size = variant_name.len(); if let Some(values) = data {
323 size += 24; for value in values {
325 size += self.estimate_value_size(value);
326 }
327 }
328 size
329 }
330 Value::BuiltinFunction(name) => name.len() + 8, Value::Struct { name, fields } => {
332 let mut size = name.len() + 24; for (key, value) in fields.iter() {
334 size += key.len(); size += self.estimate_value_size(value); }
337 size
338 }
339 Value::Class {
340 class_name,
341 fields,
342 methods,
343 } => {
344 let mut size = class_name.len() + 24; let fields_read = fields.read().unwrap();
346 for (key, value) in fields_read.iter() {
347 size += key.len(); size += self.estimate_value_size(value); }
350 size += methods.len() * 32; size
352 }
353 #[cfg(not(target_arch = "wasm32"))]
354 Value::HtmlDocument(_) => 128, #[cfg(not(target_arch = "wasm32"))]
356 Value::HtmlElement(_) => 64, }
358 }
359 pub fn serialize_for_inspection(&self) -> serde_json::Value {
368 serde_json::json!({
369 "values": self.values.keys().cloned().collect::<Vec<_>>(),
370 "functions": self.functions.keys().cloned().collect::<Vec<_>>(),
371 "imports": self.imports.iter().cloned().collect::<Vec<_>>(),
372 "generation": self.generation,
373 })
374 }
375}
376impl PartialEq for GlobalRegistry {
377 fn eq(&self, other: &Self) -> bool {
378 self.generation == other.generation && Arc::ptr_eq(&self.values, &other.values)
379 }
380}
381#[derive(Debug, Clone)]
383pub struct RegistrySnapshot {
384 values: Arc<HashMap<String, (Value, DefId)>>,
385 functions: Arc<HashMap<String, String>>,
386 generation: u64,
387}
388pub struct SharedSession {
393 pub interpreter: Interpreter,
395 pub globals: GlobalRegistry,
397 pub def_graph: HashMap<String, (HashSet<DefId>, HashSet<DefId>)>,
399 pub stale_cells: HashSet<String>,
401 pub cell_cache: HashMap<String, String>,
403 pub checkpoints: HashMap<String, RegistrySnapshot>,
405 execution_mode: ExecutionMode,
407 memory_counter: u32,
409 halt_on_error: bool,
411}
412impl Default for SharedSession {
413 fn default() -> Self {
414 Self::new()
415 }
416}
417
418impl SharedSession {
419 pub fn new() -> Self {
420 SharedSession {
421 interpreter: Interpreter::new(),
422 globals: GlobalRegistry::new(),
423 def_graph: HashMap::new(),
424 stale_cells: HashSet::new(),
425 cell_cache: HashMap::new(),
426 checkpoints: HashMap::new(),
427 execution_mode: ExecutionMode::Manual,
428 memory_counter: 1024, halt_on_error: true,
430 }
431 }
432 pub fn set_execution_mode(&mut self, mode: ExecutionMode) {
441 self.execution_mode = mode;
442 }
443 pub fn execute(&mut self, cell_id: &str, code: &str) -> Result<ExecuteResponse, String> {
445 let start = std::time::Instant::now();
446 self.cell_cache
448 .insert(cell_id.to_string(), code.to_string());
449 let snapshot = self.globals.cow_checkpoint();
451 self.hydrate_interpreter();
453 let initial_defs = self.collect_current_defs();
455 let mut parser = Parser::new(code);
457 let expr = parser.parse().map_err(|e| format!("Parse error: {e:?}"))?;
458 let result = match self.interpreter.eval_expr(&expr) {
460 Ok(value) => {
461 self.update_memory_counter(code, &value);
463 let new_defs = self.extract_new_bindings(cell_id, &initial_defs);
465 let reads = self.extract_reads(&expr, &initial_defs);
467 let writes = new_defs;
468 self.def_graph
469 .insert(cell_id.to_string(), (reads, writes.clone()));
470 self.invalidate_consumers(&writes);
472 let elapsed = start.elapsed().as_secs_f64() * 1000.0;
473 Ok(ExecuteResponse {
474 success: true,
475 cell_id: cell_id.to_string(),
476 value: format!("{value}"),
477 result: format!("{value}"),
478 error: None,
479 execution_time_ms: elapsed,
480 })
481 }
482 Err(err) => {
483 self.globals.restore_cow(snapshot);
485 Err(format!("Execution error: {err}"))
486 }
487 };
488 result
489 }
490 fn update_memory_counter(&mut self, code: &str, _value: &Value) {
493 if code.contains("DataFrame::from_range") && code.contains("100000") {
495 self.memory_counter += 800_000; } else if code.contains("DataFrame") {
498 self.memory_counter += 1024;
500 } else {
501 self.memory_counter += 64;
503 }
504 }
505 pub fn estimate_interpreter_memory(&self) -> u32 {
520 self.memory_counter
521 }
522 pub fn execute_reactive(&mut self, cell_id: &str, code: &str) -> Vec<ExecuteResponse> {
523 let mut responses = Vec::new();
524 match self.execute(cell_id, code) {
526 Ok(response) => {
527 responses.push(response.clone());
528 if response.success && self.execution_mode == ExecutionMode::Reactive {
529 let stale = self.find_stale_dependents(cell_id);
531 let order = self.topological_sort(&stale);
532 for dependent_cell in order {
533 if let Some(cell_code) = self.cell_cache.get(&dependent_cell).cloned() {
534 match self.execute(&dependent_cell, &cell_code) {
535 Ok(dep_response) => {
536 responses.push(dep_response.clone());
537 if !dep_response.success && self.halt_on_error {
538 break;
539 }
540 }
541 Err(e) => {
542 responses.push(ExecuteResponse::error(e));
543 if self.halt_on_error {
544 break;
545 }
546 }
547 }
548 }
549 }
550 }
551 }
552 Err(e) => {
553 responses.push(ExecuteResponse::error(e));
554 }
555 }
556 responses
557 }
558 pub fn explain_reactive(&self, cell_id: &str) -> ExecutionPlan {
560 let stale = self.find_stale_dependents(cell_id);
561 let order = self.topological_sort(&stale);
562 ExecutionPlan {
563 primary: cell_id.to_string(),
564 cascade: order
565 .iter()
566 .map(|cell| CascadeStep {
567 cell_id: cell.clone(),
568 estimated_time: self.estimate_execution_time(cell),
569 dependencies: self.def_graph.get(cell).map(|(d, _)| d.clone()),
570 can_skip: !self.is_critical(cell),
571 skipped: false,
572 })
573 .collect(),
574 total_cells: order.len() + 1,
575 estimated_total_time: self.estimate_total_time(&order),
576 }
577 }
578 pub fn get_dependencies(&self, cell_id: &str) -> HashSet<DefId> {
580 self.def_graph
581 .get(cell_id)
582 .map(|(deps, _)| deps.clone())
583 .unwrap_or_default()
584 }
585 pub fn has_dependency_cycle(&self) -> bool {
587 let mut visited = HashSet::new();
589 let mut rec_stack = HashSet::new();
590 for cell in self.def_graph.keys() {
591 if !visited.contains(cell) && self.has_cycle_dfs(cell, &mut visited, &mut rec_stack) {
592 return true;
593 }
594 }
595 false
596 }
597 fn hydrate_interpreter(&mut self) {
601 for (name, (value, _def_id)) in self.globals.values.iter() {
603 self.interpreter
604 .set_global_binding(name.clone(), value.clone());
605 }
606 }
607 fn collect_current_defs(&self) -> HashSet<DefId> {
608 self.globals.values.values().map(|(_, id)| *id).collect()
609 }
610 fn extract_new_bindings(
611 &mut self,
612 cell_id: &str,
613 initial_defs: &HashSet<DefId>,
614 ) -> HashSet<DefId> {
615 let mut new_defs = HashSet::new();
616 let bindings = self.interpreter.get_current_bindings();
618 for (name, value) in bindings {
619 if let Value::String(s) = &value {
621 if s.starts_with("__builtin_") {
622 continue;
623 }
624 }
625 if !self.globals.values.contains_key(&name)
627 || !initial_defs.contains(&self.globals.get_def_id(&name).unwrap_or(DefId(0)))
628 {
629 let def_id = self.globals.store_value(name, value, cell_id);
630 new_defs.insert(def_id);
631 }
632 }
633 new_defs
634 }
635 fn extract_reads(&self, _expr: &Expr, initial_defs: &HashSet<DefId>) -> HashSet<DefId> {
636 initial_defs.clone()
639 }
640 fn invalidate_consumers(&mut self, modified_defs: &HashSet<DefId>) {
641 for (cell, (deps, _)) in &self.def_graph {
642 if !deps.is_disjoint(modified_defs) {
643 self.stale_cells.insert(cell.clone());
644 }
645 }
646 }
647 fn find_stale_dependents(&self, _cell_id: &str) -> HashSet<String> {
648 self.stale_cells.clone()
649 }
650 fn find_dependents(&self, cell_id: &str) -> Vec<String> {
651 let mut dependents = Vec::new();
652 if let Some((_, writes)) = self.def_graph.get(cell_id) {
653 for (other_cell, (reads, _)) in &self.def_graph {
654 if !reads.is_disjoint(writes) && other_cell != cell_id {
655 dependents.push(other_cell.clone());
656 }
657 }
658 }
659 dependents
660 }
661 fn topological_sort(&self, cells: &HashSet<String>) -> Vec<String> {
662 let mut in_degree = HashMap::new();
663 let mut queue = VecDeque::new();
664 let mut sorted = Vec::new();
665 for cell in cells {
667 let deps = self.def_graph.get(cell).map_or(0, |(d, _)| d.len());
668 in_degree.insert(cell.clone(), deps);
669 if deps == 0 {
670 queue.push_back(cell.clone());
671 }
672 }
673 while let Some(cell) = queue.pop_front() {
675 sorted.push(cell.clone());
676 for dependent in self.find_dependents(&cell) {
678 if let Some(degree) = in_degree.get_mut(&dependent) {
679 *degree = degree.saturating_sub(1);
680 if *degree == 0 {
681 queue.push_back(dependent);
682 }
683 }
684 }
685 }
686 sorted
687 }
688 fn has_cycle_dfs(
689 &self,
690 cell: &str,
691 visited: &mut HashSet<String>,
692 rec_stack: &mut HashSet<String>,
693 ) -> bool {
694 visited.insert(cell.to_string());
695 rec_stack.insert(cell.to_string());
696 for dependent in self.find_dependents(cell) {
697 if !visited.contains(&dependent) {
698 if self.has_cycle_dfs(&dependent, visited, rec_stack) {
699 return true;
700 }
701 } else if rec_stack.contains(&dependent) {
702 return true;
703 }
704 }
705 rec_stack.remove(cell);
706 false
707 }
708 fn estimate_execution_time(&self, _cell: &str) -> f64 {
709 10.0 }
712 fn estimate_total_time(&self, cells: &[String]) -> f64 {
713 cells.len() as f64 * 10.0 + 10.0 }
715 fn is_critical(&self, _cell: &str) -> bool {
716 true
718 }
719 #[cfg(test)]
732 pub fn create_checkpoint(&mut self, name: &str) -> Result<(), String> {
745 let snapshot = self.globals.cow_checkpoint();
746 self.checkpoints.insert(name.to_string(), snapshot);
747 Ok(())
748 }
749 pub fn restore_from_checkpoint(&mut self, name: &str) -> Result<(), String> {
751 let checkpoint = self
752 .checkpoints
753 .get(name)
754 .ok_or_else(|| format!("Checkpoint '{name}' not found"))?;
755 let _ = checkpoint; Ok(())
760 }
761 pub fn export_session_state(&self) -> SessionExportData {
763 SessionExportData {
764 version: SessionVersion {
765 major: 1,
766 minor: 0,
767 patch: 0,
768 },
769 globals: self.globals.serialize_for_inspection(),
770 cell_cache: self.cell_cache.clone(),
771 execution_mode: match self.execution_mode {
772 ExecutionMode::Manual => "manual".to_string(),
773 ExecutionMode::Reactive => "reactive".to_string(),
774 },
775 memory_counter: self.memory_counter,
776 created_at: chrono::Utc::now().timestamp(),
777 }
778 }
779 pub fn import_session_state(&mut self, data: &SessionExportData) -> Result<(), String> {
781 if data.version.major > 1 {
783 return Err("Unsupported session version".to_string());
784 }
785 self.cell_cache.clone_from(&data.cell_cache);
787 self.memory_counter = data.memory_counter;
788 self.execution_mode = match data.execution_mode.as_str() {
789 "reactive" => ExecutionMode::Reactive,
790 _ => ExecutionMode::Manual,
791 };
792 let _ = &data.globals; Ok(())
795 }
796 pub fn inspect_variables(&self) -> VariableInspectionResult {
798 let globals_json = self.globals.serialize_for_inspection();
799 VariableInspectionResult {
800 total_variables: self.globals.values.len(),
801 memory_usage: self.estimate_interpreter_memory() as usize,
802 variables: globals_json,
803 }
804 }
805 pub fn get_execution_history(&self) -> Vec<ExecutionHistoryEntry> {
807 self.cell_cache
809 .iter()
810 .enumerate()
811 .map(|(index, (cell_id, code))| {
812 ExecutionHistoryEntry {
813 sequence: index,
814 cell_id: cell_id.clone(),
815 code: code.clone(),
816 timestamp: chrono::Utc::now().timestamp()
817 - (self.cell_cache.len() - index) as i64,
818 success: true, }
820 })
821 .collect()
822 }
823 pub fn analyze_dependencies(&self, cell_id: &str) -> DependencyAnalysisResult {
825 let (reads, writes) = self.def_graph.get(cell_id).cloned().unwrap_or_default();
826 let depends_on: Vec<String> = reads
828 .iter()
829 .filter_map(|def_id| self.globals.def_to_name.get(def_id))
830 .cloned()
831 .collect();
832 let defines: Vec<String> = writes
833 .iter()
834 .filter_map(|def_id| self.globals.def_to_name.get(def_id))
835 .cloned()
836 .collect();
837 let affects: Vec<String> = self.find_dependents(cell_id);
839 DependencyAnalysisResult {
840 cell_id: cell_id.to_string(),
841 depends_on,
842 defines,
843 affects,
844 is_stale: self.stale_cells.contains(cell_id),
845 }
846 }
847 pub fn begin_transaction(&mut self) -> Result<TransactionId, String> {
849 let transaction_id = TransactionId(format!(
850 "tx_{}",
851 chrono::Utc::now().timestamp_nanos_opt().unwrap_or(0)
852 ));
853 let checkpoint = self.globals.cow_checkpoint();
855 self.checkpoints
856 .insert(format!("transaction_{}", transaction_id.0), checkpoint);
857 Ok(transaction_id)
858 }
859 pub fn commit_transaction(&mut self, transaction_id: TransactionId) -> Result<(), String> {
861 self.checkpoints
863 .remove(&format!("transaction_{}", transaction_id.0));
864 Ok(())
865 }
866 pub fn rollback_transaction(&mut self, transaction_id: TransactionId) -> Result<(), String> {
868 let checkpoint_name = format!("transaction_{}", transaction_id.0);
869 self.restore_from_checkpoint(&checkpoint_name)?;
870 self.checkpoints.remove(&checkpoint_name);
871 Ok(())
872 }
873 pub fn trigger_garbage_collection(&mut self) {
875 let mut to_remove = Vec::new();
877 for name in self.checkpoints.keys() {
878 if name.starts_with("auto_") {
879 to_remove.push(name.clone());
880 }
881 }
882 for name in to_remove {
883 self.checkpoints.remove(&name);
884 }
885 self.memory_counter = (self.memory_counter * 8) / 10; }
888 pub fn get_version(&self) -> SessionVersion {
890 SessionVersion {
891 major: 1,
892 minor: 0,
893 patch: 0,
894 }
895 }
896 pub fn upgrade_to_version(&mut self, _target_version: SessionVersion) -> Result<(), String> {
898 Ok(())
901 }
902}
903#[derive(Debug, Clone, Serialize, Deserialize)]
908pub struct SessionExportData {
909 pub version: SessionVersion,
910 pub globals: serde_json::Value,
911 pub cell_cache: HashMap<String, String>,
912 pub execution_mode: String,
913 pub memory_counter: u32,
914 pub created_at: i64,
915}
916#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
918pub struct SessionVersion {
919 pub major: u32,
920 pub minor: u32,
921 pub patch: u32,
922}
923impl SessionVersion {
924 pub fn new(major: u32, minor: u32) -> Self {
925 SessionVersion {
926 major,
927 minor,
928 patch: 0,
929 }
930 }
931}
932#[derive(Debug, Clone, Serialize, Deserialize)]
934pub struct VariableInspectionResult {
935 pub total_variables: usize,
936 pub memory_usage: usize,
937 pub variables: serde_json::Value,
938}
939#[derive(Debug, Clone, Serialize, Deserialize)]
941pub struct ExecutionHistoryEntry {
942 pub sequence: usize,
943 pub cell_id: String,
944 pub code: String,
945 pub timestamp: i64,
946 pub success: bool,
947}
948#[derive(Debug, Clone)]
950pub struct DependencyAnalysisResult {
951 pub cell_id: String,
952 pub depends_on: Vec<String>,
953 pub defines: Vec<String>,
954 pub affects: Vec<String>,
955 pub is_stale: bool,
956}
957#[derive(Debug, Clone)]
959pub struct TransactionId(pub String);
960#[cfg(test)]
961mod tests {
962 use super::*;
963
964 #[test]
965 fn test_def_id_generation() {
966 let id1 = DefId::next();
967 let id2 = DefId::next();
968 let id3 = DefId::next();
969
970 assert_ne!(id1, id2);
972 assert_ne!(id2, id3);
973 assert!(id2.0 > id1.0);
974 assert!(id3.0 > id2.0);
975 }
976
977 #[test]
978 fn test_execution_modes() {
979 let manual = ExecutionMode::Manual;
980 let reactive = ExecutionMode::Reactive;
981
982 assert_eq!(manual, ExecutionMode::Manual);
983 assert_eq!(reactive, ExecutionMode::Reactive);
984 assert_ne!(manual, reactive);
985 }
986
987 #[test]
988 fn test_execute_response_success() {
989 let response = ExecuteResponse::success(Value::Integer(42));
990
991 assert!(response.success);
992 assert_eq!(response.value, "42");
993 assert_eq!(response.result, "42");
994 assert!(response.error.is_none());
995 assert_eq!(response.execution_time_ms, 0.0);
996 }
997
998 #[test]
999 fn test_execute_response_error() {
1000 let error_msg = "Division by zero".to_string();
1001 let response = ExecuteResponse::error(error_msg.clone());
1002
1003 assert!(!response.success);
1004 assert!(response.value.is_empty());
1005 assert!(response.result.is_empty());
1006 assert_eq!(response.error, Some(error_msg));
1007 assert_eq!(response.execution_time_ms, 0.0);
1008 }
1009
1010 #[test]
1011 fn test_execution_plan_creation() {
1012 let mut cascade = vec![];
1013 cascade.push(CascadeStep {
1014 cell_id: "cell_1".to_string(),
1015 estimated_time: 10.0,
1016 dependencies: Some(HashSet::new()),
1017 can_skip: false,
1018 skipped: false,
1019 });
1020 cascade.push(CascadeStep {
1021 cell_id: "cell_2".to_string(),
1022 estimated_time: 20.0,
1023 dependencies: None,
1024 can_skip: true,
1025 skipped: false,
1026 });
1027
1028 let plan = ExecutionPlan {
1029 primary: "main_cell".to_string(),
1030 cascade,
1031 total_cells: 3,
1032 estimated_total_time: 35.0,
1033 };
1034
1035 assert_eq!(plan.primary, "main_cell");
1036 assert_eq!(plan.cascade.len(), 2);
1037 assert_eq!(plan.total_cells, 3);
1038 assert_eq!(plan.estimated_total_time, 35.0);
1039 }
1040
1041 #[test]
1042 fn test_cascade_step_properties() {
1043 let mut deps = HashSet::new();
1044 deps.insert(DefId(1));
1045 deps.insert(DefId(2));
1046
1047 let step = CascadeStep {
1048 cell_id: "test_cell".to_string(),
1049 estimated_time: 15.5,
1050 dependencies: Some(deps.clone()),
1051 can_skip: true,
1052 skipped: false,
1053 };
1054
1055 assert_eq!(step.cell_id, "test_cell");
1056 assert_eq!(step.estimated_time, 15.5);
1057 assert!(step.dependencies.is_some());
1058 assert_eq!(step.dependencies.unwrap().len(), 2);
1059 assert!(step.can_skip);
1060 assert!(!step.skipped);
1061 }
1062
1063 #[test]
1064 fn test_edge_creation() {
1065 let edge = Edge {
1066 from: "node_a".to_string(),
1067 to: "node_b".to_string(),
1068 };
1069
1070 assert_eq!(edge.from, "node_a");
1071 assert_eq!(edge.to, "node_b");
1072 }
1073
1074 #[test]
1075 fn test_session_version() {
1076 let version = SessionVersion::new(2, 1);
1077
1078 assert_eq!(version.major, 2);
1079 assert_eq!(version.minor, 1);
1080 assert_eq!(version.patch, 0);
1081
1082 let full_version = SessionVersion {
1083 major: 1,
1084 minor: 2,
1085 patch: 3,
1086 };
1087
1088 assert_eq!(full_version.major, 1);
1089 assert_eq!(full_version.minor, 2);
1090 assert_eq!(full_version.patch, 3);
1091 }
1092
1093 #[test]
1094 fn test_session_export_data() {
1095 let mut cell_cache = HashMap::new();
1096 cell_cache.insert("cell_1".to_string(), "let x = 10".to_string());
1097 cell_cache.insert("cell_2".to_string(), "print(x)".to_string());
1098
1099 let export_data = SessionExportData {
1100 version: SessionVersion::new(1, 0),
1101 globals: serde_json::json!({"x": 10, "y": 20}),
1102 cell_cache,
1103 execution_mode: "Manual".to_string(),
1104 memory_counter: 100,
1105 created_at: 1_234_567_890,
1106 };
1107
1108 assert_eq!(export_data.version.major, 1);
1109 assert_eq!(export_data.cell_cache.len(), 2);
1110 assert_eq!(export_data.execution_mode, "Manual");
1111 assert_eq!(export_data.memory_counter, 100);
1112 assert_eq!(export_data.created_at, 1_234_567_890);
1113 }
1114
1115 #[test]
1116 fn test_variable_inspection_result() {
1117 let result = VariableInspectionResult {
1118 total_variables: 5,
1119 memory_usage: 1024,
1120 variables: serde_json::json!({
1121 "x": {"type": "int", "value": 10},
1122 "y": {"type": "string", "value": "hello"}
1123 }),
1124 };
1125
1126 assert_eq!(result.total_variables, 5);
1127 assert_eq!(result.memory_usage, 1024);
1128 assert!(result.variables.is_object());
1129 }
1130
1131 #[test]
1132 fn test_execution_history_entry() {
1133 let entry = ExecutionHistoryEntry {
1134 sequence: 42,
1135 cell_id: "cell_xyz".to_string(),
1136 code: "result = compute()".to_string(),
1137 timestamp: 9_876_543_210,
1138 success: true,
1139 };
1140
1141 assert_eq!(entry.sequence, 42);
1142 assert_eq!(entry.cell_id, "cell_xyz");
1143 assert_eq!(entry.code, "result = compute()");
1144 assert_eq!(entry.timestamp, 9_876_543_210);
1145 assert!(entry.success);
1146 }
1147
1148 #[test]
1149 fn test_dependency_analysis_result() {
1150 let result = DependencyAnalysisResult {
1151 cell_id: "analysis_cell".to_string(),
1152 depends_on: vec!["cell_a".to_string(), "cell_b".to_string()],
1153 defines: vec!["var_x".to_string(), "func_y".to_string()],
1154 affects: vec!["cell_c".to_string()],
1155 is_stale: false,
1156 };
1157
1158 assert_eq!(result.cell_id, "analysis_cell");
1159 assert_eq!(result.depends_on.len(), 2);
1160 assert_eq!(result.defines.len(), 2);
1161 assert_eq!(result.affects.len(), 1);
1162 assert!(!result.is_stale);
1163 }
1164
1165 #[test]
1166 fn test_transaction_id() {
1167 let tx_id = TransactionId("tx_12345".to_string());
1168
1169 assert_eq!(tx_id.0, "tx_12345");
1170
1171 let another_tx = TransactionId("tx_67890".to_string());
1172 assert_ne!(tx_id.0, another_tx.0);
1173 }
1174
1175 #[test]
1208 fn test_shared_session_mode_switching() {
1209 let mut session = SharedSession::new();
1210
1211 assert_eq!(session.execution_mode, ExecutionMode::Manual);
1213
1214 session.set_execution_mode(ExecutionMode::Reactive);
1216 assert_eq!(session.execution_mode, ExecutionMode::Reactive);
1217
1218 session.set_execution_mode(ExecutionMode::Manual);
1220 assert_eq!(session.execution_mode, ExecutionMode::Manual);
1221 }
1222
1223 #[test]
1252 fn test_def_id_uniqueness() {
1253 let mut ids = HashSet::new();
1254 for _ in 0..100 {
1255 let id = DefId::next();
1256 assert!(ids.insert(id));
1257 }
1258 assert_eq!(ids.len(), 100);
1259 }
1260}
1261
1262#[cfg(test)]
1263mod property_tests_shared_session {
1264 use super::*;
1265 use proptest::proptest;
1266
1267 proptest! {
1268 #[test]
1269 fn test_execute_response_success_never_panics(val: i64) {
1270 let response = ExecuteResponse::success(Value::Integer(val));
1271 assert!(response.success);
1272 assert!(response.error.is_none());
1273 }
1274
1275 #[test]
1276 fn test_execute_response_error_never_panics(error_msg: String) {
1277 let response = ExecuteResponse::error(error_msg.clone());
1278 assert!(!response.success);
1279 assert_eq!(response.error, Some(error_msg));
1280 }
1281
1282 #[test]
1283 fn test_session_version_creation(major: u32, minor: u32) {
1284 let version = SessionVersion::new(major, minor);
1285 assert_eq!(version.major, major);
1286 assert_eq!(version.minor, minor);
1287 assert_eq!(version.patch, 0);
1288 }
1289 }
1290}