diff --git a/onihime/src/lib.rs b/onihime/src/lib.rs index 62a8b9d..fd842e9 100644 --- a/onihime/src/lib.rs +++ b/onihime/src/lib.rs @@ -7,4 +7,8 @@ unsafe_code )] +pub use self::span::Span; + pub mod lexer; + +mod span; diff --git a/onihime/src/span.rs b/onihime/src/span.rs new file mode 100644 index 0000000..54af3ad --- /dev/null +++ b/onihime/src/span.rs @@ -0,0 +1,90 @@ +/// A (half-open) range bounded inclusively below and exclusively above +/// `(start..end)`. +/// +/// The range `start..end` contains all values with `start <= x < end`. It is +/// empty if `start >= end`. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Span { + /// The lower bound of the range (inclusive). + pub start: usize, + /// The upper bound of the range (exclusive). + pub end: usize, +} + +impl Span { + /// Construct a new instance of a span. + #[must_use] + pub const fn new(start: usize, end: usize) -> Self { + Self { start, end } + } + + /// Returns `true` if `item` is contained in the span. + #[must_use] + pub fn contains(&self, item: usize) -> bool { + self.start <= item && item < self.end + } + + /// Returns `true` if the span contains no items. + #[must_use] + pub fn is_empty(&self) -> bool { + self.start >= self.end + } + + /// Extend the span's end bound to that of the provided span, if + /// `other.end > self.end`. + pub fn extend(&mut self, other: &Self) { + if other.end > self.end { + self.end = other.end; + } + } +} + +impl From> for Span { + fn from(range: std::ops::Range) -> Self { + Self::new(range.start, range.end) + } +} + +impl From for std::ops::Range { + fn from(span: Span) -> Self { + span.start..span.end + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn span_equality() { + let a = Span::new(0, 0); + let b = Span::new(0, 1); + + assert_eq!(a, a); + assert_ne!(a, b); + } + + #[test] + fn span_contains() { + let s = Span::new(1, 3); + + assert!(s.contains(1)); + assert!(s.contains(2)); + + assert!(!s.contains(0)); + assert!(!s.contains(3)); + } + + #[test] + fn span_extend() { + let mut a = Span::new(0, 5); + let b = Span::new(1, 10); + let c = Span::new(5, 6); + + assert_eq!(a.end, 5); + a.extend(&b); + assert_eq!(a.end, 10); + a.extend(&c); + assert_eq!(a.end, 10); + } +}