cxx_gen/gen/
out.rs

1use crate::gen::block::Block;
2use crate::gen::builtin::Builtins;
3use crate::gen::include::Includes;
4use crate::gen::pragma::Pragma;
5use crate::gen::Opt;
6use crate::syntax::namespace::Namespace;
7use crate::syntax::Types;
8use std::cell::RefCell;
9use std::fmt::{self, Arguments, Write};
10
11pub(crate) struct OutFile<'a> {
12    pub header: bool,
13    pub opt: &'a Opt,
14    pub types: &'a Types<'a>,
15    pub include: Includes<'a>,
16    pub pragma: Pragma<'a>,
17    pub builtin: Builtins<'a>,
18    content: RefCell<Content<'a>>,
19}
20
21#[derive(Default)]
22pub(crate) struct Content<'a> {
23    bytes: String,
24    namespace: &'a Namespace,
25    blocks: Vec<BlockBoundary<'a>>,
26    section_pending: bool,
27    blocks_pending: usize,
28}
29
30#[derive(Copy, Clone, PartialEq, Debug)]
31enum BlockBoundary<'a> {
32    Begin(Block<'a>),
33    End(Block<'a>),
34}
35
36impl<'a> OutFile<'a> {
37    pub(crate) fn new(header: bool, opt: &'a Opt, types: &'a Types) -> Self {
38        OutFile {
39            header,
40            opt,
41            types,
42            include: Includes::new(),
43            pragma: Pragma::new(),
44            builtin: Builtins::new(),
45            content: RefCell::new(Content::new()),
46        }
47    }
48
49    // Write a blank line if the preceding section had any contents.
50    pub(crate) fn next_section(&mut self) {
51        self.content.get_mut().next_section();
52    }
53
54    pub(crate) fn begin_block(&mut self, block: Block<'a>) {
55        self.content.get_mut().begin_block(block);
56    }
57
58    pub(crate) fn end_block(&mut self, block: Block<'a>) {
59        self.content.get_mut().end_block(block);
60    }
61
62    pub(crate) fn set_namespace(&mut self, namespace: &'a Namespace) {
63        self.content.get_mut().set_namespace(namespace);
64    }
65
66    pub(crate) fn write_fmt(&self, args: Arguments) {
67        let content = &mut *self.content.borrow_mut();
68        Write::write_fmt(content, args).unwrap();
69    }
70
71    pub(crate) fn content(&mut self) -> Vec<u8> {
72        self.flush();
73
74        let include = &self.include.content.bytes;
75        let pragma_begin = &self.pragma.begin.bytes;
76        let builtin = &self.builtin.content.bytes;
77        let content = &self.content.get_mut().bytes;
78        let pragma_end = &self.pragma.end.bytes;
79
80        let mut out = String::new();
81        out.push_str(include);
82        if !out.is_empty() && !pragma_begin.is_empty() {
83            out.push('\n');
84        }
85        out.push_str(pragma_begin);
86        if !out.is_empty() && !builtin.is_empty() {
87            out.push('\n');
88        }
89        out.push_str(builtin);
90        if !out.is_empty() && !content.is_empty() {
91            out.push('\n');
92        }
93        out.push_str(content);
94        if !out.is_empty() && !pragma_end.is_empty() {
95            out.push('\n');
96        }
97        out.push_str(pragma_end);
98        if out.is_empty() {
99            out.push_str("// empty\n");
100        }
101        out.into_bytes()
102    }
103
104    fn flush(&mut self) {
105        self.include.content.flush();
106        self.pragma.begin.flush();
107        self.builtin.content.flush();
108        self.content.get_mut().flush();
109        self.pragma.end.flush();
110    }
111}
112
113impl<'a> Write for Content<'a> {
114    fn write_str(&mut self, s: &str) -> fmt::Result {
115        self.write(s);
116        Ok(())
117    }
118}
119
120impl<'a> PartialEq for Content<'a> {
121    fn eq(&self, _other: &Self) -> bool {
122        true
123    }
124}
125
126impl<'a> Content<'a> {
127    pub(crate) fn new() -> Self {
128        Content::default()
129    }
130
131    pub(crate) fn next_section(&mut self) {
132        self.section_pending = true;
133    }
134
135    pub(crate) fn begin_block(&mut self, block: Block<'a>) {
136        self.push_block_boundary(BlockBoundary::Begin(block));
137    }
138
139    pub(crate) fn end_block(&mut self, block: Block<'a>) {
140        self.push_block_boundary(BlockBoundary::End(block));
141    }
142
143    pub(crate) fn set_namespace(&mut self, namespace: &'a Namespace) {
144        for name in self.namespace.iter().rev() {
145            self.end_block(Block::UserDefinedNamespace(name));
146        }
147        for name in namespace {
148            self.begin_block(Block::UserDefinedNamespace(name));
149        }
150        self.namespace = namespace;
151    }
152
153    pub(crate) fn write_fmt(&mut self, args: Arguments) {
154        Write::write_fmt(self, args).unwrap();
155    }
156
157    fn write(&mut self, b: &str) {
158        if !b.is_empty() {
159            if self.blocks_pending > 0 {
160                self.flush_blocks();
161            }
162            if self.section_pending && !self.bytes.is_empty() {
163                self.bytes.push('\n');
164            }
165            self.bytes.push_str(b);
166            self.section_pending = false;
167            self.blocks_pending = 0;
168        }
169    }
170
171    fn push_block_boundary(&mut self, boundary: BlockBoundary<'a>) {
172        if self.blocks_pending > 0 && boundary == self.blocks.last().unwrap().rev() {
173            self.blocks.pop();
174            self.blocks_pending -= 1;
175        } else {
176            self.blocks.push(boundary);
177            self.blocks_pending += 1;
178        }
179    }
180
181    fn flush(&mut self) {
182        self.set_namespace(Default::default());
183        if self.blocks_pending > 0 {
184            self.flush_blocks();
185        }
186    }
187
188    fn flush_blocks(&mut self) {
189        self.section_pending = !self.bytes.is_empty();
190        let mut read = self.blocks.len() - self.blocks_pending;
191        let mut write = read;
192
193        while read < self.blocks.len() {
194            match self.blocks[read] {
195                BlockBoundary::Begin(begin_block) => {
196                    if self.section_pending {
197                        self.bytes.push('\n');
198                        self.section_pending = false;
199                    }
200                    Block::write_begin(begin_block, &mut self.bytes);
201                    self.blocks[write] = BlockBoundary::Begin(begin_block);
202                    write += 1;
203                }
204                BlockBoundary::End(end_block) => {
205                    write = write.checked_sub(1).unwrap();
206                    let begin_block = self.blocks[write];
207                    assert_eq!(begin_block, BlockBoundary::Begin(end_block));
208                    Block::write_end(end_block, &mut self.bytes);
209                    self.section_pending = true;
210                }
211            }
212            read += 1;
213        }
214
215        self.blocks.truncate(write);
216    }
217}
218
219impl<'a> BlockBoundary<'a> {
220    fn rev(self) -> BlockBoundary<'a> {
221        match self {
222            BlockBoundary::Begin(block) => BlockBoundary::End(block),
223            BlockBoundary::End(block) => BlockBoundary::Begin(block),
224        }
225    }
226}