visi-core 0.2.19

Embeddable spreadsheet engine: Excel formula compilation and evaluation, dependency-tracked recalculation, and .xlsx import/export
Documentation
use crate::core::RefType;
use serde::{Deserialize, Serialize};

/// Which part of an Excel Table a structured reference selects, as in
/// `Sales[#Headers]`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SheetSection {
    /// The body rows, excluding header and totals (default)
    Data,
    /// The header row.
    Headers,
    /// The totals row.
    Totals,
    /// Header, data and totals together.
    All,
}

/// One piece of a compiled formula
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum FormulaPart {
    /// A literal stretch of the formula -- operators, function names,
    /// constants -- copied through unchanged.
    Text(String),
    /// A single cell, as in `Sheet2!$A1`.
    SheetReference {
        /// Sheet the cell is on.
        sheet_id: u64,
        /// Row, 0-based.
        row: usize,
        /// Column, 0-based.
        col: usize,
        /// Whether the row was written with a `$`.
        row_ref_type: RefType,
        /// Whether the column was written with a `$`.
        col_ref_type: RefType,
    },
    /// A whole column, held by column id so a column rename survives.
    ColumnReference {
        /// Sheet the column is on.
        sheet_id: u64,
        /// The column's identifier, not its position.
        col_id: u64,
    },
    /// An Excel Table structured reference, as in `Sales[Amount]` or
    /// `[@Amount]`.
    StructuredReference {
        /// Sheet the reference resolves against.
        sheet_id: u64,
        /// The referenced column, or `None` for a whole-table reference.
        col_id: Option<u64>,
        /// `true` for the `[@Amount]` form, which means the current row.
        is_this_row: bool,
        /// Which part of the table is selected.
        section: SheetSection,
    },
    /// A rectangular range, as in `Sheet2!A1:$B$10`.
    RangeReference {
        /// Sheet the range is on.
        sheet_id: u64,
        /// First row, 0-based.
        start_row: usize,
        /// First column, 0-based.
        start_col: usize,
        /// Last row, 0-based and inclusive.
        end_row: usize,
        /// Last column, 0-based and inclusive.
        end_col: usize,
        /// Whether the start row was written with a `$`.
        start_row_ref_type: RefType,
        /// Whether the start column was written with a `$`.
        start_col_ref_type: RefType,
        /// Whether the end row was written with a `$`.
        end_row_ref_type: RefType,
        /// Whether the end column was written with a `$`.
        end_col_ref_type: RefType,
    },
}

/// A formula split into literal text and id-held references
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CompiledFormula {
    /// The pieces, in the order they appear in the formula text.
    pub parts: Vec<FormulaPart>,
}

impl CompiledFormula {
    /// Creates a plain formula from a raw string, without any parsed references.
    pub fn plain(text: String) -> Self {
        Self {
            parts: vec![FormulaPart::Text(text)],
        }
    }
}

impl Default for CompiledFormula {
    fn default() -> Self {
        Self::plain(String::new())
    }
}