🙃
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
backend/target
|
|
||||||
1
backend/.gitignore
vendored
Normal file
1
backend/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
@@ -20,6 +20,7 @@ pub enum LeadErrCode {
|
|||||||
Server,
|
Server,
|
||||||
Unsupported,
|
Unsupported,
|
||||||
Invalid,
|
Invalid,
|
||||||
|
Ref,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use log::info;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cell::{Cell, CellRef},
|
cell::{Cell, CellRef},
|
||||||
common::Literal,
|
common::{LeadErr, LeadErrCode, Literal},
|
||||||
evaluator::{Eval, evaluate},
|
evaluator::{Eval, evaluate},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ impl Grid {
|
|||||||
|
|
||||||
if self.cells.contains_key(&cell_ref) {
|
if self.cells.contains_key(&cell_ref) {
|
||||||
updated_cells = self
|
updated_cells = self
|
||||||
.update_exisiting_cell(raw_val, eval, precs, cell_ref)?
|
.update_exisiting_cell(raw_val, eval, precs, cell_ref)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(updated_cells)
|
.chain(updated_cells)
|
||||||
.collect();
|
.collect();
|
||||||
@@ -85,39 +85,22 @@ impl Grid {
|
|||||||
// This is a topological order on the precedents graph
|
// This is a topological order on the precedents graph
|
||||||
// i.e. if a requires b (e.g. a = 1 + b) then a -> b
|
// i.e. if a requires b (e.g. a = 1 + b) then a -> b
|
||||||
// so a comes before b in the topo order
|
// so a comes before b in the topo order
|
||||||
fn topo_order(&self, from: CellRef) -> Result<Vec<CellRef>, String> {
|
fn topo_order(&self, from: CellRef) -> (Vec<CellRef>, bool) {
|
||||||
let mut res: Vec<CellRef> = Vec::new();
|
let mut res = Vec::new();
|
||||||
let mut search_set = Vec::new();
|
|
||||||
let mut temp = HashSet::new();
|
let mut temp = HashSet::new();
|
||||||
let mut perm = HashSet::new();
|
let mut perm = HashSet::new();
|
||||||
|
let mut cycle_detected = false;
|
||||||
|
|
||||||
search_set.push(from);
|
self.topo_visit(
|
||||||
|
from,
|
||||||
|
&mut temp,
|
||||||
|
&mut perm,
|
||||||
|
&mut res,
|
||||||
|
&mut cycle_detected,
|
||||||
|
from,
|
||||||
|
);
|
||||||
|
|
||||||
let cell_data = &self.cells[&from];
|
(res, cycle_detected)
|
||||||
search_set.extend(cell_data.deps().iter());
|
|
||||||
|
|
||||||
temp.insert(from);
|
|
||||||
perm.insert(from); // Make this inside the inner topo_visit
|
|
||||||
|
|
||||||
let mut searched = 1;
|
|
||||||
|
|
||||||
while searched != search_set.len() {
|
|
||||||
if perm.contains(&search_set[searched]) {
|
|
||||||
searched += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.topo_visit(
|
|
||||||
search_set[searched],
|
|
||||||
&mut temp,
|
|
||||||
&mut perm,
|
|
||||||
&mut search_set,
|
|
||||||
&mut res,
|
|
||||||
)?;
|
|
||||||
searched += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn topo_visit(
|
fn topo_visit(
|
||||||
@@ -125,38 +108,38 @@ impl Grid {
|
|||||||
cell: CellRef,
|
cell: CellRef,
|
||||||
temp: &mut HashSet<CellRef>,
|
temp: &mut HashSet<CellRef>,
|
||||||
perm: &mut HashSet<CellRef>,
|
perm: &mut HashSet<CellRef>,
|
||||||
search_set: &mut Vec<CellRef>,
|
|
||||||
res: &mut Vec<CellRef>,
|
res: &mut Vec<CellRef>,
|
||||||
) -> Result<(), String> {
|
cycle_detected: &mut bool,
|
||||||
|
caller: CellRef,
|
||||||
|
) {
|
||||||
if perm.contains(&cell) {
|
if perm.contains(&cell) {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
|
||||||
if temp.contains(&cell) {
|
|
||||||
return Err("Evalutation error: Cycle detected in cell refs.".into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
temp.insert(cell);
|
if !temp.insert(cell) {
|
||||||
|
*cycle_detected = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if !self.cells.contains_key(&cell) {
|
if !self.cells.contains_key(&cell) {
|
||||||
perm.insert(cell);
|
perm.insert(cell);
|
||||||
res.push(cell);
|
res.push(cell);
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cell_data = &self.cells[&cell];
|
// Walk dependencies if this cell exists; otherwise treat as leaf/external ref.
|
||||||
|
if let Some(cell_data) = self.cells.get(&cell) {
|
||||||
search_set.extend(cell_data.deps().iter());
|
for &dep in cell_data.deps().iter() {
|
||||||
// search_set.extend(cell_data.precedents.iter().cloned());
|
self.topo_visit(dep, temp, perm, res, cycle_detected, caller);
|
||||||
|
}
|
||||||
for prec in cell_data.precs().iter() {
|
|
||||||
self.topo_visit(*prec, temp, perm, search_set, res)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Done exploring this node
|
||||||
|
temp.remove(&cell);
|
||||||
perm.insert(cell);
|
perm.insert(cell);
|
||||||
|
if cell != caller {
|
||||||
res.push(cell);
|
res.push(cell);
|
||||||
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_exisiting_cell(
|
fn update_exisiting_cell(
|
||||||
@@ -165,13 +148,13 @@ impl Grid {
|
|||||||
new_eval: Eval,
|
new_eval: Eval,
|
||||||
new_precs: HashSet<CellRef>,
|
new_precs: HashSet<CellRef>,
|
||||||
cell_ref: CellRef,
|
cell_ref: CellRef,
|
||||||
) -> Result<Vec<CellRef>, String> {
|
) -> Vec<CellRef> {
|
||||||
let (old_precs, old_eval) = match self.cells.get_mut(&cell_ref) {
|
let (old_precs, old_eval) = match self.cells.get_mut(&cell_ref) {
|
||||||
Some(cell) => {
|
Some(cell) => {
|
||||||
cell.set_raw(raw);
|
cell.set_raw(raw);
|
||||||
(cell.precs().clone(), cell.eval().clone())
|
(cell.precs().clone(), cell.eval().clone())
|
||||||
}
|
}
|
||||||
None => return Ok(Vec::new()),
|
None => return Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// diffs (outside any borrow)
|
// diffs (outside any borrow)
|
||||||
@@ -204,12 +187,24 @@ impl Grid {
|
|||||||
|
|
||||||
let cell = self.cells.get_mut(&cell_ref).unwrap(); // Should be impossible to crash
|
let cell = self.cells.get_mut(&cell_ref).unwrap(); // Should be impossible to crash
|
||||||
cell.set_precs(new_precs);
|
cell.set_precs(new_precs);
|
||||||
cell.set_eval(new_eval);
|
|
||||||
|
|
||||||
if eval_changed {
|
if eval_changed {
|
||||||
self.propagate(cell_ref)
|
cell.set_eval(new_eval);
|
||||||
|
match self.propagate(cell_ref) {
|
||||||
|
Ok(affected_cells) => affected_cells,
|
||||||
|
Err(affected_cells) => {
|
||||||
|
let cell = self.cells.get_mut(&cell_ref).unwrap();
|
||||||
|
cell.set_eval(Eval::Err(LeadErr {
|
||||||
|
title: "Propagation error.".into(),
|
||||||
|
desc: "Circular dependencies detected.".into(),
|
||||||
|
code: LeadErrCode::Ref,
|
||||||
|
}));
|
||||||
|
|
||||||
|
affected_cells
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Vec::new())
|
Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,32 +234,41 @@ impl Grid {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn propagate(&mut self, from: CellRef) -> Result<Vec<CellRef>, String> {
|
fn propagate(&mut self, from: CellRef) -> Result<Vec<CellRef>, Vec<CellRef>> {
|
||||||
let mut res = Vec::new();
|
let (topo, cycle_detected) = self.topo_order(from);
|
||||||
let topo = self.topo_order(from)?;
|
|
||||||
|
|
||||||
for cell_ref in topo {
|
if !cycle_detected {
|
||||||
res.push(cell_ref);
|
for cell_ref in topo.to_owned() {
|
||||||
|
let raw = if let Some(cell) = self.cells.get(&cell_ref) {
|
||||||
let raw = if let Some(cell) = self.cells.get(&cell_ref) {
|
let s = cell.raw();
|
||||||
let s = cell.raw();
|
if let Some(rest) = s.strip_prefix('=') {
|
||||||
if let Some(rest) = s.strip_prefix('=') {
|
rest.to_owned()
|
||||||
rest.to_owned()
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let (e, _) = evaluate(raw, Some(self));
|
||||||
|
|
||||||
|
if let Some(cell) = self.cells.get_mut(&cell_ref) {
|
||||||
|
cell.set_eval(e);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Now we dropped the borrow of self.cells before this point
|
|
||||||
let (e, _) = evaluate(raw, Some(self));
|
|
||||||
|
|
||||||
if let Some(cell) = self.cells.get_mut(&cell_ref) {
|
|
||||||
cell.set_eval(e);
|
|
||||||
}
|
}
|
||||||
|
Ok(topo)
|
||||||
|
} else {
|
||||||
|
let err = LeadErr {
|
||||||
|
title: "Propagation error.".into(),
|
||||||
|
desc: "Circular dependencies detected.".into(),
|
||||||
|
code: LeadErrCode::Ref,
|
||||||
|
};
|
||||||
|
topo.iter().for_each(|cell_ref| {
|
||||||
|
if let Some(cell) = self.cells.get_mut(&cell_ref) {
|
||||||
|
cell.set_eval(Eval::Err(err.to_owned()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Err(topo)
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,18 +51,18 @@
|
|||||||
</Sidebar.GroupLabel>
|
</Sidebar.GroupLabel>
|
||||||
<Sidebar.GroupContent>
|
<Sidebar.GroupContent>
|
||||||
<Sidebar.Menu>
|
<Sidebar.Menu>
|
||||||
{#each items as item (item.title)}
|
<!-- {#each items as item (item.title)} -->
|
||||||
<Sidebar.MenuItem>
|
<!-- <Sidebar.MenuItem> -->
|
||||||
<Sidebar.MenuButton>
|
<!-- <Sidebar.MenuButton> -->
|
||||||
{#snippet child({ props })}
|
<!-- {#snippet child({ props })} -->
|
||||||
<a href={item.url} {...props}>
|
<!-- <a href={item.url} {...props}> -->
|
||||||
<item.icon />
|
<!-- <item.icon /> -->
|
||||||
<span>{item.title}</span>
|
<!-- <span>{item.title}</span> -->
|
||||||
</a>
|
<!-- </a> -->
|
||||||
{/snippet}
|
<!-- {/snippet} -->
|
||||||
</Sidebar.MenuButton>
|
<!-- </Sidebar.MenuButton> -->
|
||||||
</Sidebar.MenuItem>
|
<!-- </Sidebar.MenuItem> -->
|
||||||
{/each}
|
<!-- {/each} -->
|
||||||
</Sidebar.Menu>
|
</Sidebar.Menu>
|
||||||
</Sidebar.GroupContent>
|
</Sidebar.GroupContent>
|
||||||
</Sidebar.Group>
|
</Sidebar.Group>
|
||||||
|
|||||||
Reference in New Issue
Block a user