use core::convert::{AsMut, AsRef};
use core::error::Error;
use core::fmt::{Debug, Display, Formatter};
use core::ops::ControlFlow;
use core::write;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd)]
pub struct Position {
r: u32,
c: u32,
}
impl Position {
#[must_use]
pub const fn line(&self) -> u32 {
self.r
}
#[must_use]
pub const fn column(&self) -> u32 {
self.c
}
#[must_use]
pub const fn unpack(self) -> (u32, u32) {
(self.r, self.c)
}
#[must_use]
pub const fn new(line: u32, column: u32) -> Self {
Self { r: line, c: column }
}
#[must_use]
pub const fn new_zero() -> Self {
Self::new(0, 0)
}
}
impl Display for Position {
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(fmt, "Line: {}, column: {}", self.r, self.c)
}
}
impl Default for Position {
fn default() -> Self {
Self::new_zero()
}
}
pub trait Posable {
fn get_pos(&self) -> Position;
fn line(&self) -> u32 {
self.get_pos().r
}
fn column(&self) -> u32 {
self.get_pos().c
}
}
pub trait PosableMut: Posable {
fn get_pos_mut(&mut self) -> &mut Position;
fn progress(&mut self, nrow: i32, ncol: i32) {
let pos = self.get_pos_mut();
pos.r = pos.r.saturating_add_signed(nrow);
pos.c = pos.c.saturating_add_signed(ncol);
}
fn seek_start(&mut self) {
*self.get_pos_mut() = Position::new_zero();
}
}
impl<T, E> Posable for Result<T, E>
where
T: Posable,
E: Posable,
{
fn get_pos(&self) -> Position {
match self {
Ok(e) => e.get_pos(),
Err(e) => e.get_pos(),
}
}
}
impl<T, E> PosableMut for Result<T, E>
where
T: PosableMut,
E: PosableMut,
{
fn get_pos_mut(&mut self) -> &mut Position {
match self {
Ok(e) => e.get_pos_mut(),
Err(e) => e.get_pos_mut(),
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Pos<T> {
el: T,
pos: Position,
}
impl<T> AsRef<T> for Pos<T> {
fn as_ref(&self) -> &T {
&self.el
}
}
impl<T> AsMut<T> for Pos<T> {
fn as_mut(&mut self) -> &mut T {
&mut self.el
}
}
impl<T> Display for Pos<T>
where
T: Display,
{
fn fmt(&self, fmt: &mut Formatter<'_>) -> core::fmt::Result {
write!(fmt, "{}: {}", self.pos, self.el)
}
}
impl<T> Error for Pos<T>
where
T: Error,
{
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.el.source()
}
}
impl<T> Posable for Pos<T> {
fn get_pos(&self) -> Position {
self.pos
}
}
impl<T> PosableMut for Pos<T> {
fn get_pos_mut(&mut self) -> &mut Position {
&mut self.pos
}
}
impl<T> Pos<T> {
pub const fn new(el: T, pos: Position) -> Self {
Self { el, pos }
}
pub const fn new_pos(el: T, line: u32, column: u32) -> Self {
Self {
el,
pos: Position { r: line, c: column },
}
}
pub fn take(self) -> T {
self.el
}
pub fn take_pos(self) -> Position {
self.pos
}
pub fn take_all(self) -> (T, Position) {
(self.el, self.pos)
}
pub fn test<TF: FnOnce(&T) -> bool>(&self, f: TF) -> bool {
f(&self.el)
}
pub fn test_pos<TF: FnOnce(&T, &Position) -> bool>(&self, f: TF) -> bool {
f(&self.el, &self.pos)
}
pub fn map<U, MF: FnOnce(T) -> U>(self, f: MF) -> Pos<U> {
Pos {
el: f(self.el),
pos: self.pos,
}
}
pub fn map_pos<U, MF: FnOnce(T, Position) -> (U, Position)>(self, f: MF) -> Pos<U> {
let (nel, npos) = f(self.el, self.pos);
Pos { el: nel, pos: npos }
}
pub const fn make_ref(&self) -> Pos<&T> {
Pos {
el: &(self.el),
pos: self.pos,
}
}
pub const fn make_mut(&mut self) -> Pos<&mut T> {
Pos {
el: &mut (self.el),
pos: self.pos,
}
}
}
impl<T, E> Pos<Result<T, E>> {
pub fn branch(self) -> ControlFlow<Pos<Result<core::convert::Infallible, E>>, Pos<T>> {
let pos = self.pos;
match self.el {
Ok(t) => ControlFlow::Continue(Pos { el: t, pos }),
Err(e) => ControlFlow::Break(Pos { el: Err(e), pos }),
}
}
#[allow(clippy::missing_errors_doc)]
pub fn throw(self) -> Result<Pos<T>, Pos<E>> {
let pos = self.pos;
match self.el {
Ok(t) => Ok(Pos { el: t, pos }),
Err(e) => Err(Pos { el: e, pos }),
}
}
#[allow(clippy::missing_errors_doc)]
pub fn throw_el(self) -> Result<Pos<T>, E> {
match self.el {
Ok(el) => Ok(Pos { el, pos: self.pos }),
Err(e) => Err(e),
}
}
#[allow(clippy::missing_errors_doc)]
pub fn throw_err(self) -> Result<T, Pos<E>> {
match self.el {
Ok(t) => Ok(t),
Err(el) => Err(Pos { el, pos: self.pos }),
}
}
}