intern_lang/lib.rs
1//! # intern_lang
2//!
3//! Fast string and symbol interning — identifier comparisons become integer
4//! comparisons.
5//!
6//! `intern-lang` maps each distinct string to a small, copyable [`Symbol`],
7//! stores the bytes once in a contiguous backing store, and hands back integer
8//! handles. A compiler front-end interns every identifier once, then compares and
9//! passes symbols instead of strings: a name comparison becomes an integer
10//! comparison, and a name in an AST node costs four bytes instead of an owned
11//! `String`. It is the deduplication layer beneath a lexer and a symbol table,
12//! and it owns interning and nothing else — no lexing, no scoping, no I/O.
13//!
14//! ## At a glance
15//!
16//! - [`Interner`] — the single-threaded interner. [`intern`](Interner::intern)
17//! deduplicates and returns a stable [`Symbol`];
18//! [`resolve`](Interner::resolve) borrows the bytes back out of the store.
19//! - [`Symbol`] — a four-byte `Copy` handle whose equality, ordering, and hashing
20//! are integer operations.
21//!
22//! ## Example
23//!
24//! ```
25//! use intern_lang::Interner;
26//!
27//! let mut interner = Interner::new();
28//!
29//! // Interning the same string twice yields the same symbol...
30//! let a = interner.intern("while");
31//! let b = interner.intern("while");
32//! assert_eq!(a, b);
33//!
34//! // ...and distinct strings yield distinct symbols.
35//! let c = interner.intern("for");
36//! assert_ne!(a, c);
37//!
38//! // Comparing names is now an integer compare; resolving borrows the bytes.
39//! assert_eq!(interner.resolve(a), Some("while"));
40//! assert_eq!(interner.resolve(c), Some("for"));
41//! ```
42//!
43//! ## `no_std`
44//!
45//! The crate is `no_std`-compatible: it relies only on `alloc`, never on the
46//! standard library. The default `std` feature is additive. Disable default
47//! features to build for a `no_std` target.
48
49#![cfg_attr(not(feature = "std"), no_std)]
50#![cfg_attr(docsrs, feature(doc_cfg))]
51#![forbid(unsafe_code)]
52#![deny(missing_docs)]
53#![deny(unused_must_use)]
54#![deny(unused_results)]
55#![deny(clippy::unwrap_used)]
56#![deny(clippy::expect_used)]
57#![deny(clippy::todo)]
58#![deny(clippy::unimplemented)]
59#![deny(clippy::print_stdout)]
60#![deny(clippy::print_stderr)]
61#![deny(clippy::dbg_macro)]
62#![deny(clippy::unreachable)]
63
64extern crate alloc;
65
66mod interner;
67mod symbol;
68
69pub use interner::Interner;
70pub use symbol::Symbol;