Skip to main content

sheets_diff/
lib.rs

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