use std::{
fmt::{Display, Debug},
str::FromStr
};
use crate::TextPosition;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct InsertPosition {
line: usize,
col: usize,
}
impl Default for InsertPosition {
fn default() -> Self {
Self { line: 1, col: 0 }
}
}
impl InsertPosition {
pub fn new(line: usize, col: usize) -> Self {
assert_ne!(line, 0);
InsertPosition { line, col }
}
pub fn line(&self) -> usize { self.line }
pub fn col(&self) -> usize { self.col }
pub fn inc_col(&mut self) {
self.col += 1;
}
pub fn inc_line(&mut self) {
self.line += 1;
self.col = 0;
}
pub fn inc(&mut self, c: char) {
if c == '\n' {
self.inc_line();
} else {
self.inc_col();
}
}
pub(crate) fn text_pos_left(&self) -> TextPosition {
TextPosition::new(self.line(), self.col())
}
pub(crate) fn text_pos_right(&self) -> TextPosition {
TextPosition::new(self.line(), self.col()+1)
}
}
impl Display for InsertPosition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.line(), self.col())
}
}
impl Debug for InsertPosition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
impl FromStr for InsertPosition {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (line_str, col_str) = s.trim().split_once(':').ok_or(())?;
let line: usize = line_str.parse().map_err(|_| ())?;
let col: usize = col_str.parse().map_err(|_| ())?;
if line == 0 { return Err(()); }
Ok(InsertPosition::new(line, col))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn initializes_correctly() {
let default = InsertPosition::default();
assert_eq!(default.line(), 1);
assert_eq!(default.col(), 0);
}
#[test]
fn increment_methods() {
let mut pos = InsertPosition::default();
pos.inc_col();
pos.inc_col();
pos.inc_col();
assert_eq!(pos.line(), 1);
assert_eq!(pos.col(), 3);
pos.inc_col();
pos.inc_line();
pos.inc_col();
assert_eq!(pos.line(), 2);
assert_eq!(pos.col(), 1);
pos.inc_col();
pos.inc_line();
pos.inc_line();
assert_eq!(pos.line(), 4);
assert_eq!(pos.col(), 0);
}
#[test]
fn display_print() {
let mut pos = InsertPosition::default();
pos.inc_col();
pos.inc_line();
let text_repr = format!("{}", pos);
assert_eq!(text_repr, "2:0");
}
#[test]
fn debug_print() {
let mut pos = InsertPosition::default();
pos.inc_col();
pos.inc_line();
let text_repr = format!("{:?}", pos);
assert_eq!(text_repr, "2:0");
}
#[test]
fn ordering_and_eq() {
let mut pos1 = InsertPosition::default();
pos1.inc_col();
pos1.inc_line();
pos1.inc_col();
let mut pos2 = pos1.clone();
pos2.inc_line();
let pos3 = pos2.clone();
assert!(pos2 > pos1);
assert_eq!(pos2, pos3);
}
#[test]
fn parsing() {
assert_eq!("4:7".parse(), Ok(InsertPosition::new(4, 7)));
assert_eq!("1:0".parse(), Ok(InsertPosition::new(1, 0)));
assert_eq!("1:-9".parse::<InsertPosition>(), Err(()));
assert_eq!("0:6".parse::<InsertPosition>(), Err(()));
}
}