use crate::SheetId;
use crate::engine::graph::DependencyGraph;
use crate::engine::named_range::NameScope;
use crate::engine::vertex::{VertexId, VertexKind};
use formualizer_common::{ExcelError, ExcelErrorKind};
#[derive(Debug, Clone)]
pub struct SourceScalarEntry {
pub name: String,
pub vertex: VertexId,
pub version: Option<u64>,
}
#[derive(Debug, Clone)]
pub struct SourceTableEntry {
pub name: String,
pub vertex: VertexId,
pub version: Option<u64>,
}
impl DependencyGraph {
fn allocate_source_vertex(&mut self) -> VertexId {
let scope_sheet_id: SheetId = self.default_sheet_id;
self.allocate_symbol_vertex(VertexKind::External, scope_sheet_id)
}
pub fn resolve_source_scalar_entry(&self, name: &str) -> Option<&SourceScalarEntry> {
self.source_scalars.get(name)
}
pub fn resolve_source_table_entry(&self, name: &str) -> Option<&SourceTableEntry> {
self.source_tables.get(name)
}
pub fn define_source_scalar(
&mut self,
name: &str,
version: Option<u64>,
) -> Result<(), ExcelError> {
if name.is_empty() {
return Err(ExcelError::new(ExcelErrorKind::Name)
.with_message("Source name cannot be empty".to_string()));
}
if self.source_scalars.contains_key(name) || self.source_tables.contains_key(name) {
return Err(ExcelError::new(ExcelErrorKind::Name)
.with_message(format!("Source already defined: {name}")));
}
let vertex = self.allocate_source_vertex();
self.source_vertex_lookup.insert(vertex, name.to_string());
self.mark_volatile(vertex, version.is_none());
let entry = SourceScalarEntry {
name: name.to_string(),
vertex,
version,
};
self.source_scalars.insert(name.to_string(), entry);
self.resolve_pending_name_references(NameScope::Workbook, name);
self.bump_symbol_revision();
Ok(())
}
pub fn define_source_table(
&mut self,
name: &str,
version: Option<u64>,
) -> Result<(), ExcelError> {
if name.is_empty() {
return Err(ExcelError::new(ExcelErrorKind::Name)
.with_message("Source name cannot be empty".to_string()));
}
if self.source_tables.contains_key(name) || self.source_scalars.contains_key(name) {
return Err(ExcelError::new(ExcelErrorKind::Name)
.with_message(format!("Source already defined: {name}")));
}
let vertex = self.allocate_source_vertex();
self.source_vertex_lookup.insert(vertex, name.to_string());
self.mark_volatile(vertex, version.is_none());
let entry = SourceTableEntry {
name: name.to_string(),
vertex,
version,
};
self.source_tables.insert(name.to_string(), entry);
self.bump_symbol_revision();
Ok(())
}
pub fn set_source_scalar_version(
&mut self,
name: &str,
version: Option<u64>,
) -> Result<(), ExcelError> {
let vertex = {
let entry = self.source_scalars.get_mut(name).ok_or_else(|| {
ExcelError::new(ExcelErrorKind::Name)
.with_message(format!("Unknown source: {name}"))
})?;
if entry.version == version {
return Ok(());
}
entry.version = version;
entry.vertex
};
self.mark_volatile(vertex, version.is_none());
self.mark_dirty(vertex);
Ok(())
}
pub fn set_source_table_version(
&mut self,
name: &str,
version: Option<u64>,
) -> Result<(), ExcelError> {
let vertex = {
let entry = self.source_tables.get_mut(name).ok_or_else(|| {
ExcelError::new(ExcelErrorKind::Name)
.with_message(format!("Unknown source: {name}"))
})?;
if entry.version == version {
return Ok(());
}
entry.version = version;
entry.vertex
};
self.mark_volatile(vertex, version.is_none());
self.mark_dirty(vertex);
Ok(())
}
pub fn invalidate_source(&mut self, name: &str) -> Result<(), ExcelError> {
if let Some(s) = self.source_scalars.get(name) {
self.mark_dirty(s.vertex);
return Ok(());
}
if let Some(t) = self.source_tables.get(name) {
self.mark_dirty(t.vertex);
return Ok(());
}
Err(ExcelError::new(ExcelErrorKind::Name).with_message(format!("Unknown source: {name}")))
}
}