use crate::Block;
use alloc::string::{String, ToString};
#[derive(Debug)]
pub struct View<'ast, S, F> {
parent: &'ast Block<S>,
mapping: F,
}
impl<S, F: Clone> Clone for View<'_, S, F> {
#[inline]
fn clone(&self) -> Self {
Self {
parent: self.parent,
mapping: self.mapping.clone(),
}
}
}
impl<S, F: Copy> Copy for View<'_, S, F> {}
impl<'ast, S, F> View<'ast, S, F> {
#[inline]
pub const fn new(parent: &'ast Block<S>, mapping: F) -> Self {
Self { parent, mapping }
}
}
#[derive(Clone, Copy)]
pub struct MapViewFn<F1, F2> {
f1: F1,
f2: F2,
}
pub trait ViewFn<'ast, S: 'ast> {
type Output: Sized;
fn view(&self, node: &'ast S) -> Self::Output;
#[inline]
fn map<F2, O2>(self, f2: F2) -> MapViewFn<Self, F2>
where
Self: Sized,
F2: Fn(Self::Output) -> O2,
{
MapViewFn { f1: self, f2 }
}
}
impl<'ast, S: 'ast> ViewFn<'ast, S> for () {
type Output = &'ast S;
#[inline]
fn view(&self, node: &'ast S) -> &'ast S {
node
}
}
impl<'ast, S, F, O> ViewFn<'ast, S> for F
where
S: 'ast,
F: Fn(&'ast S) -> O,
{
type Output = O;
#[inline]
fn view(&self, node: &'ast S) -> O {
(self)(node)
}
}
impl<'ast, S, F1, F2, O> ViewFn<'ast, S> for MapViewFn<F1, F2>
where
S: 'ast,
F1: ViewFn<'ast, S>,
F2: Fn(F1::Output) -> O,
{
type Output = O;
#[inline]
fn view(&self, node: &'ast S) -> O {
(self.f2)(self.f1.view(node))
}
}
impl<'ast, S, F> View<'ast, S, F>
where
F: ViewFn<'ast, S>,
{
#[inline]
pub fn head(&self) -> F::Output {
self.mapping.view(&self.parent.head)
}
#[inline]
pub fn map<F2, O2>(self, f2: F2) -> View<'ast, S, MapViewFn<F, F2>>
where
F2: Fn(F::Output) -> O2,
{
let View { parent, mapping } = self;
View {
parent,
mapping: mapping.map(f2),
}
}
}
impl<'ast, S, F> View<'ast, S, F>
where
F: Clone + ViewFn<'ast, S>,
{
#[inline]
pub fn subs(
&self,
) -> core::iter::Map<
core::slice::Iter<'ast, Block<S>>,
impl Fn(&'ast Block<S>) -> View<'ast, S, F>,
> {
let mapping = self.mapping.clone();
let imapf = move |parent: &'ast Block<S>| View {
parent,
mapping: mapping.clone(),
};
self.parent.subs.iter().map(imapf)
}
}
impl<'ast, S, F> View<'ast, S, F>
where
F: Clone + ViewFn<'ast, S>,
F::Output: ToString,
{
pub(crate) fn append_to_string(
&self,
ret: &mut String,
single_indent: &str,
upper_indent_factor: u32,
) {
for _ in 0..upper_indent_factor {
ret.push_str(single_indent);
}
*ret += &self.head().to_string();
ret.push('\n');
let next_luif = upper_indent_factor + 1;
for i in self.subs() {
i.append_to_string(ret, single_indent, next_luif);
}
}
}