mz_ore_build/codegen.rs
1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License in the LICENSE file at the
6// root of this repository, or online at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! Code generation utilities.
17
18/// A code generation buffer.
19///
20/// A `CodegenBuf` provides a string-based API for generating Rust code. Its
21/// value is in the various function it provides to automatically manage
22/// indentation.
23#[derive(Clone, Debug, Default)]
24pub struct CodegenBuf {
25 inner: String,
26 level: usize,
27}
28
29impl CodegenBuf {
30 /// Creates a new code generation buffer.
31 pub fn new() -> CodegenBuf {
32 CodegenBuf::default()
33 }
34
35 /// Consumes the buffer, returning its contents.
36 pub fn into_string(self) -> String {
37 self.inner
38 }
39
40 /// Writes a string into the buffer directly.
41 pub fn write<S>(&mut self, s: S)
42 where
43 S: AsRef<str>,
44 {
45 self.inner.push_str(s.as_ref());
46 }
47
48 /// Writes a line into the buffer at the current indentation level.
49 ///
50 /// Specifically, the method writes (4 * indentation level) spaces into the
51 /// buffer, followed by `s`, followed by a newline character.
52 pub fn writeln<S>(&mut self, s: S)
53 where
54 S: AsRef<str>,
55 {
56 self.start_line();
57 self.write(s);
58 self.end_line();
59 }
60
61 /// Starts a new line.
62 ///
63 /// Specifically, the method writes (4 * indentation level) spaces into
64 /// the buffer.
65 pub fn start_line(&mut self) {
66 for _ in 0..self.level {
67 self.write(" ");
68 }
69 }
70
71 /// Ends the current line.
72 ///
73 /// Specifically, the method writes a newline character into the buffer.
74 pub fn end_line(&mut self) {
75 self.write("\n");
76 }
77
78 /// Writes a new indented block.
79 ///
80 /// Specifically, if `s` is empty, the method writes the line `{` into the
81 /// buffer; otherwise writes the line `s {` into the buffer at the current
82 /// indentation level. Then it increments the buffer's indentation level,
83 /// runs the provided function, then decrements the indentation level and writes
84 /// a closing `}`.
85 pub fn write_block<S, F>(&mut self, s: S, f: F)
86 where
87 S: AsRef<str>,
88 F: FnOnce(&mut Self),
89 {
90 self.start_line();
91 self.write(s.as_ref());
92 if !s.as_ref().is_empty() {
93 self.inner.push(' ');
94 }
95 self.write("{\n");
96 self.level += 1;
97 f(self);
98 self.level -= 1;
99 self.writeln("}");
100 }
101
102 /// Closes the current indented block and starts a new one at the same
103 /// indentation level.
104 ///
105 /// Specifically, the method writes the line `} s {` into the buffer at one
106 /// less than the buffer's indentation level.
107 ///
108 /// # Panics
109 ///
110 /// Panics if the current indentation level is zero.
111 pub fn restart_block<S>(&mut self, s: S)
112 where
113 S: AsRef<str>,
114 {
115 self.level -= 1;
116 self.start_line();
117 self.write("} ");
118 self.write(s.as_ref());
119 self.write(" {\n");
120 self.level += 1;
121 }
122}