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}