Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wit-bindgen/src/source.rs
1693 views
1
use std::fmt::{self, Write};
2
use std::ops::Deref;
3
4
/// Helper structure to maintain indentation automatically when printing.
5
#[derive(Default)]
6
pub struct Source {
7
s: String,
8
indent: usize,
9
}
10
11
impl Source {
12
pub fn push_str(&mut self, src: &str) {
13
let lines = src.lines().collect::<Vec<_>>();
14
for (i, line) in lines.iter().enumerate() {
15
let trimmed = line.trim();
16
if trimmed.starts_with('}') && self.s.ends_with(" ") {
17
self.s.pop();
18
self.s.pop();
19
}
20
self.s.push_str(if lines.len() == 1 {
21
line
22
} else {
23
line.trim_start()
24
});
25
if trimmed.ends_with('{') {
26
self.indent += 1;
27
}
28
if trimmed.starts_with('}') {
29
// Note that a `saturating_sub` is used here to prevent a panic
30
// here in the case of invalid code being generated in debug
31
// mode. It's typically easier to debug those issues through
32
// looking at the source code rather than getting a panic.
33
self.indent = self.indent.saturating_sub(1);
34
}
35
if i != lines.len() - 1 || src.ends_with('\n') {
36
self.newline();
37
}
38
}
39
}
40
41
pub fn indent(&mut self, amt: usize) {
42
self.indent += amt;
43
}
44
45
pub fn deindent(&mut self, amt: usize) {
46
self.indent -= amt;
47
}
48
49
fn newline(&mut self) {
50
self.s.push('\n');
51
for _ in 0..self.indent {
52
self.s.push_str(" ");
53
}
54
}
55
56
pub fn as_mut_string(&mut self) -> &mut String {
57
&mut self.s
58
}
59
}
60
61
impl Write for Source {
62
fn write_str(&mut self, s: &str) -> fmt::Result {
63
self.push_str(s);
64
Ok(())
65
}
66
}
67
68
impl Deref for Source {
69
type Target = str;
70
fn deref(&self) -> &str {
71
&self.s
72
}
73
}
74
75
impl From<Source> for String {
76
fn from(s: Source) -> String {
77
s.s
78
}
79
}
80
81
#[cfg(test)]
82
mod tests {
83
use super::Source;
84
85
#[test]
86
fn simple_append() {
87
let mut s = Source::default();
88
s.push_str("x");
89
assert_eq!(s.s, "x");
90
s.push_str("y");
91
assert_eq!(s.s, "xy");
92
s.push_str("z ");
93
assert_eq!(s.s, "xyz ");
94
s.push_str(" a ");
95
assert_eq!(s.s, "xyz a ");
96
s.push_str("\na");
97
assert_eq!(s.s, "xyz a \na");
98
}
99
100
#[test]
101
fn newline_remap() {
102
let mut s = Source::default();
103
s.push_str("function() {\n");
104
s.push_str("y\n");
105
s.push_str("}\n");
106
assert_eq!(s.s, "function() {\n y\n}\n");
107
}
108
109
#[test]
110
fn if_else() {
111
let mut s = Source::default();
112
s.push_str("if() {\n");
113
s.push_str("y\n");
114
s.push_str("} else if () {\n");
115
s.push_str("z\n");
116
s.push_str("}\n");
117
assert_eq!(s.s, "if() {\n y\n} else if () {\n z\n}\n");
118
}
119
120
#[test]
121
fn trim_ws() {
122
let mut s = Source::default();
123
s.push_str(
124
"function() {
125
x
126
}",
127
);
128
assert_eq!(s.s, "function() {\n x\n}");
129
}
130
}
131
132