pub struct Span {
pub span_id: String,
pub file_path: String,
pub byte_start: usize,
pub byte_end: usize,
pub start_line: usize,
pub start_col: usize,
pub end_line: usize,
pub end_col: usize,
pub context: Option<SpanContext>,
pub semantics: Option<SpanSemantics>,
pub relationships: Option<SpanRelationships>,
pub checksums: Option<SpanChecksums>,
}Expand description
Span in source code (byte + line/column)
Represents a half-open range [start, end) where:
byte_startis inclusive (first byte INCLUDED)byte_endis exclusive (first byte NOT included)
All offsets are UTF-8 byte positions. Lines are 1-indexed for user-friendliness. Columns are 0-indexed byte offsets within each line.
§Examples
Creating a span and extracting text:
use magellan::output::command::Span;
let source = "fn main() { println!(\"Hello\"); }";
let span = Span::new(
"main.rs".into(), // file_path
3, // byte_start (points to 'm')
7, // byte_end (points to '(')
1, // start_line (1-indexed)
3, // start_col (byte offset in line)
1, // end_line
7, // end_col
);
// Extract text using the span
let text = source.get(span.byte_start..span.byte_end).unwrap();
assert_eq!(text, "main");§Safety
Always use .get() for UTF-8 safe slicing:
// SAFE: Returns Option<&str>, None if out of bounds
let text = source.get(span.byte_start..span.byte_end);
// UNSAFE: Can panic on invalid UTF-8 boundaries
// let text = &source[span.byte_start..span.byte_end];§Serialization
Span implements Serialize and Deserialize for JSON output.
All fields are public and included in serialization.
Fields§
§span_id: StringStable span ID (SHA-256 hash of file_path:byte_start:byte_end)
This ID is deterministic and platform-independent.
See Span::generate_id for the algorithm details.
file_path: StringFile path (absolute or root-relative)
Use consistent paths for stable IDs. The path is included
in the span ID hash, so different representations of the same
file (e.g., ./main.rs vs main.rs) produce different IDs.
byte_start: usizeByte range start (inclusive, first byte INCLUDED)
UTF-8 byte offset from the start of the file.
byte_end: usizeByte range end (exclusive, first byte NOT included)
UTF-8 byte offset. The span covers [byte_start, byte_end).
Length is byte_end - byte_start.
start_line: usizeStart line (1-indexed)
Line number where the span starts, counting from 1. Matches editor line numbers.
start_col: usizeStart column (0-indexed, byte-based)
Byte offset within start_line where the span begins.
This is a byte offset, not a character offset.
end_line: usizeEnd line (1-indexed)
Line number where the span ends.
end_col: usizeEnd column (0-indexed, byte-based)
Byte offset within end_line where the span ends (exclusive).
context: Option<SpanContext>Context lines around the span
semantics: Option<SpanSemantics>Semantic information (kind, language) - grouped in a single struct
relationships: Option<SpanRelationships>Relationship information (callers, callees, imports, exports)
checksums: Option<SpanChecksums>Checksums for content verification
Implementations§
Source§impl Span
impl Span
Sourcepub fn generate_id(
file_path: &str,
byte_start: usize,
byte_end: usize,
) -> String
pub fn generate_id( file_path: &str, byte_start: usize, byte_end: usize, ) -> String
Generate a stable span ID from (file_path, byte_start, byte_end)
Uses SHA-256 for platform-independent, deterministic span IDs.
§Algorithm
The hash is computed from: file_path + ":" + byte_start + ":" + byte_end
The first 8 bytes (64 bits) of the hash are formatted as 16 hex characters.
§Properties
This ensures span IDs are:
- Deterministic: same inputs always produce the same ID
- Platform-independent: SHA-256 produces consistent results across architectures
- Collision-resistant: 64-bit space with good distribution
§Stability
The span ID format is part of Magellan’s stable API contract. IDs generated by this function will remain consistent across versions.
§Examples
use magellan::output::command::Span;
let id1 = Span::generate_id("main.rs", 10, 20);
let id2 = Span::generate_id("main.rs", 10, 20);
let id3 = Span::generate_id("main.rs", 10, 21);
assert_eq!(id1, id2); // Same inputs = same ID
assert_ne!(id1, id3); // Different inputs = different ID
assert_eq!(id1.len(), 16); // Always 16 hex charactersSourcepub fn new(
file_path: String,
byte_start: usize,
byte_end: usize,
start_line: usize,
start_col: usize,
end_line: usize,
end_col: usize,
) -> Self
pub fn new( file_path: String, byte_start: usize, byte_end: usize, start_line: usize, start_col: usize, end_line: usize, end_col: usize, ) -> Self
Create a new Span from component parts
Constructs a Span with a stable span_id automatically
generated using Span::generate_id.
§Parameters
file_path: Path to the source file (absolute or root-relative)byte_start: UTF-8 byte offset where the span starts (inclusive)byte_end: UTF-8 byte offset where the span ends (exclusive)start_line: Line number where the span starts (1-indexed)start_col: Byte offset withinstart_linewhere the span starts (0-indexed)end_line: Line number where the span ends (1-indexed)end_col: Byte offset withinend_linewhere the span ends (0-indexed, exclusive)
§Half-Open Convention
The span uses half-open range semantics [byte_start, byte_end):
byte_startis inclusive (first byte included)byte_endis exclusive (first byte NOT included)
§Examples
use magellan::output::command::Span;
let span = Span::new(
"main.rs".into(), // file_path
3, // byte_start (inclusive)
7, // byte_end (exclusive)
1, // start_line (1-indexed)
3, // start_col (byte offset, 0-indexed)
1, // end_line
7, // end_col (byte offset, 0-indexed)
);
assert_eq!(span.byte_end - span.byte_start, 4); // Length
assert_eq!(span.span_id.len(), 16); // Stable IDSourcepub fn with_context(self, context: SpanContext) -> Self
pub fn with_context(self, context: SpanContext) -> Self
Set context on the span
Sourcepub fn with_semantics(self, semantics: SpanSemantics) -> Self
pub fn with_semantics(self, semantics: SpanSemantics) -> Self
Set semantic information on the span
Sourcepub fn with_semantics_from(self, kind: String, language: String) -> Self
pub fn with_semantics_from(self, kind: String, language: String) -> Self
Set semantic information from kind and language strings
Sourcepub fn with_relationships(self, relationships: SpanRelationships) -> Self
pub fn with_relationships(self, relationships: SpanRelationships) -> Self
Set relationships on the span
Sourcepub fn with_checksums(self, checksums: SpanChecksums) -> Self
pub fn with_checksums(self, checksums: SpanChecksums) -> Self
Set checksums on the span
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Span
impl<'de> Deserialize<'de> for Span
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for Span
impl StructuralPartialEq for Span
Auto Trait Implementations§
impl Freeze for Span
impl RefUnwindSafe for Span
impl Send for Span
impl Sync for Span
impl Unpin for Span
impl UnsafeUnpin for Span
impl UnwindSafe for Span
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more