witx_codegen/doc/
mod.rs

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}