use core::convert::{AsRef, AsMut};
use core::ops::ControlFlow;
use core::fmt::{Formatter, Display, Debug};
use core::error::Error;
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}),
}
}
}
#[cfg(feature = "nightly-features")]
impl<T> core::ops::Try for Pos<T> where T : core::ops::Try {
type Output = Pos<T::Output>;
type Residual = Pos<T::Residual>;
fn from_output(output : Self::Output) -> Self {
Self{
el : T::from_output(output.el),
pos : output.pos
}
}
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
match self.el.branch() {
ControlFlow::Break(e) => ControlFlow::Break(Pos::new(e, self.pos)),
ControlFlow::Continue(e) => ControlFlow::Continue(Pos::new(e, self.pos))
}
}
}
#[cfg(feature = "nightly-features")]
impl<T, R> core::ops::FromResidual<Pos<R>> for Pos<T> where T : core::ops::FromResidual<R> {
fn from_residual(output : Pos<R>) -> Self {
Self{
el : T::from_residual(output.el),
pos : output.pos
}
}
}
#[cfg(feature = "nightly-features")]
impl<T, R> core::ops::Residual<Pos<R>> for Pos<T> where T : core::ops::Residual<R> {
type TryType = Pos<T::TryType>;
}