Skip to main content

SourceMap

Struct SourceMap 

Source
pub struct SourceMap<'src> { /* private fields */ }
Expand description

Provides utilities for mapping ByteSpans to SourceSpans, byte offsets to SourcePositions, and extracting content from the original source text.

The 'src lifetime ties the SourceMap to the source text it was built from.

SourceMap is a key part of what makes libgraphql-parser fast. The lexer and parser operate exclusively on compact u32 byte offsets (stored in ByteSpans), deferring line/column computation until it is actually needed — typically only for error formatting or tooling & IDE features. SourceMap is the mechanism that makes this deferred resolution possible, translating raw byte offsets back to human-readable SourcePositions on demand.

Construction of SourceMaps is typically owned by a GraphQLTokenSource and uses one of two modes of data-fill: SourceMap::new_with_source or SourceMap::new_precomputed.

§Construction with source text (SourceMap::new_with_source)

An O(sourcelen) (SIMD-accelerated) pre-pass scans the source string for line terminators (\n, \r, \r\n) and records the byte offset of each line start. Individual position lookups via SourceMap::resolve_offset later are then O(log n) binary searches on the line-start table, plus a short char-counting walk from line start to target byte offset to compute UTF-8 and UTF-16 column values.

This mode is used by StrGraphQLTokenSource, which has direct access to the source string. It is memory-efficient (only one u32 per line) and avoids as much per-token bookkeeping as possible during lexing — the lexer only tracks a single curr_byte_offset and defers all line/column computation.

§Pre-Computed Columns Mode (SourceMap::new_precomputed)

Some token sources do not have access to the underlying source text at resolution time. For example, libgraphql_macros::RustMacroGraphQLTokenSource produces tokens from a proc_macro2::TokenStream. Each proc_macro2::Span carries line/column information at the time the token is produced, but there is no contiguous source &str to scan after the fact. In this mode, the token source collects (byte_offset, SourcePosition) entries during lexing and then constructs the SourceMap at the end by passing the entries to new_precomputed(). Later, lookups will binary-search that entries table.

This mode uses more memory (one full SourcePosition per inserted offset, rather than one u32 per line), but lookups are O(log n) with no char-counting walk — just a binary search and a direct return.

When a SourceMap is constructed in pre-computed mode, the 'src lifetime is typically 'static since no source text is borrowed.

§UTF-16 Column Recovery

In source-text mode, UTF-16 columns are computed on demand by iterating chars from the line start to the target byte offset and summing char::len_utf16(). In pre-computed columns mode, UTF-16 columns are whatever the token source provided (or None if the token source cannot compute them).

Implementations§

Source§

impl<'src> SourceMap<'src>

Source

pub fn new_with_source(source: &'src str, file_path: Option<PathBuf>) -> Self

Builds a SourceMap in source-text mode by scanning source for line terminators.

This is an O(n) pre-pass that identifies all line start byte offsets. Line terminators recognized: \n, \r, \r\n (the pair counts as one terminator).

Source

pub fn new_precomputed( entries: Vec<(u32, SourcePosition)>, file_path: Option<PathBuf>, ) -> Self

Creates a SourceMap in pre-computed columns mode.

The entries parameter contains (byte_offset, SourcePosition) pairs that were collected during lexing. Entries must be sorted by byte offset in monotonically increasing order (which is naturally the case when collected during a left-to-right lex pass).

This mode is intended for token sources that know line/column information at lex time but do not have access to the underlying source text afterward.

See the type-level documentation for a detailed comparison of the two modes.

§Example
// During lexing, collect entries into a Vec:
let mut entries = Vec::new();
entries.push((byte_offset, position));
// After lexing, build the SourceMap:
let source_map = SourceMap::new_precomputed(entries, None);
Source

pub fn empty() -> Self

Creates an empty SourceMap that cannot resolve any offsets.

Useful for token sources that don’t have source text (e.g. proc-macro token sources or test mocks).

Source

pub fn source(&self) -> Option<&'src str>

Returns the source text, if this is a source-text-mode SourceMap.

Source

pub fn file_path(&self) -> Option<&Path>

Returns the file path, if available.

Source

pub fn resolve_offset(&self, byte_offset: u32) -> Option<SourcePosition>

Resolves a byte offset to a full SourcePosition (line, col_utf8, col_utf16, byte_offset).

Returns None if the offset cannot be resolved — for example, if the byte offset is out of bounds (source-text mode) or if no pre-computed entries cover the requested offset.

§Source-text mode

Uses binary search on line_starts to find the line, then counts chars from the line start to compute columns.

§Pre-computed columns mode

Binary-searches the pre-computed entries for the largest byte offset <= the requested offset (floor lookup). If the requested offset falls between two entries, the earlier entry’s position is returned (this handles lookups for byte offsets mid-token, returning the position of the nearest preceding entry).

Source

pub fn resolve_span(&self, span: ByteSpan) -> Option<SourceSpan>

Resolves a ByteSpan to a full SourceSpan with line/column information and file path.

Returns None if either endpoint of the span cannot be resolved. Common scenarios where resolution fails:

  • Empty SourceMap (SourceMap::empty()): no entries exist, so no offset can be resolved.
  • Out-of-bounds offset: the byte offset exceeds the source text length (source-text mode) or falls before the first pre-computed entry (pre-computed columns mode).
  • Mid-UTF-8 offset: the byte offset lands in the middle of a multi-byte UTF-8 character (source-text mode only).

For error reporting, the parser’s internal resolve_span() wrapper falls back to SourceSpan::zero() when this method returns None. For AST tooling that needs accurate positions, callers should handle the None case explicitly.

Source

pub fn get_line(&self, line_index: usize) -> Option<&'src str>

Returns the content of the line at the given 0-based line index, stripped of any trailing line terminator (\n, \r, \r\n).

Returns None if this is not a source-text-mode SourceMap, or if line_index is out of bounds.

This uses the line_starts table built by compute_line_starts(), which correctly recognizes bare \r as a line terminator per the GraphQL spec. Code that needs to extract line content should use this method rather than str::lines(), which does not handle bare \r.

Note: graphql_parse_error::get_line() provides similar functionality via a linear scan (no pre-computed table). Both must use the same line-terminator semantics.

Source

pub fn line_count(&self) -> usize

Returns the number of lines in the source text.

In source-text mode, this is the number of line-start entries computed during construction. In pre-computed columns mode, this is derived from the highest line number seen in the entries (plus one). Returns 0 if no entries have been inserted.

Trait Implementations§

Source§

impl<'src> Clone for SourceMap<'src>

Source§

fn clone(&self) -> SourceMap<'src>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<'src> Debug for SourceMap<'src>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'src> Freeze for SourceMap<'src>

§

impl<'src> RefUnwindSafe for SourceMap<'src>

§

impl<'src> Send for SourceMap<'src>

§

impl<'src> Sync for SourceMap<'src>

§

impl<'src> Unpin for SourceMap<'src>

§

impl<'src> UnsafeUnpin for SourceMap<'src>

§

impl<'src> UnwindSafe for SourceMap<'src>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.