indented_blocks/
view.rs

1/*!
2 * This module provides support for [`View`]s, which provide a
3 * reference-mapping functionality to support simple, zero-copy
4 * use cases, which require a mapping of `head` values.
5 * This is especially useful if the mapping itself either has
6 * only a rather small overhead or the resulting [`View`] is only
7 * traversed once.
8 */
9
10use crate::Block;
11use alloc::string::{String, ToString};
12
13#[derive(Debug)]
14pub struct View<'ast, S, F> {
15    parent: &'ast Block<S>,
16    mapping: F,
17}
18
19impl<S, F: Clone> Clone for View<'_, S, F> {
20    #[inline]
21    fn clone(&self) -> Self {
22        Self {
23            parent: self.parent,
24            mapping: self.mapping.clone(),
25        }
26    }
27}
28
29impl<S, F: Copy> Copy for View<'_, S, F> {}
30
31impl<'ast, S, F> View<'ast, S, F> {
32    #[inline]
33    pub const fn new(parent: &'ast Block<S>, mapping: F) -> Self {
34        Self { parent, mapping }
35    }
36}
37
38#[derive(Clone, Copy)]
39pub struct MapViewFn<F1, F2> {
40    f1: F1,
41    f2: F2,
42}
43
44/// helper trait to create namable closures
45pub trait ViewFn<S> {
46    type Output: Sized;
47
48    fn view(&self, node: S) -> Self::Output;
49}
50
51impl<S> ViewFn<S> for () {
52    type Output = S;
53
54    #[inline]
55    fn view(&self, node: S) -> S {
56        node
57    }
58}
59
60impl<S, F, O> ViewFn<S> for F
61where
62    F: Fn(S) -> O,
63{
64    type Output = O;
65
66    #[inline]
67    fn view(&self, node: S) -> O {
68        (self)(node)
69    }
70}
71
72impl<S, F: ViewFn<S>> ViewFn<S> for alloc::rc::Rc<F> {
73    type Output = F::Output;
74    #[inline]
75    fn view(&self, node: S) -> F::Output {
76        (&**self).view(node)
77    }
78}
79impl<S, F: ViewFn<S>> ViewFn<S> for alloc::sync::Arc<F> {
80    type Output = F::Output;
81    #[inline]
82    fn view(&self, node: S) -> F::Output {
83        (&**self).view(node)
84    }
85}
86
87impl<S, F1, F2, O> ViewFn<S> for MapViewFn<F1, F2>
88where
89    F1: ViewFn<S>,
90    F2: Fn(F1::Output) -> O,
91{
92    type Output = O;
93
94    #[inline]
95    fn view(&self, node: S) -> O {
96        (self.f2)(self.f1.view(node))
97    }
98}
99
100impl<'ast, S: 'ast, F> View<'ast, S, F>
101where
102    F: ViewFn<&'ast S>,
103{
104    #[inline]
105    pub fn head(&self) -> F::Output {
106        self.mapping.view(&self.parent.head)
107    }
108
109    #[inline]
110    pub fn map<F2, O2>(self, f2: F2) -> View<'ast, S, MapViewFn<F, F2>>
111    where
112        F2: Fn(F::Output) -> O2,
113    {
114        let View { parent, mapping } = self;
115        View {
116            parent,
117            mapping: MapViewFn { f1: mapping, f2 },
118        }
119    }
120}
121
122impl<'ast, S: 'ast, F> View<'ast, S, F>
123where
124    F: Clone + ViewFn<&'ast S>,
125{
126    #[inline]
127    pub fn subs(
128        &self,
129    ) -> core::iter::Map<
130        core::slice::Iter<'ast, Block<S>>,
131        impl Fn(&'ast Block<S>) -> View<'ast, S, F>,
132    > {
133        let mapping = self.mapping.clone();
134        let imapf = move |parent: &'ast Block<S>| View {
135            parent,
136            mapping: mapping.clone(),
137        };
138        self.parent.subs.iter().map(imapf)
139    }
140}
141
142impl<'ast, S: 'ast, F> View<'ast, S, F>
143where
144    F: Clone + ViewFn<&'ast S>,
145    F::Output: ToString,
146{
147    pub(crate) fn append_to_string(
148        &self,
149        ret: &mut String,
150        single_indent: &str,
151        upper_indent_factor: u32,
152    ) {
153        for _ in 0..upper_indent_factor {
154            ret.push_str(single_indent);
155        }
156        *ret += &self.head().to_string();
157        ret.push('\n');
158        let next_luif = upper_indent_factor + 1;
159        for i in self.subs() {
160            i.append_to_string(ret, single_indent, next_luif);
161        }
162    }
163}