use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use super::input::Input;
use super::position;
pub struct Span<I: Input> {
input: Rc<I>,
start: usize,
end: usize
}
#[inline]
pub fn new<I: Input>(input: Rc<I>, start: usize, end: usize) -> Span<I> {
Span { input, start, end }
}
impl<I: Input> Span<I> {
#[inline]
pub fn start(&self) -> usize {
self.start
}
#[inline]
pub fn end(&self) -> usize {
self.end
}
#[inline]
pub fn start_pos(&self) -> position::Position<I> {
unsafe { position::new(self.input.clone(), self.start) }
}
#[inline]
pub fn end_pos(&self) -> position::Position<I> {
unsafe { position::new(self.input.clone(), self.end) }
}
#[inline]
pub fn split(self) -> (position::Position<I>, position::Position<I>) {
let pos1 = unsafe { position::new(self.input.clone(), self.start) };
let pos2 = unsafe { position::new(self.input, self.end) };
(pos1, pos2)
}
#[inline]
pub fn as_str(&self) -> &str {
unsafe { self.input.slice(self.start, self.end) }
}
}
impl<I: Input> fmt::Debug for Span<I> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Span {{ start: {}, end: {} }}", self.start, self.end)
}
}
impl<I: Input> Clone for Span<I> {
fn clone(&self) -> Span<I> {
new(self.input.clone(), self.start, self.end)
}
}
impl<I: Input> PartialEq for Span<I> {
fn eq(&self, other: &Span<I>) -> bool {
Rc::ptr_eq(&self.input, &other.input) && self.start == other.start && self.end == other.end
}
}
impl<I: Input> Eq for Span<I> {}
impl<I: Input> PartialOrd for Span<I> {
fn partial_cmp(&self, other: &Span<I>) -> Option<Ordering> {
if Rc::ptr_eq(&self.input, &other.input) {
match self.start.partial_cmp(&other.start) {
Some(Ordering::Equal) => self.end.partial_cmp(&other.end),
ordering => ordering
}
} else {
None
}
}
}
impl<I: Input> Ord for Span<I> {
fn cmp(&self, other: &Span<I>) -> Ordering {
self.partial_cmp(other).expect(
"cannot compare spans from \
different inputs"
)
}
}
impl<I: Input> Hash for Span<I> {
fn hash<H: Hasher>(&self, state: &mut H) {
(&*self.input as *const I).hash(state);
self.start.hash(state);
self.end.hash(state);
}
}