#![cfg_attr(feature = "nightly", feature(step_trait, step_trait_ext))] use std::marker::PhantomData; use std::path::PathBuf; #[cfg(feature = "nightly")] use std::iter::Step; use serde::{Deserialize, Serialize}; pub mod compiler; #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Column(pub u32, PhantomData); impl Column { fn new(c: u32) -> Column { Column(c, PhantomData) } } impl Clone for Column { fn clone(&self) -> Column { *self } } impl Copy for Column {} impl Serialize for Column { fn serialize( &self, s: S, ) -> Result<::Ok, ::Error> { s.serialize_u32(self.0) } } impl<'dt, I: Indexed> Deserialize<'dt> for Column { fn deserialize>( d: D, ) -> std::result::Result>::Error> { ::deserialize(d).map(Column::new) } } #[cfg(feature = "serialize-rustc")] impl rustc_serialize::Decodable for Column { fn decode(d: &mut D) -> Result, D::Error> { d.read_u32().map(Column::new) } } #[cfg(feature = "serialize-rustc")] impl rustc_serialize::Encodable for Column { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u32(self.0) } } impl Column { pub fn new_one_indexed(c: u32) -> Column { Column(c, PhantomData) } pub fn zero_indexed(self) -> Column { Column(self.0 - 1, PhantomData) } } impl Column { pub fn new_zero_indexed(c: u32) -> Column { Column(c, PhantomData) } pub fn one_indexed(self) -> Column { Column(self.0 + 1, PhantomData) } } #[cfg(feature = "nightly")] macro_rules! impl_step { ($target: ty) => { unsafe impl Step for $target { fn steps_between(start: &Self, end: &Self) -> Option { Step::steps_between(&start.0, &end.0) } fn forward_checked(arg: Self, count: usize) -> Option { Step::forward_checked(arg.0, count).map(|x| Self(x, PhantomData)) } fn backward_checked(arg: Self, count: usize) -> Option { Step::backward_checked(arg.0, count).map(|x| Self(x, PhantomData)) } } }; } #[cfg(feature = "nightly")] impl_step!(Column); #[cfg(feature = "nightly")] impl_step!(Column); #[cfg(feature = "nightly")] impl_step!(Row); #[cfg(feature = "nightly")] impl_step!(Row); #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Row(pub u32, PhantomData); impl Row { fn new(c: u32) -> Row { Row(c, PhantomData) } } impl Clone for Row { fn clone(&self) -> Row { *self } } impl Copy for Row {} impl serde::Serialize for Row { fn serialize(&self, s: S) -> Result { s.serialize_u32(self.0) } } impl<'dt, I: Indexed> serde::Deserialize<'dt> for Row { fn deserialize>(d: D) -> std::result::Result { ::deserialize(d).map(Row::new) } } #[cfg(feature = "serialize-rustc")] impl rustc_serialize::Decodable for Row { fn decode(d: &mut D) -> Result, D::Error> { d.read_u32().map(Row::new) } } #[cfg(feature = "serialize-rustc")] impl rustc_serialize::Encodable for Row { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u32(self.0) } } impl Row { pub fn new_one_indexed(c: u32) -> Row { Row(c, PhantomData) } pub fn zero_indexed(self) -> Row { Row(self.0 - 1, PhantomData) } } impl Row { pub fn new_zero_indexed(c: u32) -> Row { Row(c, PhantomData) } pub fn one_indexed(self) -> Row { Row(self.0 + 1, PhantomData) } } #[cfg_attr(feature = "derive", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Position { pub row: Row, pub col: Column, } impl Position { pub fn new(row: Row, col: Column) -> Position { Position { row, col } } } impl Clone for Position { fn clone(&self) -> Position { *self } } impl Copy for Position {} impl Position { pub fn zero_indexed(self) -> Position { Position { row: self.row.zero_indexed(), col: self.col.zero_indexed() } } } impl Position { pub fn one_indexed(self) -> Position { Position { row: self.row.one_indexed(), col: self.col.one_indexed() } } } #[cfg_attr(feature = "derive", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Range { pub row_start: Row, pub row_end: Row, pub col_start: Column, pub col_end: Column, } impl Range { pub fn new( row_start: Row, row_end: Row, col_start: Column, col_end: Column, ) -> Range { Range { row_start, row_end, col_start, col_end } } pub fn from_positions(start: Position, end: Position) -> Range { Range { row_start: start.row, row_end: end.row, col_start: start.col, col_end: end.col } } pub fn start(self) -> Position { Position { row: self.row_start, col: self.col_start } } pub fn end(self) -> Position { Position { row: self.row_end, col: self.col_end } } } impl Clone for Range { fn clone(&self) -> Range { *self } } impl Copy for Range {} impl Range { pub fn zero_indexed(self) -> Range { Range { row_start: self.row_start.zero_indexed(), row_end: self.row_end.zero_indexed(), col_start: self.col_start.zero_indexed(), col_end: self.col_end.zero_indexed(), } } } impl Range { pub fn one_indexed(self) -> Range { Range { row_start: self.row_start.one_indexed(), row_end: self.row_end.one_indexed(), col_start: self.col_start.one_indexed(), col_end: self.col_end.one_indexed(), } } } #[cfg_attr(feature = "derive", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Location { pub file: PathBuf, pub position: Position, } impl Location { pub fn new>(row: Row, col: Column, file: F) -> Location { Location { position: Position { row, col }, file: file.into() } } pub fn from_position>(position: Position, file: F) -> Location { Location { position, file: file.into() } } } impl Clone for Location { fn clone(&self) -> Location { Location { position: self.position, file: self.file.clone() } } } impl Location { pub fn zero_indexed(&self) -> Location { Location { position: self.position.zero_indexed(), file: self.file.clone() } } } impl Location { pub fn one_indexed(&self) -> Location { Location { position: self.position.one_indexed(), file: self.file.clone() } } } #[cfg_attr(feature = "derive", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Span { pub file: PathBuf, pub range: Range, } impl Span { pub fn new>( row_start: Row, row_end: Row, col_start: Column, col_end: Column, file: F, ) -> Span { Span { range: Range { row_start, row_end, col_start, col_end }, file: file.into() } } pub fn from_range>(range: Range, file: F) -> Span { Span { range, file: file.into() } } pub fn from_positions>( start: Position, end: Position, file: F, ) -> Span { Span { range: Range::from_positions(start, end), file: file.into() } } } impl Clone for Span { fn clone(&self) -> Span { Span { range: self.range, file: self.file.clone() } } } impl Span { pub fn zero_indexed(&self) -> Span { Span { range: self.range.zero_indexed(), file: self.file.clone() } } } impl Span { pub fn one_indexed(&self) -> Span { Span { range: self.range.one_indexed(), file: self.file.clone() } } } pub trait Indexed {} #[cfg_attr(feature = "derive", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] #[derive(Hash, PartialEq, Eq, Debug, PartialOrd, Ord)] pub struct ZeroIndexed; impl Indexed for ZeroIndexed {} #[cfg_attr(feature = "derive", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] #[derive(Hash, PartialEq, Eq, Debug, PartialOrd, Ord)] pub struct OneIndexed; impl Indexed for OneIndexed {} #[cfg(feature = "nightly")] #[cfg(test)] mod test { use super::*; #[test] fn iter_row() { assert_eq!((Row::new_one_indexed(4)..Row::new_one_indexed(8)).count(), 4); assert_eq!( &*(Row::new_zero_indexed(0)..=Row::new_zero_indexed(8)) .filter(|r| r.0 < 3) .map(|r| r.0) .collect::>(), &[0, 1, 2], ); } }