1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//! The [`Lookup`] trait: the read-side contract shared by every interner.
use crateSymbol;
/// The read-side contract every interner in the crate implements.
///
/// `Lookup` is the seam that lets generic code accept either the single-threaded
/// [`Interner`](crate::Interner) or the
/// [`ConcurrentInterner`](crate::ConcurrentInterner): both look a string up to its
/// symbol, resolve a symbol back to its bytes, and report their size — all through
/// `&self`. Interning is deliberately *not* on this trait, because the two
/// interners disagree on how it is called (`&mut self` for the single-threaded
/// one, `&self` for the concurrent one), and forcing a common signature would tax
/// the single-threaded hot path with synchronisation it does not need.
///
/// Resolution is expressed as [`resolve_with`](Lookup::resolve_with) — a closure
/// that runs against the borrowed string — rather than a method returning
/// `&str`. A concurrent interner can only expose the bytes while it holds its
/// read lock, so the borrow cannot outlive the call; a closure keeps resolution
/// zero-copy for both interners without leaking the lock's lifetime into the
/// signature.
///
/// # Examples
///
/// ```
/// use intern_lang::{Interner, Lookup};
///
/// fn name_len(interner: &impl Lookup, s: &str) -> Option<usize> {
/// let sym = interner.get(s)?;
/// interner.resolve_with(sym, str::len)
/// }
///
/// let mut interner = Interner::new();
/// let _ = interner.intern("identifier");
/// assert_eq!(name_len(&interner, "identifier"), Some(10));
/// assert_eq!(name_len(&interner, "missing"), None);
/// ```