witx_codegen/overview/
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 OverviewGenerator {
17    module_name: Option<String>,
18}
19
20impl OverviewGenerator {
21    pub fn new(module_name: Option<String>) -> Self {
22        OverviewGenerator { module_name }
23    }
24}
25
26impl<T: Write> Generator<T> for OverviewGenerator {
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!(
46            "---------------------- Module: [{}] ----------------------",
47            module_name
48        );
49        w.eob()?;
50        w.write_line(module_title_doc)?;
51        w.eob()?;
52
53        for type_ in module_witx.typenames() {
54            if skip_imports && &type_.module != module_id {
55                continue;
56            }
57            let constants_for_type: Vec<_> = module_witx
58                .constants()
59                .filter_map(|x| {
60                    if x.ty == type_.name {
61                        Some(ASConstant {
62                            name: x.name.as_str().to_string(),
63                            value: x.value,
64                        })
65                    } else {
66                        None
67                    }
68                })
69                .collect();
70            Self::define_type(&mut w, type_.as_ref(), &constants_for_type)?;
71        }
72
73        for func in module_witx.funcs() {
74            Self::define_func(&mut w, &module_name, func.as_ref())?;
75        }
76
77        Ok(())
78    }
79}
80
81impl OverviewGenerator {
82    fn header<T: Write>(w: &mut PrettyWriter<T>) -> Result<(), Error> {
83        w.write_line("* API overview *")?;
84        w.eob()?;
85        Ok(())
86    }
87
88    fn define_as_alias<T: Write>(
89        w: &mut PrettyWriter<T>,
90        name: &str,
91        other_type: &ASType,
92    ) -> Result<(), Error> {
93        w.write_line(format!(
94            "alias {} = {}",
95            name.as_type(),
96            other_type.as_lang()
97        ))?;
98        Ok(())
99    }
100
101    fn define_as_atom<T: Write>(
102        w: &mut PrettyWriter<T>,
103        name: &str,
104        type_: &ASType,
105    ) -> Result<(), Error> {
106        w.write_line(format!("alias {} = {}", name.as_type(), type_.as_lang()))?;
107        Ok(())
108    }
109
110    fn define_as_enum<T: Write>(
111        w: &mut PrettyWriter<T>,
112        name: &str,
113        enum_: &ASEnum,
114    ) -> Result<(), Error> {
115        let repr = enum_.repr.as_ref();
116        w.write_line(format!(
117            "enum {}: (tag: {})",
118            name.as_type(),
119            repr.as_lang()
120        ))?;
121        {
122            let mut w = w.new_block();
123            for choice in &enum_.choices {
124                w.write_line(format!("- {}: {}", choice.name.as_const(), choice.value))?;
125            }
126        }
127        Ok(())
128    }
129
130    fn define_as_constants<T: Write>(
131        w: &mut PrettyWriter<T>,
132        name: &str,
133        constants: &ASConstants,
134    ) -> Result<(), Error> {
135        let repr = constants.repr.as_ref();
136        w.write_line(format!(
137            "constants {}: (type: {})",
138            name.as_type(),
139            repr.as_lang()
140        ))?;
141        Self::define_constants_for_type(w, name, &constants.constants)?;
142        Ok(())
143    }
144
145    fn define_as_type<T: Write>(
146        w: &mut PrettyWriter<T>,
147        name: &str,
148        type_: &ASType,
149    ) -> Result<(), Error> {
150        match type_ {
151            ASType::Alias(_)
152            | ASType::Bool
153            | ASType::Char8
154            | ASType::Char32
155            | ASType::F32
156            | ASType::F64
157            | ASType::U8
158            | ASType::U16
159            | ASType::U32
160            | ASType::U64
161            | ASType::S8
162            | ASType::S16
163            | ASType::S32
164            | ASType::S64
165            | ASType::USize
166            | ASType::Handle(_)
167            | ASType::Slice(_)
168            | ASType::String(_)
169            | ASType::ReadBuffer(_)
170            | ASType::WriteBuffer(_) => Self::define_as_atom(w, name, type_)?,
171            ASType::Enum(enum_) => Self::define_as_enum(w, name, enum_)?,
172            ASType::Union(union_) => Self::define_as_union(w, name, union_)?,
173            ASType::Constants(constants) => Self::define_as_constants(w, name, constants)?,
174            ASType::Tuple(members) => Self::define_as_tuple(w, name, members)?,
175            ASType::Struct(members) => Self::define_as_struct(w, name, members)?,
176            _ => {
177                dbg!(type_);
178                unimplemented!();
179            }
180        }
181        Ok(())
182    }
183
184    fn define_constants_for_type<T: Write>(
185        w: &mut PrettyWriter<T>,
186        type_name: &str,
187        constants: &[ASConstant],
188    ) -> Result<(), Error> {
189        if constants.is_empty() {
190            return Ok(());
191        }
192        w.write_line(format!("predefined constants for {}:", type_name.as_type()))?;
193        {
194            let mut w = w.new_block();
195            let mut hex = false;
196            let mut single_bits: usize = 0;
197            for constant in constants {
198                if constant.value > 0xffff {
199                    hex = true;
200                }
201                if constant.value.count_ones() == 1 {
202                    single_bits += 1;
203                }
204            }
205            if constants.len() > 2 && single_bits == constants.len() {
206                hex = true;
207            }
208            for constant in constants {
209                let value_s = if hex {
210                    format!("0x{:x}", constant.value)
211                } else {
212                    format!("{}", constant.value)
213                };
214                w.write_line(format!("- {} = {}", constant.name.as_const(), value_s))?;
215            }
216        }
217        Ok(())
218    }
219
220    fn define_type<T: Write>(
221        w: &mut PrettyWriter<T>,
222        type_witx: &witx::NamedType,
223        constants: &[ASConstant],
224    ) -> Result<(), Error> {
225        let type_name = type_witx.name.as_str();
226        let tref = &type_witx.tref;
227        match tref {
228            witx::TypeRef::Name(other_type) => {
229                Self::define_as_alias(w, type_name, &ASType::from(&other_type.tref))?
230            }
231            witx::TypeRef::Value(type_witx) => {
232                let t = ASType::from(type_witx.as_ref());
233                Self::define_as_type(w, type_name, &t)?
234            }
235        }
236        Self::define_constants_for_type(w, type_name, constants)?;
237        w.eob()?;
238        Ok(())
239    }
240}