gridline_engine/engine/
cell.rs1use dashmap::DashMap;
2use serde::{Deserialize, Serialize};
3
4use super::cell_ref::CellRef;
5use super::deps::extract_dependencies;
6
7#[derive(Clone, Debug, Serialize, Deserialize)]
9pub enum CellType {
10 Empty,
11 Text(String),
12 Number(f64),
13 Script(String),
14}
15
16#[derive(Clone, Debug, Serialize, Deserialize)]
18pub struct Cell {
19 pub contents: CellType,
20 pub depends_on: Vec<CellRef>,
21 pub dirty: bool,
22 #[serde(skip)]
24 pub cached_value: Option<String>,
25}
26
27impl Cell {
28 pub fn new_empty() -> Cell {
29 Cell {
30 contents: CellType::Empty,
31 depends_on: vec![],
32 dirty: false,
33 cached_value: None,
34 }
35 }
36
37 pub fn new_text(text: &str) -> Cell {
38 Cell {
39 contents: CellType::Text(text.to_string()),
40 depends_on: vec![],
41 dirty: false,
42 cached_value: None,
43 }
44 }
45
46 pub fn new_number(n: f64) -> Cell {
47 Cell {
48 contents: CellType::Number(n),
49 depends_on: vec![],
50 dirty: false,
51 cached_value: None,
52 }
53 }
54
55 pub fn new_script(script: &str) -> Cell {
58 Cell {
59 depends_on: extract_dependencies(script),
60 contents: CellType::Script(script.to_string()),
61 dirty: true,
62 cached_value: None,
63 }
64 }
65
66 pub fn from_input(input: &str) -> Cell {
73 let trimmed = input.trim();
74 if trimmed.is_empty() {
75 return Cell::new_empty();
76 }
77
78 if let Some(formula) = trimmed.strip_prefix('=') {
79 return Cell::new_script(formula);
80 }
81
82 if trimmed.starts_with('"') && trimmed.ends_with('"') && trimmed.len() >= 2 {
83 let text = &trimmed[1..trimmed.len() - 1];
84 return Cell::new_text(text);
85 }
86
87 if let Ok(n) = trimmed.parse::<f64>() {
88 return Cell::new_number(n);
89 }
90
91 Cell::new_text(trimmed)
92 }
93
94 pub fn to_input_string(&self) -> String {
96 match &self.contents {
97 CellType::Empty => String::new(),
98 CellType::Text(s) => s.clone(),
99 CellType::Number(n) => n.to_string(),
100 CellType::Script(s) => format!("={}", s),
101 }
102 }
103}
104
105pub type Grid = DashMap<CellRef, Cell>;