1use std::{
4 any::Any,
5 cell::{Ref, RefCell, RefMut},
6 fmt::{self, Display},
7 rc::Rc,
8};
9
10use rustc_hash::FxHashMap;
11
12use crate::{common_traits::RcShare, context::Context, identifier::Identifier};
13
14struct StateInner {
15 indent_width: u16,
17 cur_indent: u16,
19 aux_data: FxHashMap<Identifier, Box<dyn Any>>,
21}
22
23impl Default for StateInner {
24 fn default() -> Self {
25 Self {
26 indent_width: 2,
27 cur_indent: 0,
28 aux_data: FxHashMap::default(),
29 }
30 }
31}
32
33#[derive(Default)]
35pub struct State(Rc<RefCell<StateInner>>);
36
37impl RcShare for State {
38 fn share(&self) -> Self {
39 State(Rc::clone(&self.0))
40 }
41}
42
43impl State {
44 pub fn indent_width(&self) -> u16 {
46 self.0.as_ref().borrow().indent_width
47 }
48
49 pub fn set_indent_width(&self, indent_width: u16) {
51 self.0.as_ref().borrow_mut().indent_width = indent_width;
52 }
53
54 pub fn current_indent(&self) -> u16 {
56 self.0.as_ref().borrow().cur_indent
57 }
58
59 pub fn push_indent(&self) {
61 let mut inner = self.0.as_ref().borrow_mut();
62 inner.cur_indent += inner.indent_width;
63 }
64
65 pub fn pop_indent(&self) {
67 let mut inner = self.0.as_ref().borrow_mut();
68 inner.cur_indent -= inner.indent_width;
69 }
70
71 pub fn aux_data_ref(&self) -> Ref<'_, FxHashMap<Identifier, Box<dyn Any>>> {
74 Ref::map(self.0.borrow(), |inner| &inner.aux_data)
75 }
76
77 pub fn aux_data_mut(&self) -> RefMut<'_, FxHashMap<Identifier, Box<dyn Any>>> {
80 RefMut::map(self.0.borrow_mut(), |inner| &mut inner.aux_data)
81 }
82}
83
84#[macro_export]
89macro_rules! indented_block {
90 ($state:ident, { $($tt:tt)* }) => {
91 $state.push_indent();
92 $($tt)*
93 $state.pop_indent();
94 }
95}
96
97struct Displayable<'t, 'c, T: Printable + ?Sized> {
99 t: &'t T,
100 ctx: &'c Context,
101 state: State,
102}
103
104impl<T: Printable + ?Sized> Display for Displayable<'_, '_, T> {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 self.t.fmt(self.ctx, &self.state, f)
107 }
108}
109
110pub trait Printable {
141 fn fmt(&self, ctx: &Context, state: &State, f: &mut fmt::Formatter<'_>) -> fmt::Result;
142
143 fn disp<'t, 'c>(&'t self, ctx: &'c Context) -> Box<dyn Display + 'c>
145 where
146 't: 'c,
147 {
148 self.print(ctx, &State::default())
149 }
150
151 fn print<'t, 'c>(&'t self, ctx: &'c Context, state: &State) -> Box<dyn Display + 'c>
153 where
154 't: 'c,
155 {
156 Box::new(Displayable {
157 t: self,
158 ctx,
159 state: state.share(),
160 })
161 }
162}
163#[macro_export]
175macro_rules! impl_printable_for_display {
176 ($ty_name:ty) => {
177 impl $crate::printable::Printable for $ty_name {
178 fn fmt(
179 &self,
180 _ctx: &pliron::context::Context,
181 _state: &pliron::printable::State,
182 f: &mut std::fmt::Formatter<'_>,
183 ) -> std::fmt::Result {
184 write!(f, "{}", self)
185 }
186 }
187 };
188}
189
190impl_printable_for_display!(&str);
191impl_printable_for_display!(String);
192impl_printable_for_display!(usize);
193impl_printable_for_display!(u64);
194impl_printable_for_display!(u32);
195impl_printable_for_display!(i64);
196impl_printable_for_display!(i32);
197impl_printable_for_display!(bool);
198impl_printable_for_display!(char);
199
200impl<T: Printable + ?Sized> Printable for &T {
201 fn fmt(&self, ctx: &Context, state: &State, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 (*self).fmt(ctx, state, f)
203 }
204}
205
206#[derive(Clone, Copy)]
207pub enum ListSeparator {
209 None,
211 Newline,
213 CharNewline(char),
215 Char(char),
217 CharSpace(char),
219}
220
221impl Printable for ListSeparator {
222 fn fmt(&self, _ctx: &Context, state: &State, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 match self {
224 ListSeparator::None => Ok(()),
225 ListSeparator::Newline => fmt_indented_newline(state, f),
226 ListSeparator::CharNewline(c) => {
227 write!(f, "{c}")?;
228 fmt_indented_newline(state, f)
229 }
230 ListSeparator::Char(c) => write!(f, "{c}"),
231 ListSeparator::CharSpace(c) => write!(f, "{c} "),
232 }
233 }
234}
235
236pub fn fmt_iter<I>(
238 mut iter: I,
239 ctx: &Context,
240 state: &State,
241 sep: ListSeparator,
242 f: &mut fmt::Formatter<'_>,
243) -> fmt::Result
244where
245 I: Iterator,
246 I::Item: Printable,
247{
248 if let Some(first) = iter.next() {
249 first.fmt(ctx, state, f)?;
250 }
251 for item in iter {
252 sep.fmt(ctx, state, f)?;
253 item.fmt(ctx, state, f)?;
254 }
255 Ok(())
256}
257
258pub fn fmt_indented_newline(state: &State, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260 let align = state.current_indent().into();
261 write!(f, "\n{:>align$}", "")?;
262 Ok(())
263}
264
265struct IndentedNewliner {
266 state: State,
267}
268
269impl Display for IndentedNewliner {
270 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
271 fmt_indented_newline(&self.state, f)
272 }
273}
274
275pub fn indented_nl(state: &State) -> impl Display {
277 IndentedNewliner {
278 state: state.share(),
279 }
280}