spreadsheet_kit/core/
recalc.rs1#[cfg(feature = "recalc")]
2use crate::core::types::RecalculateOutcome;
3use anyhow::Result;
4#[cfg(feature = "recalc")]
5use anyhow::anyhow;
6#[cfg(not(feature = "recalc"))]
7use anyhow::bail;
8#[cfg(feature = "recalc")]
9use std::path::Path;
10#[cfg(feature = "recalc")]
11use std::sync::Arc;
12
13#[cfg(feature = "recalc")]
14pub async fn execute_with_backend(
15 path: &Path,
16 timeout_ms: Option<u64>,
17 backend: Arc<dyn crate::recalc::RecalcBackend>,
18) -> Result<RecalculateOutcome> {
19 let result = backend.recalculate(path, timeout_ms).await?;
20 Ok(RecalculateOutcome {
21 backend: result.backend_name.to_string(),
22 duration_ms: result.duration_ms,
23 cells_evaluated: result.cells_evaluated,
24 eval_errors: result.eval_errors,
25 })
26}
27
28#[cfg(feature = "recalc")]
29pub fn select_backend_from_env() -> Result<Arc<dyn crate::recalc::RecalcBackend>> {
30 use crate::config::RecalcBackendKind;
31 use crate::recalc::RecalcBackend;
32
33 #[cfg(feature = "recalc-formualizer")]
34 let formualizer: Option<Arc<dyn RecalcBackend>> =
35 Some(Arc::new(crate::recalc::FormualizerBackend));
36 #[cfg(not(feature = "recalc-formualizer"))]
37 let formualizer: Option<Arc<dyn RecalcBackend>> = None;
38
39 #[cfg(feature = "recalc-libreoffice")]
40 let libreoffice: Option<Arc<dyn RecalcBackend>> = {
41 let backend: Arc<dyn RecalcBackend> = Arc::new(crate::recalc::LibreOfficeBackend::new(
42 crate::recalc::RecalcConfig::default(),
43 ));
44 if backend.is_available() {
45 Some(backend)
46 } else {
47 None
48 }
49 };
50 #[cfg(not(feature = "recalc-libreoffice"))]
51 let libreoffice: Option<Arc<dyn RecalcBackend>> = None;
52
53 let requested = std::env::var("SPREADSHEET_MCP_RECALC_BACKEND")
54 .ok()
55 .and_then(|value| parse_recalc_backend_kind(&value))
56 .unwrap_or(RecalcBackendKind::Auto);
57
58 let selected = match requested {
59 RecalcBackendKind::Formualizer => formualizer,
60 RecalcBackendKind::Libreoffice => libreoffice,
61 RecalcBackendKind::Auto => formualizer.or(libreoffice),
62 };
63
64 selected.ok_or_else(|| {
65 anyhow!(
66 "no recalc backend available for this build/runtime; requested {:?}",
67 requested
68 )
69 })
70}
71
72#[cfg(feature = "recalc")]
73fn parse_recalc_backend_kind(value: &str) -> Option<crate::config::RecalcBackendKind> {
74 use crate::config::RecalcBackendKind;
75
76 match value.to_ascii_lowercase().as_str() {
77 "auto" => Some(RecalcBackendKind::Auto),
78 "formualizer" => Some(RecalcBackendKind::Formualizer),
79 "libreoffice" => Some(RecalcBackendKind::Libreoffice),
80 _ => None,
81 }
82}
83
84#[cfg(not(feature = "recalc"))]
85pub fn unavailable() -> Result<()> {
86 bail!(
87 "recalculate is not available in this build; rebuild with a recalc feature (e.g. --features recalc-formualizer)"
88 )
89}