File tree Expand file tree Collapse file tree 2 files changed +59
-0
lines changed
Expand file tree Collapse file tree 2 files changed +59
-0
lines changed Original file line number Diff line number Diff line change @@ -141,6 +141,34 @@ impl SourceFile {
141141 }
142142 Some ( SourceSpan :: from ( start..end) )
143143 }
144+
145+ /// Creates a span for an item using a substring of `contents`
146+ ///
147+ /// Note that substr must be a literal substring, as in it must be
148+ /// a pointer into the same string! If it's not we'll return None.
149+ pub fn span_for_substr ( & self , substr : & str ) -> Option < SourceSpan > {
150+ // Get the bounds of the full string
151+ let base_addr = self . inner . contents . as_ptr ( ) as usize ;
152+ let base_len = self . inner . contents . len ( ) ;
153+
154+ // Get the bounds of the substring
155+ let substr_addr = substr. as_ptr ( ) as usize ;
156+ let substr_len = substr. len ( ) ;
157+
158+ // The index of the substring is just the number of bytes it is from the start
159+ // (This will bail out if the """substring""" has an address *before* the full string)
160+ let start = substr_addr. checked_sub ( base_addr) ?;
161+ // The end index (exclusive) is just the start index + sublen
162+ // (This will bail out if this overflows)
163+ let end = start. checked_add ( substr_len) ?;
164+ // Finally, make sure the substr endpoint isn't past the end of the full string
165+ if end > base_len {
166+ return None ;
167+ }
168+
169+ // At this point it's definitely a substring, nice!
170+ Some ( SourceSpan :: from ( start..end) )
171+ }
144172}
145173
146174impl SourceCode for SourceFile {
Original file line number Diff line number Diff line change 1+ use miette:: SourceCode ;
2+
3+ #[ test]
4+ fn substr_span ( ) {
5+ // Make the file
6+ let contents = String :: from ( "hello !there!" ) ;
7+ let source = axoasset:: SourceFile :: new ( "file.md" , contents) . unwrap ( ) ;
8+
9+ // Do some random parsing operation
10+ let mut parse = source. contents ( ) . split ( '!' ) ;
11+ let _ = parse. next ( ) ;
12+ let there = parse. next ( ) . unwrap ( ) ;
13+
14+ // Get the span
15+ let there_span = source. span_for_substr ( there) . unwrap ( ) ;
16+
17+ // Assert the span is correct
18+ let span_bytes = source. read_span ( & there_span, 0 , 0 ) . unwrap ( ) . data ( ) ;
19+ assert_eq ! ( std:: str :: from_utf8( span_bytes) . unwrap( ) , "there" ) ;
20+ }
21+
22+ #[ test]
23+ fn substr_span_invalid ( ) {
24+ // Make the file
25+ let contents = String :: from ( "hello !there!" ) ;
26+ let source = axoasset:: SourceFile :: new ( "file.md" , contents) . unwrap ( ) ;
27+
28+ // Get the span for a non-substring (string literal isn't pointing into the String)
29+ let there_span = source. span_for_substr ( "there" ) ;
30+ assert_eq ! ( there_span, None ) ;
31+ }
You can’t perform that action at this time.
0 commit comments