span_lang/lib.rs
1//! # span-lang
2//!
3//! The source-position substrate for language tooling. It defines the small,
4//! copyable coordinate types that a lexer, a parser, and a diagnostic renderer
5//! all share: a [`BytePos`] (a byte offset), a [`Span`] (a half-open byte range),
6//! a resolved [`LineCol`], and the [`LineIndex`] that maps between them — correctly
7//! over UTF-8, across both `\n` and `\r\n` line endings.
8//!
9//! It owns positions and nothing else. Loading source text is the job of a
10//! separate layer; rendering an error that points at a span is another. Keeping
11//! this crate to coordinates alone is what lets every layer above it depend on it
12//! without pulling in I/O or rendering.
13//!
14//! ## Design
15//!
16//! - A [`BytePos`] is a 32-bit byte offset, so a single source is addressable up
17//! to 4 GiB — the same envelope established compiler front-ends use.
18//! - A [`Span`] is two packed offsets (eight bytes), `Copy`, with the invariant
19//! that `start <= end`. An empty span (`start == end`) is a legal zero-width
20//! point.
21//! - A [`LineIndex`] is built once per source and answers byte → [`LineCol`] in
22//! `O(log lines)` (a binary search over line starts), and the inverse, without
23//! allocating on the lookup path.
24//!
25//! ## Quickstart
26//!
27//! ```
28//! use span_lang::{LineIndex, Span};
29//!
30//! let src = "fn main() {\n work();\n}\n";
31//!
32//! // A span is a half-open byte range; merging covers both inputs.
33//! let a = Span::new(16, 20);
34//! let b = Span::new(18, 22);
35//! assert_eq!(a.merge(b), Span::new(16, 22));
36//!
37//! // Resolve a byte offset to a human (line, column) coordinate.
38//! let index = LineIndex::new(src);
39//! let lc = index.line_col(a.start());
40//! assert_eq!((lc.line, lc.col), (2, 5));
41//!
42//! // And back again — the mapping round-trips.
43//! assert_eq!(index.offset(lc), Some(a.start()));
44//! ```
45
46#![cfg_attr(not(feature = "std"), no_std)]
47#![cfg_attr(docsrs, feature(doc_cfg))]
48#![deny(missing_docs)]
49#![forbid(unsafe_code)]
50
51extern crate alloc;
52
53mod index;
54mod line_col;
55mod pos;
56mod span;
57mod spanned;
58
59pub use index::LineIndex;
60pub use line_col::LineCol;
61pub use pos::BytePos;
62pub use span::Span;
63pub use spanned::Spanned;