1mod common;
2mod function;
3mod r#struct;
4mod tuple;
5mod union;
6
7use std::io::Write;
8
9use common::*;
10
11use super::*;
12use crate::astype::*;
13use crate::error::*;
14use crate::pretty_writer::PrettyWriter;
15
16pub struct DocGenerator {
17 module_name: Option<String>,
18}
19
20impl DocGenerator {
21 pub fn new(module_name: Option<String>) -> Self {
22 DocGenerator { module_name }
23 }
24}
25
26impl<T: Write> Generator<T> for DocGenerator {
27 fn generate(
28 &self,
29 writer: &mut T,
30 module_witx: witx::Module,
31 options: &Options,
32 ) -> Result<(), Error> {
33 let mut w = PrettyWriter::new(writer, "* ");
34 let module_name = match &self.module_name {
35 None => module_witx.name().as_str().to_string(),
36 Some(module_name) => module_name.to_string(),
37 };
38 let module_id = module_witx.module_id();
39 let skip_imports = options.skip_imports;
40
41 if !options.skip_header {
42 Self::header(&mut w)?;
43 }
44
45 let module_title_doc = format!("# Module: {}", module_name);
46 w.eob()?;
47 w.write_line(module_title_doc)?;
48 w.eob()?;
49
50 w.write_line("## Table of contents")?.eob()?;
51 w.write_line("### Types list:")?.eob()?;
52 w.write("[**[All](#types)**]")?;
53 for type_ in module_witx.typenames() {
54 if skip_imports && &type_.module != module_id {
55 continue;
56 }
57 let type_name = type_.name.as_str();
58 w.write(format!(" - [{}]", type_name.as_type()))?;
59 }
60 w.eol()?.eob()?;
61 w.write_line("### Functions list:")?.eob()?;
62 w.write("[**[All](#functions)**]")?;
63 for func in module_witx.funcs() {
64 let func_name = func.name.as_str();
65 w.write(format!(" - [{}]", func_name.as_fn()))?;
66 }
67 w.eol()?.eob()?;
68
69 w.write_line("## Types")?.eob()?;
70
71 for type_ in module_witx.typenames() {
72 if skip_imports && &type_.module != module_id {
73 continue;
74 }
75 let constants_for_type: Vec<_> = module_witx
76 .constants()
77 .filter_map(|x| {
78 if x.ty == type_.name {
79 Some(ASConstant {
80 name: x.name.as_str().to_string(),
81 value: x.value,
82 })
83 } else {
84 None
85 }
86 })
87 .collect();
88 Self::define_type(&mut w, type_.as_ref(), &constants_for_type)?;
89 }
90
91 w.write_line("## Functions")?.eob()?;
92
93 for func in module_witx.funcs() {
94 Self::define_func(&mut w, &module_name, func.as_ref())?;
95 }
96
97 Ok(())
98 }
99}
100
101impl DocGenerator {
102 fn write_docs<T: Write>(w: &mut PrettyWriter<T>, docs: &str) -> Result<(), Error> {
103 if docs.is_empty() {
104 return Ok(());
105 }
106 w.eob()?;
107 for docs_line in docs.lines() {
108 let docs_line = docs_line.trim().replace('<', "\\<").replace('>', "\\>");
109 w.write_line(format!("> {}", docs_line))?;
110 }
111 w.eob()?;
112 Ok(())
113 }
114
115 fn header<T: Write>(_w: &mut PrettyWriter<T>) -> Result<(), Error> {
116 Ok(())
117 }
118
119 fn define_as_alias<T: Write>(
120 w: &mut PrettyWriter<T>,
121 name: &str,
122 other_type: &ASType,
123 ) -> Result<(), Error> {
124 w.write_lines(format!(
125 "### {}\n\nAlias for {}.",
126 name.as_type(),
127 other_type.as_lang()
128 ))?
129 .eob()?;
130 Ok(())
131 }
132
133 fn define_as_atom<T: Write>(
134 w: &mut PrettyWriter<T>,
135 name: &str,
136 type_: &ASType,
137 ) -> Result<(), Error> {
138 w.write_line(format!(
139 "### {}\nAlias for {}.",
140 name.as_type(),
141 type_.as_lang()
142 ))?
143 .eob()?;
144 Ok(())
145 }
146
147 fn define_as_enum<T: Write>(
148 w: &mut PrettyWriter<T>,
149 name: &str,
150 enum_: &ASEnum,
151 ) -> Result<(), Error> {
152 let repr = enum_.repr.as_ref();
153 w.write_lines(format!(
154 "### {}\n\nEnumeration with tag type: {}, and the following members:",
155 name.as_type(),
156 repr.as_lang()
157 ))?
158 .eob()?;
159 {
160 let mut w = w.new_block();
161 for choice in &enum_.choices {
162 w.write_line(format!("{}: {}", choice.name.as_const(), name.as_type()))?;
163 }
164 }
165 Ok(())
166 }
167
168 fn define_as_constants<T: Write>(
169 w: &mut PrettyWriter<T>,
170 name: &str,
171 constants: &ASConstants,
172 ) -> Result<(), Error> {
173 let repr = constants.repr.as_ref();
174 w.write_lines(format!(
175 "### {}\n\nSet of constants, of type {}",
176 name.as_type(),
177 repr.as_lang()
178 ))?
179 .eob()?;
180 Self::define_constants_for_type(w, name, &constants.constants)?;
181 Ok(())
182 }
183
184 fn define_as_type<T: Write>(
185 w: &mut PrettyWriter<T>,
186 name: &str,
187 type_: &ASType,
188 ) -> Result<(), Error> {
189 match type_ {
190 ASType::Alias(_)
191 | ASType::Bool
192 | ASType::Char8
193 | ASType::Char32
194 | ASType::F32
195 | ASType::F64
196 | ASType::U8
197 | ASType::U16
198 | ASType::U32
199 | ASType::U64
200 | ASType::S8
201 | ASType::S16
202 | ASType::S32
203 | ASType::S64
204 | ASType::USize
205 | ASType::Handle(_)
206 | ASType::Slice(_)
207 | ASType::String(_)
208 | ASType::ReadBuffer(_)
209 | ASType::WriteBuffer(_) => Self::define_as_atom(w, name, type_)?,
210 ASType::Enum(enum_) => Self::define_as_enum(w, name, enum_)?,
211 ASType::Union(union_) => Self::define_as_union(w, name, union_)?,
212 ASType::Constants(constants) => Self::define_as_constants(w, name, constants)?,
213 ASType::Tuple(members) => Self::define_as_tuple(w, name, members)?,
214 ASType::Struct(members) => Self::define_as_struct(w, name, members)?,
215 _ => {
216 dbg!(type_);
217 unimplemented!();
218 }
219 }
220 Ok(())
221 }
222
223 fn define_constants_for_type<T: Write>(
224 w: &mut PrettyWriter<T>,
225 type_name: &str,
226 constants: &[ASConstant],
227 ) -> Result<(), Error> {
228 if constants.is_empty() {
229 return Ok(());
230 }
231 w.write_line(format!("Predefined constants for {}:", type_name.as_type()))?
232 .eob()?;
233 {
234 let mut w = w.new_block();
235 let mut hex = false;
236 let mut single_bits: usize = 0;
237 for constant in constants {
238 if constant.value > 0xffff {
239 hex = true;
240 }
241 if constant.value.count_ones() == 1 {
242 single_bits += 1;
243 }
244 }
245 if constants.len() > 2 && single_bits == constants.len() {
246 hex = true;
247 }
248 for constant in constants {
249 let value_s = if hex {
250 format!("0x{:x}", constant.value)
251 } else {
252 format!("{}", constant.value)
253 };
254 w.write_line(format!("{} = `{}`", constant.name.as_const(), value_s))?;
255 }
256 }
257 Ok(())
258 }
259
260 fn define_type<T: Write>(
261 w: &mut PrettyWriter<T>,
262 type_witx: &witx::NamedType,
263 constants: &[ASConstant],
264 ) -> Result<(), Error> {
265 let type_name = type_witx.name.as_str();
266 let tref = &type_witx.tref;
267 match tref {
268 witx::TypeRef::Name(other_type) => {
269 Self::define_as_alias(w, type_name, &ASType::from(&other_type.tref))?
270 }
271 witx::TypeRef::Value(type_witx) => {
272 let t = ASType::from(type_witx.as_ref());
273 Self::define_as_type(w, type_name, &t)?
274 }
275 }
276 Self::define_constants_for_type(w, type_name, constants)?;
277
278 let docs = &type_witx.docs;
279 if !docs.is_empty() {
280 Self::write_docs(w, docs)?;
281 }
282
283 w.eob()?.write_line("---")?.eob()?;
284 Ok(())
285 }
286}