cxx_gen/gen/
out.rs

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