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(&mut self, indent: &'static str) -> Indent<'_, Self> {
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<Item: Display, Sep: Display>(&mut self, items: &[Item], sep: Sep) -> std::fmt::Result {
42 self.list_wrap("", items, sep, "")
43 }
44
45 fn list_end<Item: Display, Sep: Display, End: Display>(
46 &mut self,
47 items: &[Item],
48 sep: Sep,
49 end: End,
50 ) -> std::fmt::Result {
51 self.list_wrap("", items, sep, end)
52 }
53
54 fn list_wrap<Item: Display, Sep: Display, O: Display, E: Display>(
58 &mut self,
59 open: O,
60 mut items: &[Item],
61 sep: Sep,
62 close: E,
63 ) -> std::fmt::Result {
64 if items.is_empty() {
65 return Ok(());
66 }
67 write!(self, "{open}")?;
68 while let [pat, rest @ ..] = items {
69 write!(self, "{pat}")?;
70 if !rest.is_empty() {
71 write!(self, "{sep}")?;
72 }
73 items = rest;
74 }
75 write!(self, "{close}")
76 }
77}
78
79pub struct Indent<'f, F: Write + ?Sized> {
81 indent: &'static str,
82 needs_indent: bool,
83 f: &'f mut F,
84}
85
86impl<'f, F: Write + ?Sized> Indent<'f, F> {
87 pub const fn new(f: &'f mut F, indent: &'static str) -> Self {
88 Indent { f, needs_indent: false, indent }
89 }
90
91 pub const fn inner(&mut self) -> &mut F {
93 self.f
94 }
95}
96
97impl<F: Write + ?Sized> Write for Indent<'_, F> {
98 fn write_str(&mut self, s: &str) -> std::fmt::Result {
99 for s in s.split_inclusive('\n') {
100 if self.needs_indent {
101 self.f.write_str(self.indent)?;
102 }
103 self.f.write_str(s)?;
104 self.needs_indent = s.ends_with('\n');
105 }
106 Ok(())
107 }
108 fn write_char(&mut self, c: char) -> std::fmt::Result {
109 if self.needs_indent {
110 self.f.write_str(self.indent)?;
111 }
112 self.needs_indent = c == '\n';
113 self.f.write_char(c)
114 }
115}
116
117pub struct Delimit<'f, F: Write + ?Sized, E: Display = &'static str> {
119 pub f: &'f mut F,
121 close: E,
122}
123
124impl<F: Write + ?Sized, E: Display> Delimit<'_, F, E> {
125 pub const fn inner(&mut self) -> &mut F {
127 self.f
128 }
129}
130
131impl<'f, F: Write + ?Sized, E: Display> Delimit<'f, F, E> {
132 pub fn new<O: Display>(f: &'f mut F, open: O, close: E) -> Self {
133 let _ = write!(f, "{open}");
134 Self { f, close }
135 }
136}
137
138impl<F: Write + ?Sized, E: Display> Drop for Delimit<'_, F, E> {
139 fn drop(&mut self) {
140 let Self { f, close, .. } = self;
141 let _ = write!(f, "{close}");
142 }
143}
144
145impl<F: Write + ?Sized, E: Display> Write for Delimit<'_, F, E> {
146 fn write_str(&mut self, s: &str) -> std::fmt::Result {
147 self.f.write_str(s)
148 }
149}
150
151pub struct DelimitIndent<'f, F: Write + ?Sized, E: Display = &'static str> {
153 f: Indent<'f, F>,
154 close: E,
155}
156
157impl<F: Write + ?Sized, E: Display> DelimitIndent<'_, F, E> {
158 pub const fn inner(&mut self) -> &mut F {
160 self.f.inner()
161 }
162}
163
164impl<'f, F: Write + ?Sized, E: Display> DelimitIndent<'f, F, E> {
165 pub fn new<O: Display>(f: &'f mut F, open: O, close: E) -> Self {
166 let mut f = f.indent();
167 let _ = write!(f, "{open}");
168 Self { f, close }
169 }
170}
171
172impl<F: Write + ?Sized, E: Display> Drop for DelimitIndent<'_, F, E> {
173 fn drop(&mut self) {
174 let Self { f: Indent { f, .. }, close, .. } = self;
175 let _ = write!(f, "{close}");
176 }
177}
178
179impl<F: Write + ?Sized, E: Display> Write for DelimitIndent<'_, F, E> {
180 fn write_str(&mut self, s: &str) -> std::fmt::Result {
181 self.f.write_str(s)
182 }
183}