Skip to main content

sheets_diff/
lib.rs

1//! # sheets-diff
2//!
3//! Structured diff engine for Microsoft Excel `.xlsx` workbooks.
4//!
5//! ## Quick start
6//!
7//! ```rust,no_run
8//! use sheets_diff::compare_paths;
9//!
10//! let diff = compare_paths("old.xlsx", "new.xlsx")?;
11//! println!("changed cells: {}", diff.summary.cells_changed);
12//! # Ok::<(), sheets_diff::SheetsDiffError>(())
13//! ```
14//!
15//! ## Input sources
16//!
17//! | Function | When to use |
18//! |---|---|
19//! | [`compare_paths`] | Simplest; caller provides file paths |
20//! | [`compare_bytes`] | You already have the bytes (e.g. from a cache or repo) |
21//! | [`compare_readers`] | You have open `Read + Seek` handles |
22//! | `compare_*_with_options` variants | Any of the above plus [`DiffOptions`] |
23//!
24//! See [`DiffOptions`] / [`DiffOptionsBuilder`] for all configuration knobs.
25
26// ---------------------------------------------------------------------------
27// Internal modules (not pub)
28// ---------------------------------------------------------------------------
29
30pub mod address;
31mod compare;
32mod diff;
33mod error;
34mod matcher;
35mod normalize;
36mod open;
37
38// ---------------------------------------------------------------------------
39// Public modules
40// ---------------------------------------------------------------------------
41
42/// Typed result model (`WorkbookDiff`, `SheetDiff`, `CellDiff`, `CellValue`, …).
43pub mod model;
44
45/// Comparison options and builder (`DiffOptions`, `DiffOptionsBuilder`, …).
46pub mod options;
47
48/// Output formatters (text summary, unified diff).
49pub mod output;
50
51// ---------------------------------------------------------------------------
52// Re-exports — the stable public API surface (RFC-002, RFC-031)
53// ---------------------------------------------------------------------------
54
55// Error types
56pub use error::{LimitKind, OpenErrorKind, ReadErrorKind, SheetsDiffError};
57
58// Model
59pub use model::{
60    AlignmentSummary,
61    CellChangeKind,
62    CellDateTime,
63    CellDiff,
64    CellDuration,
65    CellError,
66    CellValue,
67    DateTimeKind,
68    DiagnosticKind,
69    DiagnosticLocation,
70    DiagnosticSummary,
71    Diagnostic,
72    DiffStage,
73    DiffSummary,
74    FormatChange,
75    FormulaChange,
76    FormulaText,
77    MatchConfidence,
78    Severity,
79    SheetChange,
80    SheetDiff,
81    SheetMatchReason,
82    SheetRef,
83    SheetSummary,
84    Side,
85    SourceDescription,
86    SourceKind,
87    ValueChange,
88    ValueDifferenceKind,
89    WorkbookChange,
90    WorkbookDiff,
91    WorkbookObjectChange,
92    WorkbookSideInfo,
93};
94
95// Address
96pub use address::{CellAddress, ComparedRange, MAX_COL, MAX_COL_LABEL, MAX_ROW};
97
98// Options
99pub use options::{
100    AlignmentMode,
101    Cancellation,
102    ComparisonOptions,
103    DateComparePolicy,
104    DiagnosticOptions,
105    DiffEvent,
106    DiffOptions,
107    DiffOptionsBuilder,
108    ExecutionMode,
109    ExecutionOptions,
110    FormulaCompareMode,
111    Limits,
112    MatchingOptions,
113    NumberComparePolicy,
114    NumericTypePolicy,
115    OutputOptions,
116    ProgressSink,
117    SheetMatchingMode,
118    TypeMismatchPolicy,
119    ValueCompareOptions,
120};
121
122// ---------------------------------------------------------------------------
123// Public entry points (RFC-033 §12)
124// ---------------------------------------------------------------------------
125
126use std::io::{Read, Seek};
127use std::path::Path;
128
129/// Compare two workbooks given their filesystem paths.
130///
131/// Uses [`DiffOptions::default()`].
132pub fn compare_paths(
133    old: impl AsRef<Path>,
134    new: impl AsRef<Path>,
135) -> Result<WorkbookDiff, SheetsDiffError> {
136    diff::run_compare_paths(old, new, DiffOptions::default())
137}
138
139/// Compare two workbooks given their filesystem paths, with explicit options.
140pub fn compare_paths_with_options(
141    old: impl AsRef<Path>,
142    new: impl AsRef<Path>,
143    opts: DiffOptions,
144) -> Result<WorkbookDiff, SheetsDiffError> {
145    diff::run_compare_paths(old, new, opts)
146}
147
148/// Compare two workbooks given byte slices.
149pub fn compare_bytes(
150    old: impl AsRef<[u8]>,
151    new: impl AsRef<[u8]>,
152) -> Result<WorkbookDiff, SheetsDiffError> {
153    diff::run_compare_bytes(old, new, DiffOptions::default())
154}
155
156/// Compare two workbooks given byte slices, with explicit options.
157pub fn compare_bytes_with_options(
158    old: impl AsRef<[u8]>,
159    new: impl AsRef<[u8]>,
160    opts: DiffOptions,
161) -> Result<WorkbookDiff, SheetsDiffError> {
162    diff::run_compare_bytes(old, new, opts)
163}
164
165/// Compare two workbooks given `Read + Seek` readers.
166///
167/// `.xlsx` is ZIP-based and requires seeking.
168pub fn compare_readers<R1, R2>(
169    old: R1,
170    new: R2,
171) -> Result<WorkbookDiff, SheetsDiffError>
172where
173    R1: Read + Seek,
174    R2: Read + Seek,
175{
176    diff::run_compare_readers(old, new, DiffOptions::default())
177}
178
179/// Compare two workbooks given `Read + Seek` readers, with explicit options.
180pub fn compare_readers_with_options<R1, R2>(
181    old: R1,
182    new: R2,
183    opts: DiffOptions,
184) -> Result<WorkbookDiff, SheetsDiffError>
185where
186    R1: Read + Seek,
187    R2: Read + Seek,
188{
189    diff::run_compare_readers(old, new, opts)
190}