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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
use std::ops::Range;
/// Trait for types the `Lexer` can read from.
///
/// Most notably this is implemented for `&str`. It is unlikely you will
/// ever want to use this Trait yourself, unless implementing a new `Source`
/// the `Lexer` can use.
pub trait Source {
/// Slice of this `Source`, for most types this will be `&str` with
/// appropriate lifetime.
type Slice;
/// Length of the source
fn len(&self) -> usize;
/// Read a single byte from source.
///
/// **Implementors of this method must guarantee it to return `0` when
/// `offset` is set to length of the `Source` (one byte after last)!**
///
/// ```rust
/// # extern crate logos;
/// # fn main() {
/// use logos::Source;
///
/// let foo = "foo";
///
/// unsafe {
/// assert_eq!(foo.read(0), b'f');
/// assert_eq!(foo.read(1), b'o');
/// assert_eq!(foo.read(2), b'o');
/// assert_eq!(foo.read(3), 0);
/// }
/// # }
/// ```
unsafe fn read(&self, offset: usize) -> u8;
/// Get a slice of the source at given range. This is analogous for
/// `slice::get_unchecked(range)`.
///
/// ```rust
/// # extern crate logos;
/// # fn main() {
/// use logos::Source;
///
/// let foo = "It was the year when they finally immanentized the Eschaton.";
///
/// unsafe {
/// assert_eq!(foo.slice(51..59), "Eschaton");
/// }
/// # }
/// ```
unsafe fn slice(&self, range: Range<usize>) -> Self::Slice;
}
impl<'source> Source for &'source str {
type Slice = &'source str;
fn len(&self) -> usize {
(*self).len()
}
unsafe fn read(&self, offset: usize) -> u8 {
debug_assert!(offset <= self.len(), "Reading out founds!");
match self.as_bytes().get(offset) {
Some(byte) => *byte,
None => 0,
}
}
unsafe fn slice(&self, range: Range<usize>) -> Self::Slice {
debug_assert!(
range.start <= self.len() && range.end <= self.len(),
"Reading out of bounds {:?} for {}!", range, self.len()
);
self.get_unchecked(range)
}
}
/// `Source` implemented on `NulTermStr` from the
/// [`toolshed`](https://crates.io/crates/toolshed) crate.
///
/// **This requires the `"nul_term_source"` feature to be enabled.**
#[cfg(feature = "nul_term_source")]
impl<'source> Source for toolshed::NulTermStr<'source> {
type Slice = &'source str;
fn len(&self) -> usize {
(**self).len()
}
unsafe fn read(&self, offset: usize) -> u8 {
debug_assert!(offset <= self.len(), "Reading out founds!");
self.byte_unchecked(offset)
}
unsafe fn slice(&self, range: Range<usize>) -> Self::Slice {
debug_assert!(
range.start <= self.len() && range.end <= self.len(),
"Reading out of bounds {:?} for {}!", range, self.len()
);
self.get_unchecked(range)
}
}