use std::collections::{HashMap, HashSet};
use logisheets_base::{
Addr, BlockId, BlockRange, CellId, ColId, CubeId, NormalRange, Range, RangeId, RowId, SheetId,
errors::BasicError,
};
use crate::{
Error,
async_func_manager::AsyncFuncManager,
block_manager::enum_manager::executor::EnumSetExecutor,
block_manager::field_manager::executor::FieldRenderExecutor,
block_manager::schema_manager::executor::BlockSchemaExecutor,
calc_engine::CalcEngine,
cell_attachments::executor::CellAttachmentsExecutor,
chart_manager::ChartExecutor,
checkpoint_manager::CheckpointManager,
conditional_formatting_manager::executor::ConditionalFormattingExecutor,
connectors::{
BlockSchemaConnector, CalcConnector, CellAttachmentsConnector, ContainerConnector,
CubeConnector, ExclusiveConnector, FormulaConnector, NavigatorConnector, RangeConnector,
SheetInfoConnector,
},
container::ContainerExecutor,
cube_manager::executors::CubeExecutor,
edit_action::{EditPayload, PayloadsAction, SheetRename},
exclusive::executor::ExclusiveManagerExecutor,
formula_manager::{FormulaExecutor, Vertex},
image_manager::ImageExecutor,
navigator::{NavExecutor, Navigator},
range_manager::RangeExecutor,
settings::CalcConfig,
sid_assigner::ShadowIdAssigner,
version_manager::VersionManager,
workbook::sheet_info_manager::SheetInfoManager,
};
use super::status::Status;
pub struct Executor<'a> {
pub status: Status,
pub sid_assigner: &'a mut ShadowIdAssigner,
pub version_manager: &'a mut VersionManager,
pub checkpoint_manager: &'a CheckpointManager,
pub async_func_manager: &'a mut AsyncFuncManager,
pub book_name: &'a str,
pub calc_config: CalcConfig,
pub async_funcs: &'a HashSet<String>,
pub updated_cells: HashSet<(SheetId, CellId)>,
pub cells_removed: HashSet<(SheetId, CellId)>,
pub style_updated: HashSet<(SheetId, CellId)>,
pub dirty_vertices: HashSet<Vertex>,
pub row_inserted: Vec<(SheetId, RowId)>,
pub row_removed: Vec<(SheetId, RowId)>,
pub col_inserted: Vec<(SheetId, ColId)>,
pub col_removed: Vec<(SheetId, ColId)>,
pub sheet_updated: bool,
pub cell_updated: bool, pub header_updated: HashSet<SheetId>,
}
impl<'a> Executor<'a> {
pub fn execute_and_calc(self, payload_action: PayloadsAction) -> Result<Self, Error> {
let mut result = self;
let total = payload_action.payloads.len();
for (index, payload) in payload_action.payloads.iter().enumerate() {
result = result
.apply(payload)
.map_err(|e| e.at_payload(index, total, payload))?;
}
if !payload_action.init {
super::block_key_guard::check_block_key_uniqueness(
&result.status,
&result.updated_cells,
)?;
super::pivot_guard::check_pivot_field_conflicts(&result.status)?;
}
let result = result.calc()?;
if payload_action.init {
result
.version_manager
.set_init_status(result.status.clone());
} else if payload_action.undoable {
result.version_manager.record(
result.status.clone(),
payload_action,
result.updated_cells.clone(),
);
}
Ok(result)
}
fn apply(mut self, payload: &EditPayload) -> Result<Self, Error> {
if let EditPayload::RemoveBlock(rb) = payload {
if let Some(sheet_id) = self.status.sheet_info_manager.get_sheet_id(rb.sheet_idx) {
let cascade = crate::block_manager::analysis::remove_cascade(
&self.status.navigator,
sheet_id,
rb.id,
);
for analysis in cascade {
self = self.execute_payload(EditPayload::RemoveBlock(
crate::edit_action::RemoveBlock {
sheet_idx: rb.sheet_idx,
id: analysis,
},
))?;
}
}
}
self.execute_payload(payload.clone())
}
fn execute_payload(self, payload: EditPayload) -> Result<Self, Error> {
let mut result = self;
if let EditPayload::BindFormSchema(ref p) = payload {
if let Some(sheet_id) = result.status.sheet_info_manager.get_sheet_id(p.sheet_idx) {
super::rename_propagation::propagate_field_renames(
&mut result.status,
sheet_id,
p.block_id,
&p.fields,
);
}
}
if let EditPayload::RestoreCheckpoint(ref rc) = payload {
let snapshot = result
.checkpoint_manager
.get(&rc.label)
.map_err(|e| Error::Basic(e))?;
result.status = snapshot.clone();
result.cell_updated = true;
result.sheet_updated = true;
return Ok(result);
}
if let EditPayload::SheetRename(rename) = payload {
let manager = &mut result.status.sheet_id_manager;
let SheetRename {
old_name,
idx,
new_name,
} = rename;
if let Some(old_name) = old_name {
manager.rename(&old_name, new_name);
} else {
if let Some(idx) = idx {
let id = result
.status
.sheet_info_manager
.get_sheet_id(idx)
.ok_or(Error::Basic(BasicError::SheetIdxExceed(idx)))?;
let old_name = manager
.get_string(&id)
.ok_or(Error::Basic(BasicError::SheetIdNotFound(id)))?;
manager.rename(&old_name, new_name);
} else {
return Err(Error::PayloadError("".to_string()));
}
}
result.sheet_updated = true;
return Ok(result);
}
let name_vertex = match payload {
EditPayload::DefineName(p) => Some(super::defined_names::define_name(
&mut result.status,
result.book_name,
&mut *result.sid_assigner,
p,
)?),
EditPayload::RenameName(p) => {
Some(super::defined_names::rename_name(&mut result.status, p)?)
}
EditPayload::RemoveName(p) => {
Some(super::defined_names::remove_name(&mut result.status, p)?)
}
payload => {
return result.execute_pipeline(payload);
}
};
if let Some(v) = name_vertex {
result.dirty_vertices.insert(v);
result.cell_updated = true;
}
Ok(result)
}
fn execute_pipeline(self, payload: EditPayload) -> Result<Self, Error> {
let mut result = self;
if let EditPayload::DeleteSheet(ref ds) = payload {
if let Some(id) = result.status.sheet_info_manager.get_sheet_id(ds.idx) {
if let Some(name) = result.status.sheet_id_manager.get_string(&id) {
result.status.sheet_id_manager.remove_name(&name);
}
}
}
let old_navigator = result.status.navigator.clone();
let (nav_executor, nav_updated) = result.execute_navigator(payload.clone())?;
let range_executor = result.execute_range(payload.clone())?;
let cube_executor = result.execute_cube(payload.clone())?;
let (container_executor, cell_attatchment_updated) =
result.execute_container(payload.clone())?;
result.status.container = container_executor.container;
result
.cells_removed
.extend(container_executor.cells_removed);
result
.updated_cells
.extend(container_executor.value_changed);
let (exclusive, exclusive_updated) = result.execute_exclusive(payload.clone())?;
result.status.exclusive_manager = exclusive.manager;
let (cell_attachments, updated) = result.execute_cell_attachments(payload.clone())?;
result.status.cell_attachment_manager = cell_attachments.manager;
let (image_executor, image_updated) = result.execute_image(payload.clone())?;
result.status.image_manager = image_executor.manager;
let (chart_executor, chart_updated) = result.execute_chart(payload.clone())?;
result.status.chart_manager = chart_executor.manager;
let (cf_executor, cf_updated) = result.execute_conditional_formatting(payload.clone())?;
result.status.conditional_formatting_manager = cf_executor.manager;
let mut dirty_ranges = range_executor.dirty_ranges;
range_executor.removed_ranges.into_iter().for_each(|e| {
dirty_ranges.insert(e);
});
let mut dirty_cubes = cube_executor.dirty_cubes;
cube_executor.removed_cubes.into_iter().for_each(|e| {
dirty_cubes.insert(e);
});
let (block_schema_executor, _block_schema_updated) =
result.execute_bind_schema(payload.clone())?;
let dirty_blocks = block_schema_executor.dirty_blocks;
result.status.block_schema_manager = block_schema_executor.manager;
let (field_render_executor, _field_render_updated) =
result.execute_field_render(payload.clone())?;
result.status.field_render_manager = field_render_executor.manager;
let (enum_set_executor, enum_sets_updated) = result.execute_enum_sets(payload.clone())?;
result.status.enum_set_manager = enum_set_executor.manager;
let mut dirty_blocks = dirty_blocks;
if !enum_set_executor.dirty_sets.is_empty() {
dirty_blocks.extend(blocks_using_enum_sets(
&result.status,
&enum_set_executor.dirty_sets,
));
}
result.status.navigator = nav_executor.nav;
result.row_inserted.extend(nav_executor.row_inserted);
result.row_removed.extend(nav_executor.row_removed);
result.col_inserted.extend(nav_executor.col_inserted);
result.col_removed.extend(nav_executor.col_removed);
result.status.range_manager = range_executor.manager;
result.status.cube_manager = cube_executor.manager;
let formula_executor = result.execute_formula(
payload.clone(),
&old_navigator,
dirty_ranges,
dirty_blocks,
dirty_cubes,
range_executor.trigger,
)?;
for (sheet_id, cell_id) in &formula_executor.ephemeral_shadows_cleared {
result.status.container.remove_cell(*sheet_id, cell_id);
result.updated_cells.insert((*sheet_id, *cell_id));
}
let cell_updated = result.cell_updated
|| updated
|| nav_updated
|| cell_attatchment_updated
|| exclusive_updated
|| image_updated
|| chart_updated
|| cf_updated
|| enum_sets_updated
|| result.updated_cells.len() > 0
|| result.cells_removed.len() > 0;
let (sheet_pos_manager, sheet_updated_now) = result.execute_sheet_info(&payload)?;
result.status.sheet_info_manager = sheet_pos_manager;
let sheet_updated = result.sheet_updated || sheet_updated_now;
let mut header_updated = result.header_updated;
match &payload {
EditPayload::SetColWidth(p) => {
if let Some(sheet_id) = result.status.sheet_info_manager.get_sheet_id(p.sheet_idx) {
header_updated.insert(sheet_id);
}
}
EditPayload::SetRowHeight(p) => {
if let Some(sheet_id) = result.status.sheet_info_manager.get_sheet_id(p.sheet_idx) {
header_updated.insert(sheet_id);
}
}
_ => {}
}
let mut dirty_vertices = formula_executor.dirty_vertices;
dirty_vertices.extend(result.dirty_vertices);
Ok(Executor {
status: Status {
navigator: result.status.navigator,
range_manager: result.status.range_manager,
cube_manager: result.status.cube_manager,
ext_ref_manager: result.status.ext_ref_manager,
formula_manager: formula_executor.manager,
container: result.status.container,
sheet_id_manager: result.status.sheet_id_manager,
func_id_manager: result.status.func_id_manager,
text_id_manager: result.status.text_id_manager,
name_id_manager: result.status.name_id_manager,
external_links_manager: result.status.external_links_manager,
sheet_info_manager: result.status.sheet_info_manager,
style_manager: result.status.style_manager,
cell_attachment_manager: result.status.cell_attachment_manager,
dirty_cells_next_round: result.status.dirty_cells_next_round,
exclusive_manager: result.status.exclusive_manager,
block_schema_manager: result.status.block_schema_manager,
field_render_manager: result.status.field_render_manager,
enum_set_manager: result.status.enum_set_manager,
image_manager: result.status.image_manager,
chart_manager: result.status.chart_manager,
data_validation_manager: result.status.data_validation_manager,
conditional_formatting_manager: result.status.conditional_formatting_manager,
},
version_manager: result.version_manager,
async_func_manager: result.async_func_manager,
book_name: result.book_name,
calc_config: result.calc_config,
async_funcs: result.async_funcs,
dirty_vertices: dirty_vertices,
updated_cells: result.updated_cells,
cells_removed: result.cells_removed,
sheet_updated,
cell_updated,
sid_assigner: result.sid_assigner,
checkpoint_manager: result.checkpoint_manager,
style_updated: result.style_updated,
row_inserted: result.row_inserted,
row_removed: result.row_removed,
col_inserted: result.col_inserted,
col_removed: result.col_removed,
header_updated,
})
}
pub fn calc(self) -> Result<Self, Error> {
let mut dirty_cells_in_next_run = imbl::HashSet::new();
let mut calc_cells: HashSet<(SheetId, CellId)> = HashSet::new();
let Executor {
mut status,
sid_assigner,
checkpoint_manager,
version_manager,
mut async_func_manager,
book_name,
calc_config,
async_funcs,
mut updated_cells,
cells_removed,
style_updated,
dirty_vertices,
sheet_updated,
cell_updated,
row_inserted,
row_removed,
col_inserted,
col_removed,
header_updated,
} = self;
let mut dirty_vertices = dirty_vertices;
for (sheet_id, cell_id) in std::mem::take(&mut status.dirty_cells_next_round) {
let range = match cell_id {
CellId::NormalCell(c) => Range::Normal(NormalRange::Single(c)),
CellId::BlockCell(b) => Range::Block(BlockRange::Single(b)),
CellId::EphemeralCell(e) => Range::Ephemeral(e),
};
let range_id = status.range_manager.get_range_id(&sheet_id, &range);
dirty_vertices.insert(Vertex::Range(sheet_id, range_id));
}
let connector = CalcConnector {
range_manager: &status.range_manager,
cube_manager: &status.cube_manager,
navigator: &mut status.navigator,
container: &mut status.container,
ext_links: &mut status.external_links_manager,
text_id_manager: &mut status.text_id_manager,
func_id_manager: &mut status.func_id_manager,
sheet_id_manager: &status.sheet_id_manager,
names_storage: HashMap::new(),
cells_storage: HashMap::new(),
sheet_pos_manager: &mut status.sheet_info_manager,
async_func_manager: &mut async_func_manager,
async_funcs: &async_funcs,
active_sheet: 0,
curr_addr: Addr::default(),
dirty_cells_in_next_run: &mut dirty_cells_in_next_run,
calc_cells: &mut calc_cells,
block_schema_manager: &status.block_schema_manager,
formula_manager: &status.formula_manager,
name_id_manager: &status.name_id_manager,
ext_ref_manager: &status.ext_ref_manager,
};
let engine = CalcEngine {
formula_manager: &status.formula_manager,
dirty_vertices,
config: self.calc_config,
connector,
};
engine.start();
updated_cells.extend(calc_cells);
status.dirty_cells_next_round = dirty_cells_in_next_run.into_iter().collect();
Ok(Executor {
status,
sid_assigner,
checkpoint_manager,
version_manager,
async_func_manager,
book_name,
calc_config,
async_funcs,
updated_cells,
cells_removed,
style_updated,
dirty_vertices: HashSet::new(),
sheet_updated,
cell_updated,
row_inserted,
row_removed,
col_inserted,
col_removed,
header_updated,
})
}
fn execute_range(&mut self, payload: EditPayload) -> Result<RangeExecutor, Error> {
let ctx = RangeConnector {
sheet_id_manager: &mut self.status.sheet_id_manager,
text_id_manager: &mut self.status.text_id_manager,
func_id_manager: &mut self.status.func_id_manager,
name_id_manager: &mut self.status.name_id_manager,
external_links_manager: &mut self.status.external_links_manager,
navigator: &self.status.navigator,
sheet_pos_manager: &self.status.sheet_info_manager,
};
let executor = RangeExecutor::new(self.status.range_manager.clone());
executor.execute(&ctx, payload)
}
fn execute_bind_schema(
&mut self,
payload: EditPayload,
) -> Result<(BlockSchemaExecutor, bool), Error> {
let mut ctx = BlockSchemaConnector {
id_navigator: &self.status.navigator,
sheet_info_manager: &mut self.status.sheet_info_manager,
sheet_id_manager: &mut self.status.sheet_id_manager,
};
let executor = BlockSchemaExecutor::new(self.status.block_schema_manager.clone());
executor.execute(&mut ctx, payload)
}
fn execute_field_render(
&mut self,
payload: EditPayload,
) -> Result<(FieldRenderExecutor, bool), Error> {
let mut ctx = crate::connectors::FieldRenderConnector {
style_manager: &mut self.status.style_manager,
};
let executor = FieldRenderExecutor::new(self.status.field_render_manager.clone());
executor.execute(&mut ctx, payload)
}
fn execute_enum_sets(
&mut self,
payload: EditPayload,
) -> Result<(EnumSetExecutor, bool), Error> {
let executor = EnumSetExecutor::new(self.status.enum_set_manager.clone());
executor.execute(payload)
}
fn execute_cube(&mut self, payload: EditPayload) -> Result<CubeExecutor, Error> {
let ctx = CubeConnector {
sheet_id_manager: &mut self.status.sheet_id_manager,
text_id_manager: &mut self.status.text_id_manager,
func_id_manager: &mut self.status.func_id_manager,
name_id_manager: &mut self.status.name_id_manager,
external_links_manager: &mut self.status.external_links_manager,
navigator: &self.status.navigator,
sheet_pos_manager: &self.status.sheet_info_manager,
};
let executor = CubeExecutor::new(self.status.cube_manager.clone());
executor.execute(&ctx, payload)
}
fn execute_navigator(&mut self, payload: EditPayload) -> Result<(NavExecutor, bool), Error> {
let mut ctx = NavigatorConnector {
sheet_pos_manager: &self.status.sheet_info_manager,
sheet_id_manager: &mut self.status.sheet_id_manager,
};
let executor = NavExecutor::new(self.status.navigator.clone());
executor.execute(&mut ctx, payload)
}
fn execute_cell_attachments(
&mut self,
payload: EditPayload,
) -> Result<(CellAttachmentsExecutor, bool), Error> {
let mut ctx = CellAttachmentsConnector {
sheet_pos_manager: &self.status.sheet_info_manager,
navigator: &self.status.navigator,
sheet_id_manager: &mut self.status.sheet_id_manager,
name_id_manager: &mut self.status.name_id_manager,
external_links_manager: &mut self.status.external_links_manager,
func_id_manager: &mut self.status.func_id_manager,
text_id_manager: &mut self.status.text_id_manager,
};
let executor = CellAttachmentsExecutor::new(self.status.cell_attachment_manager.clone());
executor.execute(&mut ctx, payload)
}
fn execute_image(&mut self, payload: EditPayload) -> Result<(ImageExecutor, bool), Error> {
let mut ctx = CellAttachmentsConnector {
sheet_pos_manager: &self.status.sheet_info_manager,
navigator: &self.status.navigator,
sheet_id_manager: &mut self.status.sheet_id_manager,
name_id_manager: &mut self.status.name_id_manager,
external_links_manager: &mut self.status.external_links_manager,
func_id_manager: &mut self.status.func_id_manager,
text_id_manager: &mut self.status.text_id_manager,
};
let executor = ImageExecutor::new(self.status.image_manager.clone());
executor.execute(&mut ctx, payload)
}
fn execute_conditional_formatting(
&mut self,
payload: EditPayload,
) -> Result<(ConditionalFormattingExecutor, bool), Error> {
let executor =
ConditionalFormattingExecutor::new(self.status.conditional_formatting_manager.clone());
executor.execute(
&self.status.navigator,
&self.status.sheet_info_manager,
&mut self.status.style_manager.dxf_manager,
payload,
)
}
fn execute_chart(&mut self, payload: EditPayload) -> Result<(ChartExecutor, bool), Error> {
let block_refs = self.resolve_chart_block_source(&payload);
let mut ctx = CellAttachmentsConnector {
sheet_pos_manager: &self.status.sheet_info_manager,
navigator: &self.status.navigator,
sheet_id_manager: &mut self.status.sheet_id_manager,
name_id_manager: &mut self.status.name_id_manager,
external_links_manager: &mut self.status.external_links_manager,
func_id_manager: &mut self.status.func_id_manager,
text_id_manager: &mut self.status.text_id_manager,
};
let executor = ChartExecutor::new(self.status.chart_manager.clone());
let (mut executor, changed) = executor.execute(&mut ctx, payload.clone(), block_refs)?;
self.attach_chart_refs(&mut executor, &payload);
Ok((executor, changed))
}
fn attach_chart_refs(&self, executor: &mut ChartExecutor, payload: &EditPayload) {
let (sheet_idx, chart_id) = match payload {
EditPayload::CreateChart(p) => (p.sheet_idx, &p.chart_id),
EditPayload::UpdateChart(p) => (p.sheet_idx, &p.chart_id),
_ => return,
};
let Some(sheet_id) = self.status.sheet_info_manager.get_sheet_id(sheet_idx) else {
return;
};
let Some(data) = executor
.manager
.charts_of_sheet(sheet_id)
.find(|c| &c.id == chart_id)
.map(|c| c.data.clone())
else {
return;
};
let refs = crate::chart_manager::ChartRefs::from_data(
&self.status.navigator,
&self.status.sheet_id_manager,
sheet_id,
&data,
);
executor.manager.set_refs(sheet_id, chart_id, refs);
}
fn resolve_chart_block_source(
&self,
payload: &EditPayload,
) -> Option<crate::chart_manager::ResolvedBlockRefs> {
let (sheet_idx, source) = match payload {
EditPayload::CreateChart(p) => (p.sheet_idx, p.block_source.as_ref()?),
EditPayload::UpdateChart(p) => (p.sheet_idx, p.block_source.as_ref()?),
_ => return None,
};
let sheet_id = self.status.sheet_info_manager.get_sheet_id(sheet_idx)?;
let sheet_name = self.status.sheet_id_manager.get_string(&sheet_id)?;
crate::chart_manager::resolve_block_refs(
&self.status.navigator,
&self.status.block_schema_manager,
sheet_id,
&sheet_name,
&crate::chart_manager::ChartBlockSource {
block_id: source.block_id,
category_field: source.category_field.clone(),
value_fields: source.value_fields.clone(),
},
)
}
fn execute_container(
&mut self,
payload: EditPayload,
) -> Result<(ContainerExecutor, bool), Error> {
let mut ctx = ContainerConnector {
sheet_id_manager: &mut self.status.sheet_id_manager,
text_id_manager: &mut self.status.text_id_manager,
func_id_manager: &mut self.status.func_id_manager,
name_id_manager: &mut self.status.name_id_manager,
external_links_manager: &mut self.status.external_links_manager,
navigator: &self.status.navigator,
sheet_pos_manager: &self.status.sheet_info_manager,
style_manager: &mut self.status.style_manager,
block_schema_manager: &self.status.block_schema_manager,
};
let executor = ContainerExecutor::new(self.status.container.clone());
executor.execute(&mut ctx, payload)
}
fn execute_exclusive(
&mut self,
payload: EditPayload,
) -> Result<(ExclusiveManagerExecutor, bool), Error> {
let mut ctx = ExclusiveConnector {
sheet_id_manager: &mut self.status.sheet_id_manager,
text_id_manager: &mut self.status.text_id_manager,
func_id_manager: &mut self.status.func_id_manager,
name_id_manager: &mut self.status.name_id_manager,
external_links_manager: &mut self.status.external_links_manager,
navigator: &self.status.navigator,
sheet_pos_manager: &self.status.sheet_info_manager,
style_manager: &mut self.status.style_manager,
block_schema_manager: &self.status.block_schema_manager,
};
let executor = ExclusiveManagerExecutor::new(self.status.exclusive_manager.clone());
executor.execute(&mut ctx, payload)
}
fn execute_sheet_info(
&mut self,
payload: &EditPayload,
) -> Result<(SheetInfoManager, bool), Error> {
let mut ctx = SheetInfoConnector {
sheet_id_manager: &mut self.status.sheet_id_manager,
text_id_manager: &mut self.status.text_id_manager,
func_id_manager: &mut self.status.func_id_manager,
name_id_manager: &mut self.status.name_id_manager,
external_links_manager: &mut self.status.external_links_manager,
navigator: &self.status.navigator,
updated: false,
};
let new_manager = self
.status
.sheet_info_manager
.clone()
.execute(payload, &mut ctx)?;
Ok((new_manager, ctx.updated))
}
fn execute_formula(
&mut self,
payload: EditPayload,
old_navigator: &Navigator,
dirty_ranges: HashSet<(SheetId, RangeId)>,
dirty_blocks: HashSet<(SheetId, BlockId)>,
dirty_cubes: HashSet<CubeId>,
trigger: Option<(SheetId, RangeId)>,
) -> Result<FormulaExecutor, Error> {
let mut ctx = FormulaConnector {
book_name: self.book_name,
sheet_pos_manager: &mut self.status.sheet_info_manager,
sheet_id_manager: &mut self.status.sheet_id_manager,
text_id_manager: &mut self.status.text_id_manager,
func_id_manager: &mut self.status.func_id_manager,
range_manager: &mut self.status.range_manager,
cube_manager: &mut self.status.cube_manager,
ext_ref_manager: &mut self.status.ext_ref_manager,
name_id_manager: &mut self.status.name_id_manager,
id_navigator: &mut self.status.navigator,
idx_navigator: old_navigator,
external_links_manager: &mut self.status.external_links_manager,
block_schema_manager: &self.status.block_schema_manager,
enum_set_manager: &self.status.enum_set_manager,
container: &self.status.container,
sid_assigner: &mut *self.sid_assigner,
};
let executor = FormulaExecutor {
manager: self.status.formula_manager.clone(),
dirty_vertices: HashSet::new(),
dirty_ranges,
dirty_blocks,
dirty_cubes,
trigger,
ephemeral_shadows_cleared: HashSet::new(),
};
executor.execute(payload, &mut ctx)
}
}
fn blocks_using_enum_sets(status: &Status, sets: &[String]) -> Vec<(SheetId, BlockId)> {
use crate::block_manager::schema_manager::schema::Schema;
let mut out = Vec::new();
for ((sheet_id, block_id), schema) in status.block_schema_manager.schemas.iter() {
let fields = match schema {
Schema::RowSchema(s) => &s.fields,
Schema::ColSchema(s) => &s.fields,
Schema::RandomSchema(_) => continue,
};
let uses = fields.iter().any(|(_, e)| {
e.field_type
.enum_set_id()
.is_some_and(|id| sets.iter().any(|s| s == id))
});
if uses {
out.push((*sheet_id, *block_id));
}
}
out
}