use crate::pos::Position;
#[derive(Debug, Clone, Copy)]
pub struct View<'a> {
pub(crate) view: &'a str,
pub(crate) pos: Position,
}
#[derive(Debug, Clone, Copy)]
struct CursorData<'a, D> {
pub(crate) view: &'a str,
pos: Position,
pub(crate) data: D,
}
#[must_use]
fn progress(pos: Position, view: &str, inc: usize) -> (&str, Position, &str) {
if inc == 0 {
("", pos, view)
} else {
let (pfx, sfx) = view.split_at(inc);
let mut fit = pfx.split('\n');
let mut elem = fit.next().unwrap(); let mut nls = 0;
for el in fit {
elem = el;
nls += 1;
}
let (mut r, mut c) = pos.unpack();
if nls > 0 {
c = 0;
r += nls;
}
c += u32::try_from(elem.len()).unwrap();
(pfx, Position::new(r, c), sfx)
}
}
#[derive(Debug, Clone, Copy)]
pub struct CursorStart<'a>(CursorData<'a, ()>);
#[derive(Debug, Clone, Copy)]
pub struct CursorLen<'a, D> {
this: CursorData<'a, D>,
len: usize,
}
pub type Cursor<'a> = CursorLen<'a, ()>;
pub trait Tool<'a> {
type Error;
type Data;
fn parse(&self, st: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error>;
fn map<D, F: Fn(Self::Data) -> D>(self, f: F) -> MapData<D, Self, F>
where
Self: Sized,
{
MapData(self, f, core::marker::PhantomData)
}
}
pub trait AlwaysTool<'a>: Tool<'a> {
fn parse_always(&self, st: CursorStart<'a>) -> CursorLen<'a, Self::Data>;
fn parse_always_nodata(&self, st: CursorStart<'a>) -> CursorLen<'a, ()> {
self.parse_always(st).map_data(|_| ())
}
fn set_error<E>(self) -> SetError<E, Self>
where
Self: Sized,
{
SetError(self, core::marker::PhantomData)
}
}
impl<'a, D, DI> From<CursorData<'a, D>> for CursorLen<'a, DI>
where
D: Into<DI>,
{
fn from(v: CursorData<'a, D>) -> Self {
Self {
this: CursorData {
view: v.view,
pos: v.pos,
data: v.data.into(),
},
len: 0,
}
}
}
impl<'a> From<CursorStart<'a>> for CursorLen<'a, ()> {
fn from(v: CursorStart<'a>) -> Self {
v.0.into()
}
}
impl<'a> From<&'a str> for CursorLen<'a, ()> {
fn from(s: &'a str) -> Self {
Self {
len: 0,
this: CursorData {
data: (),
view: s,
pos: Position::new_zero(),
},
}
}
}
impl<'a, D> CursorLen<'a, D> {
pub const fn get_pos(self) -> (Position, Self) {
(self.this.pos, self)
}
pub const fn get_view(self) -> (&'a str, Self) {
(self.this.view, self)
}
pub fn map_data<DD, F: FnOnce(D) -> DD>(self, f: F) -> CursorLen<'a, DD> {
CursorLen {
len: self.len,
this: CursorData {
view: self.this.view,
pos: self.this.pos,
data: f(self.this.data),
},
}
}
#[allow(clippy::missing_errors_doc)]
pub fn try_map_data<DD, E, F: FnOnce(D) -> Result<DD, E>>(
self,
f: F,
) -> Result<CursorLen<'a, DD>, E> {
Ok(CursorLen {
len: self.len,
this: CursorData {
view: self.this.view,
pos: self.this.pos,
data: f(self.this.data)?,
},
})
}
pub fn opt_map_data<DD, F: FnOnce(D) -> Option<DD>>(self, f: F) -> Option<CursorLen<'a, DD>> {
Some(CursorLen {
len: self.len,
this: CursorData {
view: self.this.view,
pos: self.this.pos,
data: f(self.this.data)?,
},
})
}
pub fn get_data(self) -> (D, CursorLen<'a, ()>) {
(
self.this.data,
CursorLen {
len: self.len,
this: CursorData {
view: self.this.view,
pos: self.this.pos,
data: (),
},
},
)
}
#[allow(clippy::missing_errors_doc)]
pub fn chain_replace<T>(self, t: &T) -> Result<CursorLen<'a, T::Data>, T::Error>
where
T: Tool<'a> + ?Sized,
{
self.chain_map(t, |_, b, _| b)
}
#[allow(clippy::missing_errors_doc)]
pub fn chain_nodata<T>(self, t: &T) -> Result<Self, T::Error>
where
T: Tool<'a> + ?Sized,
{
self.chain_map(t, |a, _, _| a)
}
#[allow(clippy::missing_errors_doc)]
pub fn chain_save<T>(self, t: &T) -> Result<CursorLen<'a, (D, T::Data)>, T::Error>
where
T: Tool<'a> + ?Sized,
{
self.chain_map(t, |a, b, _| (a, b))
}
#[allow(clippy::missing_errors_doc)]
pub fn chain_save_out<T>(self, t: &T) -> Result<(Self, T::Data), T::Error>
where
T: Tool<'a> + ?Sized,
{
let ret = self.chain_save(t)?;
Ok((
CursorLen {
len: ret.len,
this: CursorData {
view: ret.this.view,
pos: ret.this.pos,
data: ret.this.data.0,
},
},
ret.this.data.1,
))
}
#[allow(clippy::missing_errors_doc)]
pub fn chain_save_at<T>(self, t: &T, to: &mut T::Data) -> Result<Self, T::Error>
where
T: Tool<'a> + ?Sized,
{
self.chain_map(t, |a, b, _| {
*to = b;
a
})
}
pub(crate) fn chain_map<T, F, O>(self, t: &T, f: F) -> Result<CursorLen<'a, O>, T::Error>
where
T: Tool<'a> + ?Sized,
F: FnOnce(D, T::Data, usize) -> O,
{
let c = CursorStart(CursorData {
view: self.this.view,
pos: self.this.pos,
data: (),
});
t.parse(c).map(|cnew| CursorLen {
len: self.len + cnew.len,
this: CursorData {
view: cnew.this.view,
pos: cnew.this.pos,
data: f(self.this.data, cnew.this.data, cnew.len),
},
})
}
#[allow(clippy::missing_errors_doc)]
pub fn always_replace<T>(self, t: &T) -> CursorLen<'a, T::Data>
where
T: AlwaysTool<'a> + ?Sized,
{
self.always_map(t, |_, b, _| b)
}
#[allow(clippy::missing_errors_doc)]
#[must_use]
pub fn always_nodata<T>(self, t: &T) -> Self
where
T: AlwaysTool<'a> + ?Sized,
{
self.always_map(t, |a, _, _| a)
}
#[allow(clippy::missing_errors_doc)]
pub fn always_save<T>(self, t: &T) -> CursorLen<'a, (D, T::Data)>
where
T: AlwaysTool<'a> + ?Sized,
{
self.always_map(t, |a, b, _| (a, b))
}
#[allow(clippy::missing_errors_doc)]
pub fn always_save_out<T>(self, t: &T) -> (Self, T::Data)
where
T: AlwaysTool<'a> + ?Sized,
{
let ret = self.always_save(t);
(
CursorLen {
len: ret.len,
this: CursorData {
view: ret.this.view,
pos: ret.this.pos,
data: ret.this.data.0,
},
},
ret.this.data.1,
)
}
#[allow(clippy::missing_errors_doc)]
#[must_use]
pub fn always_save_at<T>(self, t: &T, to: &mut T::Data) -> Self
where
T: AlwaysTool<'a> + ?Sized,
{
self.always_map(t, |a, b, _| {
*to = b;
a
})
}
pub(crate) fn always_map<T, F, O>(self, t: &T, f: F) -> CursorLen<'a, O>
where
T: AlwaysTool<'a> + ?Sized,
F: FnOnce(D, T::Data, usize) -> O,
{
let c = CursorStart(CursorData {
view: self.this.view,
pos: self.this.pos,
data: (),
});
let cnew = t.parse_always(c);
CursorLen {
len: self.len + cnew.len,
this: CursorData {
view: cnew.this.view,
pos: cnew.this.pos,
data: f(self.this.data, cnew.this.data, cnew.len),
},
}
}
}
impl<'a> CursorStart<'a> {
#[must_use]
pub fn into_clen(self) -> CursorLen<'a, ()> {
self.into()
}
}
impl<'a> CursorLen<'a, ()> {
#[allow(clippy::missing_errors_doc)]
pub fn chain<T>(self, t: &T) -> Result<CursorLen<'a, T::Data>, T::Error>
where
T: Tool<'a> + ?Sized,
{
self.chain_replace(t)
}
pub fn always<T>(self, t: &T) -> CursorLen<'a, T::Data>
where
T: AlwaysTool<'a> + ?Sized,
{
self.always_replace(t)
}
#[allow(clippy::missing_errors_doc)]
pub fn chain_err<T>(self, t: &T) -> Result<CursorLen<'a, T::Data>, Self>
where
T: Tool<'a> + ?Sized,
{
self.chain(t).map_err(|_| self)
}
}
impl<'a> View<'a> {
#[must_use]
pub const fn new(view: &'a str) -> Self {
Self {
view,
pos: Position::new_zero(),
}
}
#[must_use]
pub const fn get_view(&self) -> &'a str {
self.view
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.view.is_empty()
}
#[must_use]
pub const fn top_position(&self) -> &Position {
&self.pos
}
#[must_use]
pub const fn into_pos(self) -> Position {
self.pos
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct GetStr<T>(pub T);
impl<'a, T> Tool<'a> for GetStr<T>
where
T: Tool<'a>,
{
type Data = &'a str;
type Error = T::Error;
fn parse(&self, c: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
let cnew = c.into_clen().chain_nodata(&self.0)?;
let l = cnew.len;
Ok(cnew.map_data(|()| &c.0.view[0..l]))
}
}
impl<'a, T> AlwaysTool<'a> for GetStr<T>
where
T: AlwaysTool<'a>,
{
fn parse_always(&self, c: CursorStart<'a>) -> CursorLen<'a, Self::Data> {
let cnew = c.into_clen().always_nodata(&self.0);
let l = cnew.len;
cnew.map_data(|()| &c.0.view[0..l])
}
}
#[macro_export]
macro_rules! always_impl {
($i:ident) => {
always_impl!($i, ());
};
($i:ident, $t:ty) => {
impl<'a> Tool<'a> for $i {
type Error = core::convert::Infallible;
type Data = $t;
fn parse(&self, st: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
Ok(self.parse_always(st))
}
}
};
}
impl<'a, T> Tool<'a> for &T
where
T: Tool<'a> + ?Sized,
{
type Error = T::Error;
type Data = T::Data;
fn parse(&self, st: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
T::parse(*self, st)
}
}
impl<'a, T> AlwaysTool<'a> for &T
where
T: AlwaysTool<'a> + ?Sized,
{
fn parse_always(&self, st: CursorStart<'a>) -> CursorLen<'a, Self::Data> {
T::parse_always(*self, st)
}
}
#[derive(Debug)]
pub struct SetError<E, T>(pub T, pub core::marker::PhantomData<fn() -> E>);
impl<E, T: Clone> Clone for SetError<E, T> {
fn clone(&self) -> Self {
Self(self.0.clone(), core::marker::PhantomData)
}
}
impl<E, T: Copy> Copy for SetError<E, T> {}
impl<E, T: Default> Default for SetError<E, T> {
fn default() -> Self {
Self(T::default(), core::marker::PhantomData)
}
}
impl<'a, E, T> Tool<'a> for SetError<E, T>
where
T: AlwaysTool<'a>,
{
type Data = T::Data;
type Error = E;
fn parse(&self, c: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
Ok(self.0.parse_always(c))
}
}
#[derive(Debug)]
pub struct MapData<D, T, CD>(pub T, pub CD, pub core::marker::PhantomData<fn() -> D>);
impl<D, CD: Clone, T: Clone> Clone for MapData<D, T, CD> {
fn clone(&self) -> Self {
Self(self.0.clone(), self.1.clone(), core::marker::PhantomData)
}
}
impl<D, CD: Copy, T: Copy> Copy for MapData<D, T, CD> {}
impl<D, CD: Default, T: Default> Default for MapData<D, T, CD> {
fn default() -> Self {
Self(T::default(), CD::default(), core::marker::PhantomData)
}
}
impl<'a, D, CD, T> Tool<'a> for MapData<D, T, CD>
where
T: Tool<'a>,
CD: Fn(T::Data) -> D,
{
type Data = D;
type Error = T::Error;
fn parse(&self, c: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
self.0.parse(c).map(|d| d.map_data(&self.1))
}
}
#[derive(Debug, Copy, Clone, Default)]
pub struct AnyChar;
impl<'a> Tool<'a> for AnyChar {
type Data = char;
type Error = Cursor<'a>;
fn parse(&self, st: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
st.0.view.chars().next().map_or_else(
|| Err(Cursor::from(st)),
|c| {
let (_, pos, view) = progress(st.0.pos, st.0.view, c.len_utf8());
Ok(CursorLen {
len: c.len_utf8(),
this: CursorData { data: c, pos, view },
})
},
)
}
}
impl<'a> Tool<'a> for char {
type Error = Cursor<'a>;
type Data = Self;
fn parse(&self, st: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
AnyChar.parse(st).and_then(|ret| {
if ret.this.data == *self {
Ok(ret)
} else {
Err(Cursor::from(st))
}
})
}
}
impl<'a> Tool<'a> for str {
type Error = Cursor<'a>;
#[allow(clippy::needless_borrows_for_generic_args, clippy::use_self)]
type Data = &'a str;
fn parse(&self, st: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
if st.0.view.starts_with(self) {
let (_, pos, view) = progress(st.0.pos, st.0.view, self.len());
Ok(CursorLen {
len: self.len(),
this: CursorData {
data: &st.0.view[0..self.len()],
view,
pos,
},
})
} else {
Err(Cursor::from(st))
}
}
}
impl<'a, T> Tool<'a> for [T]
where
T: Tool<'a>,
{
type Data = (usize, T::Data);
type Error = Option<T::Error>;
fn parse(&self, st: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
let mut err = None;
for (i, t) in self.iter().enumerate() {
match t.parse(st) {
Ok(r) => return Ok(r.map_data(|d| (i, d))),
Err(e) => err = Some(e),
}
}
Err(err)
}
}
impl<'a, T, const N: usize> Tool<'a> for [T; N]
where
T: Tool<'a>,
{
type Data = (usize, T::Data);
type Error = Option<T::Error>;
fn parse(&self, st: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
let mut err = None;
for (i, t) in self.iter().enumerate() {
match t.parse(st) {
Ok(r) => return Ok(r.map_data(|d| (i, d))),
Err(e) => err = Some(e),
}
}
Err(err)
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
pub struct TrueTool;
impl<'a> AlwaysTool<'a> for TrueTool {
fn parse_always(&self, st: CursorStart<'a>) -> CursorLen<'a, Self::Data> {
st.into()
}
}
always_impl!(TrueTool);
#[derive(Debug, Clone, Copy)]
pub struct Predicate<P> {
pub(crate) predicate: P,
}
impl<P> Predicate<P> {
pub const fn new(predicate: P) -> Self {
Self { predicate }
}
}
impl<'a, P: Fn(char) -> bool> Tool<'a> for Predicate<P> {
type Data = char;
type Error = Cursor<'a>;
fn parse(&self, st: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
AnyChar.parse(st).and_then(|ret| {
if (self.predicate)(ret.this.data) {
Ok(ret)
} else {
Err(st.into())
}
})
}
}
#[derive(Debug, Clone, Copy)]
pub struct PredicateData<P> {
pub(crate) predicate: P,
}
impl<P> PredicateData<P> {
pub const fn new(predicate: P) -> Self {
Self { predicate }
}
}
impl<'a, D, P: Fn(char) -> Option<D>> Tool<'a> for PredicateData<P> {
type Data = (D, usize);
type Error = Cursor<'a>;
fn parse(&self, st: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
AnyChar.parse(st).and_then(|ret| {
ret.try_map_data(|c| {
(self.predicate)(c)
.map(|d| (d, c.len_utf8()))
.ok_or_else(|| st.into())
})
})
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct EOFTool;
impl<'a> Tool<'a> for EOFTool {
type Data = ();
type Error = CursorStart<'a>;
fn parse(&self, st: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
if st.0.view.is_empty() {
Ok(st.into())
} else {
Err(st)
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct NonEmpty<P>(pub P);
impl<'a, P> Tool<'a> for NonEmpty<P>
where
P: Tool<'a>,
{
type Data = P::Data;
type Error = Option<P::Error>;
fn parse(&self, st: CursorStart<'a>) -> Result<CursorLen<'a, Self::Data>, Self::Error> {
self.0
.parse(st)
.map_err(Some)
.and_then(|d| if d.len > 0 { Ok(d) } else { Err(None) })
}
}