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}