loom_diff/lib.rs
1//! # loom-diff
2//!
3//! Line-level diff used by both the loom CLI and the loom-gateway.
4//! Pure functions: feed in two text blobs (or byte slices), get back
5//! either a structured [`FileDiff`] (good for JSON / UI consumers) or
6//! a `String` of git-style unified diff (good for terminal output).
7//!
8//! Backed by the `similar` crate's Myers algorithm. Binary blobs are
9//! detected via a simple null-byte heuristic and surface as a `Binary`
10//! diff variant — we don't try to render diffs of binary content.
11//!
12//! ## Layering
13//!
14//! ```text
15//! loom-web · loom-gateway ← consumers
16//! loom-diff ← THIS CRATE
17//! ─── frozen below ─────────────────────────
18//! weave-sdk · Strand · Locus · Lens · DHT · Forum
19//! ```
20
21#![warn(missing_docs)]
22
23mod render;
24mod structured;
25
26pub use render::{unified_diff_string, UnifiedDiffOptions};
27pub use structured::{
28 diff_blobs, file_diff, BinaryReason, DiffHunk, DiffLine, DiffLineKind, FileDiff, FileDiffStatus,
29};
30
31use thiserror::Error;
32
33/// Errors produced by loom-diff.
34#[derive(Debug, Error)]
35pub enum DiffError {
36 /// Caller asked for a diff with non-utf8 bytes; the structured API
37 /// surfaces this as a `Binary` diff instead. Reserved for cases where
38 /// callers explicitly demanded text decoding.
39 #[error("not valid utf-8")]
40 NotUtf8,
41}
42
43/// Result alias.
44pub type Result<T> = std::result::Result<T, DiffError>;
45
46/// Heuristic: a byte slice is "probably binary" if the first 8KB
47/// contains a null byte. This is the same check git uses.
48pub fn looks_binary(bytes: &[u8]) -> bool {
49 let sample_len = bytes.len().min(8192);
50 bytes[..sample_len].contains(&0)
51}