1use std::fmt::{Display, Write};
4
5const INDENTATION: &str = {
7 match option_env!("CONLANG_INDENT") {
8 Some(indent) => indent,
9 None => " ",
10 }
11};
12
13impl<W: Write + ?Sized> FmtAdapter for W {}
14pub trait FmtAdapter: Write {
15 fn indent(&mut self) -> Indent<'_, Self> {
17 Indent::new(self, INDENTATION)
18 }
19
20 fn indent_with<I: Display>(&mut self, indent: I) -> Indent<'_, Self, I> {
22 Indent::new(self, indent)
23 }
24
25 fn delimit<O: Display, E: Display>(&mut self, open: O, close: E) -> Delimit<'_, Self, E> {
27 Delimit::new(self, open, close)
28 }
29
30 fn delimit_indented<O: Display, E: Display>(
32 &mut self,
33 open: O,
34 close: E,
35 ) -> DelimitIndent<'_, Self, E> {
36 DelimitIndent::new(self, open, close)
37 }
38
39 #[inline]
41 fn list<Iter: IntoIterator<Item: Display>, Sep: Display>(
42 &mut self,
43 items: Iter,
44 sep: Sep,
45 ) -> std::fmt::Result {
46 self.list_wrap("", items, sep, "")
47 }
48
49 fn list_wrap<Iter: IntoIterator<Item: Display>, Sep: Display, O: Display, E: Display>(
53 &mut self,
54 open: O,
55 items: Iter,
56 sep: Sep,
57 close: E,
58 ) -> std::fmt::Result {
59 let mut iter = items.into_iter();
60 let Some(item) = iter.next() else {
61 return Ok(());
62 };
63
64 write!(self, "{open}{item}")?;
65 for item in iter {
66 write!(self, "{sep}{item}")?;
67 }
68 write!(self, "{close}")
69 }
70}
71
72pub struct Indent<'f, F: Write + ?Sized, I: Display = &'static str> {
74 indent: I,
75 needs_indent: bool,
76 f: &'f mut F,
77}
78
79impl<'f, F: Write + ?Sized, I: Display> Indent<'f, F, I> {
80 pub const fn new(f: &'f mut F, indent: I) -> Self {
81 Indent { f, needs_indent: false, indent }
82 }
83
84 pub const fn inner(&mut self) -> &mut F {
86 self.f
87 }
88}
89
90impl<F: Write + ?Sized, I: Display> Write for Indent<'_, F, I> {
91 fn write_str(&mut self, s: &str) -> std::fmt::Result {
92 for s in s.split_inclusive('\n') {
93 if self.needs_indent {
94 write!(self.f, "{}", self.indent)?;
95 }
96 self.needs_indent = s.ends_with('\n');
97 self.f.write_str(s)?;
98 }
99 Ok(())
100 }
101 fn write_char(&mut self, c: char) -> std::fmt::Result {
102 if self.needs_indent {
103 write!(self.f, "{}", self.indent)?;
104 }
105 self.needs_indent = c == '\n';
106 self.f.write_char(c)
107 }
108}
109
110pub struct Delimit<'f, F: Write + ?Sized, E: Display = &'static str> {
112 pub f: &'f mut F,
114 close: E,
115}
116
117impl<F: Write + ?Sized, E: Display> Delimit<'_, F, E> {
118 pub const fn inner(&mut self) -> &mut F {
120 self.f
121 }
122}
123
124impl<'f, F: Write + ?Sized, E: Display> Delimit<'f, F, E> {
125 pub fn new<O: Display>(f: &'f mut F, open: O, close: E) -> Self {
126 let _ = write!(f, "{open}");
127 Self { f, close }
128 }
129}
130
131impl<F: Write + ?Sized, E: Display> Drop for Delimit<'_, F, E> {
132 fn drop(&mut self) {
133 let Self { f, close, .. } = self;
134 let _ = write!(f, "{close}");
135 }
136}
137
138impl<F: Write + ?Sized, E: Display> Write for Delimit<'_, F, E> {
139 fn write_str(&mut self, s: &str) -> std::fmt::Result {
140 self.f.write_str(s)
141 }
142}
143
144pub struct DelimitIndent<'f, F: Write + ?Sized, E: Display = &'static str> {
146 f: Indent<'f, F>,
147 close: E,
148}
149
150impl<F: Write + ?Sized, E: Display> DelimitIndent<'_, F, E> {
151 pub const fn inner(&mut self) -> &mut F {
153 self.f.inner()
154 }
155}
156
157impl<'f, F: Write + ?Sized, E: Display> DelimitIndent<'f, F, E> {
158 pub fn new<O: Display>(f: &'f mut F, open: O, close: E) -> Self {
159 let mut f = f.indent();
160 let _ = write!(f, "{open}");
161 Self { f, close }
162 }
163}
164
165impl<F: Write + ?Sized, E: Display> Drop for DelimitIndent<'_, F, E> {
166 fn drop(&mut self) {
167 let Self { f: Indent { f, .. }, close, .. } = self;
168 let _ = write!(f, "{close}");
169 }
170}
171
172impl<F: Write + ?Sized, E: Display> Write for DelimitIndent<'_, F, E> {
173 fn write_str(&mut self, s: &str) -> std::fmt::Result {
174 self.f.write_str(s)
175 }
176}