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<S> {
type Output: Sized;
fn view(&self, node: S) -> Self::Output;
}
impl<S> ViewFn<S> for () {
type Output = S;
#[inline]
fn view(&self, node: S) -> S {
node
}
}
impl<S, F, O> ViewFn<S> for F
where
F: Fn(S) -> O,
{
type Output = O;
#[inline]
fn view(&self, node: S) -> O {
(self)(node)
}
}
impl<S, F: ViewFn<S>> ViewFn<S> for alloc::rc::Rc<F> {
type Output = F::Output;
#[inline]
fn view(&self, node: S) -> F::Output {
(&**self).view(node)
}
}
impl<S, F: ViewFn<S>> ViewFn<S> for alloc::sync::Arc<F> {
type Output = F::Output;
#[inline]
fn view(&self, node: S) -> F::Output {
(&**self).view(node)
}
}
impl<S, F1, F2, O> ViewFn<S> for MapViewFn<F1, F2>
where
F1: ViewFn<S>,
F2: Fn(F1::Output) -> O,
{
type Output = O;
#[inline]
fn view(&self, node: S) -> O {
(self.f2)(self.f1.view(node))
}
}
impl<'ast, S: 'ast, 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: MapViewFn { f1: mapping, f2 },
}
}
}
impl<'ast, S: 'ast, 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: 'ast, 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);
}
}
}